selfuncs.c convert_to_scalar() says:

|* The several datatypes representing absolute times are all converted
|* to Timestamp, which is actually a double, and then we just use that
|* double value.  Note this will give correct results even for the "special"
|* values of Timestamp, since those are chosen to compare correctly;
|* see timestamp_cmp.

But:
https://www.postgresql.org/docs/10/release-10.html
|Remove support for floating-point timestamps and intervals (Tom Lane)
|This removes configure's --disable-integer-datetimes option. Floating-point 
timestamps have few advantages and have not been the default since PostgreSQL 
8.3.
|b6aa17e De-support floating-point timestamps.
|configure                                                    | 18 
++++++------------
|configure.in                                                 | 12 ++++++------
|doc/src/sgml/config.sgml                                     |  8 +++-----
|doc/src/sgml/datatype.sgml                                   | 55 
+++++++++++--------------------------------------------
|doc/src/sgml/installation.sgml                               | 22 
----------------------
|src/include/c.h                                              |  7 ++++---
|src/include/pg_config.h.in                                   |  4 ----
|src/include/pg_config.h.win32                                |  4 ----
|src/interfaces/ecpg/include/ecpg_config.h.in                 |  4 ----
|src/interfaces/ecpg/include/pgtypes_interval.h               |  2 --
|src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.c      |  6 ++----
|src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.stdout |  2 ++
|src/interfaces/ecpg/test/pgtypeslib/dt_test2.pgc             |  6 ++----
|src/tools/msvc/Solution.pm                                   |  9 ---------
|src/tools/msvc/config_default.pl                             |  1 -
|15 files changed, 36 insertions(+), 124 deletions(-)

It's true that convert_to_scalar sees doubles:
|static double
|convert_timevalue_to_scalar(Datum value, Oid typid, bool *failure)
|{
|        switch (typid)
|        {
|                case TIMESTAMPOID:
|                        return DatumGetTimestamp(value);

But:
$ git grep DatumGetTimestamp src/include/
src/include/utils/timestamp.h:#define DatumGetTimestamp(X)  ((Timestamp) 
DatumGetInt64(X))

So I propose it should say something like:

|* The several datatypes representing absolute times are all converted
|* to Timestamp, which is actually an int64, and then we just promote that
|* to double.  Note this will give correct results even for the "special"
|* values of Timestamp, since those are chosen to compare correctly;
|* see timestamp_cmp.

That seems to be only used for ineq_histogram_selectivity() interpolation of
histogram bins.  It looks to me that at least isn't working for "special
values", and needs to use something other than isnan().  I added debugging code
and tested the attached like:

DROP TABLE t; CREATE TABLE t(t) AS SELECT generate_series(now(), now()+'1 day', 
'5 minutes');
INSERT INTO t VALUES('-infinity');
ALTER TABLE t ALTER t SET STATISTICS 1;
ANALYZE t;
explain SELECT * FROM t WHERE t>='2010-12-29';
>From b0151e24819499607eb2894dd920d4d8ef74b57d Mon Sep 17 00:00:00 2001
From: Justin Pryzby <pryz...@telsasoft.com>
Date: Mon, 30 Dec 2019 01:37:42 -0600
Subject: [PATCH v1 1/2] Correctly handle infinite timestamps in
 ineq_histogram_selectivity

---
 src/backend/utils/adt/selfuncs.c | 30 ++++++++++++++++++++++--------
 1 file changed, 22 insertions(+), 8 deletions(-)

diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 3f77c7e..73e2359 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -4284,14 +4284,19 @@ convert_one_bytea_to_scalar(unsigned char *value, int valuelen,
 static double
 convert_timevalue_to_scalar(Datum value, Oid typid, bool *failure)
 {
+	double	ret;
+
 	switch (typid)
 	{
 		case TIMESTAMPOID:
-			return DatumGetTimestamp(value);
+			ret = DatumGetTimestamp(value);
+			break;
 		case TIMESTAMPTZOID:
-			return DatumGetTimestampTz(value);
+			ret = DatumGetTimestampTz(value);
+			break;
 		case DATEOID:
-			return date2timestamp_no_overflow(DatumGetDateADT(value));
+			ret = date2timestamp_no_overflow(DatumGetDateADT(value));
+			break;
 		case INTERVALOID:
 			{
 				Interval   *interval = DatumGetIntervalP(value);
@@ -4301,22 +4306,31 @@ convert_timevalue_to_scalar(Datum value, Oid typid, bool *failure)
 				 * average month length of 365.25/12.0 days.  Not too
 				 * accurate, but plenty good enough for our purposes.
 				 */
-				return interval->time + interval->day * (double) USECS_PER_DAY +
+				ret = interval->time + interval->day * (double) USECS_PER_DAY +
 					interval->month * ((DAYS_PER_YEAR / (double) MONTHS_PER_YEAR) * USECS_PER_DAY);
 			}
+			break;
 		case TIMEOID:
-			return DatumGetTimeADT(value);
+			ret = DatumGetTimeADT(value);
+			break;
 		case TIMETZOID:
 			{
 				TimeTzADT  *timetz = DatumGetTimeTzADTP(value);
 
 				/* use GMT-equivalent time */
-				return (double) (timetz->time + (timetz->zone * 1000000.0));
+				ret = (double) (timetz->time + (timetz->zone * 1000000.0));
 			}
+			break;
+		default:
+			*failure = true;
+			return 0;
 	}
 
-	*failure = true;
-	return 0;
+	if (ret==PG_INT64_MIN ||
+		ret==PG_INT64_MAX)
+		ret = nan(""); /* C99 */
+
+	return ret;
 }
 
 
-- 
2.7.4

>From 5df640e0401f073df59faa3f118c8d195976ee9e Mon Sep 17 00:00:00 2001
From: Justin Pryzby <pryz...@telsasoft.com>
Date: Mon, 30 Dec 2019 01:43:40 -0600
Subject: [PATCH v1 2/2] Repair comment regarding double timestamps

..which were removed in v10 by b6aa17e.
---
 src/backend/utils/adt/selfuncs.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 73e2359..15b9382 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -3763,8 +3763,8 @@ estimate_multivariate_ndistinct(PlannerInfo *root, RelOptInfo *rel,
  * to be treated separately.
  *
  * The several datatypes representing absolute times are all converted
- * to Timestamp, which is actually a double, and then we just use that
- * double value.  Note this will give correct results even for the "special"
+ * to Timestamp, which is actually an int64, which is promoted to
+ * double.  Note this will give correct results even for the "special"
  * values of Timestamp, since those are chosen to compare correctly;
  * see timestamp_cmp.
  *
-- 
2.7.4

Reply via email to