I went ahead and pushed 0001 and 0003 (the latter in two parts), since
they didn't seem particularly controversial to me.  Just to keep the
cfbot from whining, here's a rebased version of 0002.

                        regards, tom lane

diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index c1dc511a1a..d9f577bd8b 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -2719,9 +2719,14 @@ lseg_interpt_line(Point *result, LSEG *lseg, LINE *line)
  *-------------------------------------------------------------------*/
 
 /*
- * If *result is not NULL, it is set to the intersection point of a
- * perpendicular of the line through the point.  Returns the distance
- * of those two points.
+ * Determine the closest point on the given line to the given point.
+ * If result is not NULL, *result is set to the coordinates of that point.
+ * In any case, returns the distance from the point to the line.
+ * Returns NaN for any ill-defined value.
+ *
+ * NOTE: in some cases the distance is well defined (i.e., infinity)
+ * even though the specific closest point is not.  Hence, if you care
+ * about whether the point is well-defined, check its coordinates for NaNs.
  */
 static float8
 line_closept_point(Point *result, LINE *line, Point *point)
@@ -2729,17 +2734,30 @@ line_closept_point(Point *result, LINE *line, Point *point)
 	Point		closept;
 	LINE		tmp;
 
+	/*
+	 * If it is unclear whether the point is on the line or not, then the
+	 * results are ill-defined.  This eliminates cases where any of the given
+	 * coordinates are NaN, as well as cases where infinite coordinates give
+	 * rise to Inf - Inf, 0 * Inf, etc.
+	 */
+	if (unlikely(isnan(float8_pl(float8_pl(float8_mul(line->A, point->x),
+										   float8_mul(line->B, point->y)),
+								 line->C))))
+	{
+		if (result != NULL)
+			result->x = result->y = get_float8_nan();
+		return get_float8_nan();
+	}
+
 	/*
 	 * 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.
+	 * should always find it, but perhaps roundoff issues could prevent that.
 	 */
 	line_construct(&tmp, point, line_invsl(line));
 	if (!line_interpt_line(&closept, &tmp, line))
 	{
 		if (result != NULL)
-			*result = *point;
-
+			result->x = result->y = get_float8_nan();
 		return get_float8_nan();
 	}
 
@@ -2758,7 +2776,9 @@ close_pl(PG_FUNCTION_ARGS)
 
 	result = (Point *) palloc(sizeof(Point));
 
-	if (isnan(line_closept_point(result, line, pt)))
+	(void) line_closept_point(result, line, pt);
+
+	if (unlikely(isnan(result->x) || isnan(result->y)))
 		PG_RETURN_NULL();
 
 	PG_RETURN_POINT_P(result);
diff --git a/src/test/regress/expected/geometry.out b/src/test/regress/expected/geometry.out
index c4f853ae9f..6210075bc1 100644
--- a/src/test/regress/expected/geometry.out
+++ b/src/test/regress/expected/geometry.out
@@ -1070,9 +1070,9 @@ SELECT p.f1, l.s, p.f1 ## l.s FROM POINT_TBL p, LINE_TBL l;
  (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) | {1,-1,0}                              | 
+ (1e+300,Infinity) | {-0.4,-1,-6}                          | 
+ (1e+300,Infinity) | {-0.000184615384615,-1,15.3846153846} | 
  (1e+300,Infinity) | {3,NaN,5}                             | 
  (1e+300,Infinity) | {NaN,NaN,NaN}                         | 
  (1e+300,Infinity) | {0,-1,3}                              | (1e+300,3)

Reply via email to