summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane2001-05-03 19:00:37 +0000
committerTom Lane2001-05-03 19:00:37 +0000
commit2792374cff361a7a4ec0e750b5fa935d85afc9ac (patch)
tree98736405bf8af30af89bdf224802f868057b7d2a
parent77fe28f33e49d752be4e4a1bbc6c112f825e7882 (diff)
Ensure that btree sort ordering functions and boolean comparison operators
give consistent results for all datatypes. Types float4, float8, and numeric were broken for NaN values; abstime, timestamp, and interval were broken for INVALID values; timetz was just plain broken (some possible pairs of values were neither < nor = nor >). Also clean up text, bpchar, varchar, and bit/varbit to eliminate duplicate code and thereby reduce the probability of similar inconsistencies arising in the future.
-rw-r--r--src/backend/access/nbtree/nbtcompare.c138
-rw-r--r--src/backend/utils/adt/date.c46
-rw-r--r--src/backend/utils/adt/float.c149
-rw-r--r--src/backend/utils/adt/nabstime.c137
-rw-r--r--src/backend/utils/adt/numeric.c156
-rw-r--r--src/backend/utils/adt/timestamp.c212
-rw-r--r--src/backend/utils/adt/varbit.c76
-rw-r--r--src/backend/utils/adt/varchar.c15
-rw-r--r--src/backend/utils/adt/varlena.c132
-rw-r--r--src/include/utils/nabstime.h3
-rw-r--r--src/test/regress/expected/abstime-solaris-1947.out6
-rw-r--r--src/test/regress/expected/abstime.out6
-rw-r--r--src/test/regress/expected/timestamp.out15
13 files changed, 440 insertions, 651 deletions
diff --git a/src/backend/access/nbtree/nbtcompare.c b/src/backend/access/nbtree/nbtcompare.c
index fc85906d9b..b1affe2018 100644
--- a/src/backend/access/nbtree/nbtcompare.c
+++ b/src/backend/access/nbtree/nbtcompare.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtcompare.c,v 1.41 2001/03/22 03:59:14 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtcompare.c,v 1.42 2001/05/03 19:00:36 tgl Exp $
*
* NOTES
*
@@ -25,7 +25,20 @@
* NOTE: although any negative int32 is acceptable for reporting "<",
* and any positive int32 is acceptable for reporting ">", routines
* that work on 32-bit or wider datatypes can't just return "a - b".
- * That could overflow and give the wrong answer.
+ * That could overflow and give the wrong answer. Also, one should not
+ * return INT_MIN to report "<", since some callers will negate the result.
+ *
+ * NOTE: it is critical that the comparison function impose a total order
+ * on all non-NULL values of the data type, and that the datatype's
+ * boolean comparison operators (= < >= etc) yield results consistent
+ * with the comparison routine. Otherwise bad behavior may ensue.
+ * (For example, the comparison operators must NOT punt when faced with
+ * NAN or other funny values; you must devise some collation sequence for
+ * all such values.) If the datatype is not trivial, this is most
+ * reliably done by having the boolean operators invoke the same
+ * three-way comparison code that the btree function does. Therefore,
+ * this file contains only btree support for "trivial" datatypes ---
+ * all others are in the /utils/adt/ files that implement their datatypes.
*
* NOTE: these routines must not leak memory, since memory allocated
* during an index access won't be recovered till end of query. This
@@ -33,12 +46,11 @@
* they have to be careful to free any detoasted copy of an input datum.
*-------------------------------------------------------------------------
*/
-
#include "postgres.h"
-#include "utils/nabstime.h"
#include "utils/builtins.h"
+
Datum
btboolcmp(PG_FUNCTION_ARGS)
{
@@ -86,34 +98,6 @@ btint8cmp(PG_FUNCTION_ARGS)
}
Datum
-btfloat4cmp(PG_FUNCTION_ARGS)
-{
- float4 a = PG_GETARG_FLOAT4(0);
- float4 b = PG_GETARG_FLOAT4(1);
-
- if (a > b)
- PG_RETURN_INT32(1);
- else if (a == b)
- PG_RETURN_INT32(0);
- else
- PG_RETURN_INT32(-1);
-}
-
-Datum
-btfloat8cmp(PG_FUNCTION_ARGS)
-{
- float8 a = PG_GETARG_FLOAT8(0);
- float8 b = PG_GETARG_FLOAT8(1);
-
- if (a > b)
- PG_RETURN_INT32(1);
- else if (a == b)
- PG_RETURN_INT32(0);
- else
- PG_RETURN_INT32(-1);
-}
-
-Datum
btoidcmp(PG_FUNCTION_ARGS)
{
Oid a = PG_GETARG_OID(0);
@@ -148,20 +132,6 @@ btoidvectorcmp(PG_FUNCTION_ARGS)
}
Datum
-btabstimecmp(PG_FUNCTION_ARGS)
-{
- AbsoluteTime a = PG_GETARG_ABSOLUTETIME(0);
- AbsoluteTime b = PG_GETARG_ABSOLUTETIME(1);
-
- if (AbsoluteTimeIsBefore(a, b))
- PG_RETURN_INT32(-1);
- else if (AbsoluteTimeIsBefore(b, a))
- PG_RETURN_INT32(1);
- else
- PG_RETURN_INT32(0);
-}
-
-Datum
btcharcmp(PG_FUNCTION_ARGS)
{
char a = PG_GETARG_CHAR(0);
@@ -179,79 +149,3 @@ btnamecmp(PG_FUNCTION_ARGS)
PG_RETURN_INT32(strncmp(NameStr(*a), NameStr(*b), NAMEDATALEN));
}
-
-Datum
-bttextcmp(PG_FUNCTION_ARGS)
-{
- text *a = PG_GETARG_TEXT_P(0);
- text *b = PG_GETARG_TEXT_P(1);
- int res;
- unsigned char *ap,
- *bp;
-
-#ifdef USE_LOCALE
- int la = VARSIZE(a) - VARHDRSZ;
- int lb = VARSIZE(b) - VARHDRSZ;
-
- ap = (unsigned char *) palloc(la + 1);
- bp = (unsigned char *) palloc(lb + 1);
-
- memcpy(ap, VARDATA(a), la);
- *(ap + la) = '\0';
- memcpy(bp, VARDATA(b), lb);
- *(bp + lb) = '\0';
-
- res = strcoll(ap, bp);
-
- pfree(ap);
- pfree(bp);
-
-#else
- int len = VARSIZE(a);
-
- /* len is the length of the shorter of the two strings */
- if (len > VARSIZE(b))
- len = VARSIZE(b);
-
- len -= VARHDRSZ;
-
- ap = (unsigned char *) VARDATA(a);
- bp = (unsigned char *) VARDATA(b);
-
- /*
- * If the two strings differ in the first len bytes, or if they're the
- * same in the first len bytes and they're both len bytes long, we're
- * done.
- */
-
- res = 0;
- if (len > 0)
- {
- do
- {
- res = (int) *ap++ - (int) *bp++;
- len--;
- } while (res == 0 && len != 0);
- }
-
- if (res == 0 && VARSIZE(a) != VARSIZE(b))
- {
-
- /*
- * The two strings are the same in the first len bytes, and they
- * are of different lengths.
- */
- if (VARSIZE(a) < VARSIZE(b))
- res = -1;
- else
- res = 1;
- }
-
-#endif
-
- /* Avoid leaking memory when handed toasted input. */
- PG_FREE_IF_COPY(a, 0);
- PG_FREE_IF_COPY(b, 1);
-
- PG_RETURN_INT32(res);
-}
diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c
index 5e7d3c92f2..4504f5f043 100644
--- a/src/backend/utils/adt/date.c
+++ b/src/backend/utils/adt/date.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.56 2001/03/22 03:59:49 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.57 2001/05/03 19:00:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -899,13 +899,35 @@ timetz_out(PG_FUNCTION_ARGS)
}
+static int
+timetz_cmp_internal(TimeTzADT *time1, TimeTzADT *time2)
+{
+ double t1,
+ t2;
+
+ /* Primary sort is by true (GMT-equivalent) time */
+ t1 = time1->time + time1->zone;
+ t2 = time2->time + time2->zone;
+
+ if (t1 > t2)
+ return 1;
+ if (t1 < t2)
+ return -1;
+
+ /*
+ * If same GMT time, sort by timezone; we only want to say that two
+ * timetz's are equal if both the time and zone parts are equal.
+ */
+ return time1->zone - time2->zone;
+}
+
Datum
timetz_eq(PG_FUNCTION_ARGS)
{
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
- PG_RETURN_BOOL(((time1->time + time1->zone) == (time2->time + time2->zone)));
+ PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) == 0);
}
Datum
@@ -914,7 +936,7 @@ timetz_ne(PG_FUNCTION_ARGS)
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
- PG_RETURN_BOOL(((time1->time + time1->zone) != (time2->time + time2->zone)));
+ PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) != 0);
}
Datum
@@ -923,7 +945,7 @@ timetz_lt(PG_FUNCTION_ARGS)
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
- PG_RETURN_BOOL(((time1->time + time1->zone) < (time2->time + time2->zone)));
+ PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) < 0);
}
Datum
@@ -932,7 +954,7 @@ timetz_le(PG_FUNCTION_ARGS)
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
- PG_RETURN_BOOL(((time1->time + time1->zone) <= (time2->time + time2->zone)));
+ PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) <= 0);
}
Datum
@@ -941,7 +963,7 @@ timetz_gt(PG_FUNCTION_ARGS)
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
- PG_RETURN_BOOL(((time1->time + time1->zone) > (time2->time + time2->zone)));
+ PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) > 0);
}
Datum
@@ -950,7 +972,7 @@ timetz_ge(PG_FUNCTION_ARGS)
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
- PG_RETURN_BOOL(((time1->time + time1->zone) >= (time2->time + time2->zone)));
+ PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) >= 0);
}
Datum
@@ -959,15 +981,7 @@ timetz_cmp(PG_FUNCTION_ARGS)
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
- if (DatumGetBool(DirectFunctionCall2(timetz_lt,
- TimeTzADTPGetDatum(time1),
- TimeTzADTPGetDatum(time2))))
- PG_RETURN_INT32(-1);
- if (DatumGetBool(DirectFunctionCall2(timetz_gt,
- TimeTzADTPGetDatum(time1),
- TimeTzADTPGetDatum(time2))))
- PG_RETURN_INT32(1);
- PG_RETURN_INT32(0);
+ PG_RETURN_INT32(timetz_cmp_internal(time1, time2));
}
/*
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index 7a83ee6577..06405d0cee 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -8,11 +8,11 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/float.c,v 1.70 2001/03/22 03:59:50 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/float.c,v 1.71 2001/05/03 19:00:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
-/*
+/*----------
* OLD COMMENTS
* Basic float4 ops:
* float4in, float4out, float4abs, float4um
@@ -22,8 +22,8 @@
* float4pl, float4mi, float4mul, float4div
* float8pl, float8mi, float8mul, float8div
* Comparison operators:
- * float4eq, float4ne, float4lt, float4le, float4gt, float4ge
- * float8eq, float8ne, float8lt, float8le, float8gt, float8ge
+ * float4eq, float4ne, float4lt, float4le, float4gt, float4ge, float4cmp
+ * float8eq, float8ne, float8lt, float8le, float8gt, float8ge, float8cmp
* Conversion routines:
* ftod, dtof, i4tod, dtoi4, i2tod, dtoi2, itof, ftoi, i2tof, ftoi2
*
@@ -37,7 +37,8 @@
* float84eq, float84ne, float84lt, float84le, float84gt, float84ge
*
* (You can do the arithmetic and comparison stuff using conversion
- * routines, but then you pay the overhead of converting...)
+ * routines, but then you pay the overhead of invoking a separate
+ * conversion function...)
*
* XXX GLUESOME STUFF. FIX IT! -AY '94
*
@@ -45,14 +46,15 @@
* a bit of the existing code. Need to change the error checking
* for calls to pow(), exp() since on some machines (my Linux box
* included) these routines do not set errno. - tgl 97/05/10
+ *----------
*/
+#include "postgres.h"
+
#include <ctype.h>
#include <errno.h>
#include <float.h> /* faked on sunos4 */
#include <math.h>
-#include "postgres.h"
-
#include <limits.h>
/* for finite() on Solaris */
#ifdef HAVE_IEEEFP_H
@@ -197,7 +199,7 @@ float4in(PG_FUNCTION_ARGS)
val = strtod(num, &endptr);
if (*endptr != '\0')
{
- /* Should we accept "NaN" or "Infinity" for float4? */
+ /* Shouldn't we accept "NaN" or "Infinity" for float4? */
elog(ERROR, "Bad float4 input format '%s'", num);
}
else
@@ -225,6 +227,11 @@ float4out(PG_FUNCTION_ARGS)
float4 num = PG_GETARG_FLOAT4(0);
char *ascii = (char *) palloc(MAXFLOATWIDTH + 1);
+ if (isnan(num))
+ PG_RETURN_CSTRING(strcpy(ascii, "NaN"));
+ if (isinf(num))
+ PG_RETURN_CSTRING(strcpy(ascii, "Infinity"));
+
sprintf(ascii, "%.*g", FLT_DIG, num);
PG_RETURN_CSTRING(ascii);
}
@@ -536,13 +543,43 @@ float8div(PG_FUNCTION_ARGS)
/*
* float4{eq,ne,lt,le,gt,ge} - float4/float4 comparison operations
*/
+static 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 0;
+ else
+ return -1;
+ }
+}
+
Datum
float4eq(PG_FUNCTION_ARGS)
{
float4 arg1 = PG_GETARG_FLOAT4(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- PG_RETURN_BOOL(arg1 == arg2);
+ PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) == 0);
}
Datum
@@ -551,7 +588,7 @@ float4ne(PG_FUNCTION_ARGS)
float4 arg1 = PG_GETARG_FLOAT4(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- PG_RETURN_BOOL(arg1 != arg2);
+ PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) != 0);
}
Datum
@@ -560,7 +597,7 @@ float4lt(PG_FUNCTION_ARGS)
float4 arg1 = PG_GETARG_FLOAT4(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- PG_RETURN_BOOL(arg1 < arg2);
+ PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) < 0);
}
Datum
@@ -569,7 +606,7 @@ float4le(PG_FUNCTION_ARGS)
float4 arg1 = PG_GETARG_FLOAT4(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- PG_RETURN_BOOL(arg1 <= arg2);
+ PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) <= 0);
}
Datum
@@ -578,7 +615,7 @@ float4gt(PG_FUNCTION_ARGS)
float4 arg1 = PG_GETARG_FLOAT4(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- PG_RETURN_BOOL(arg1 > arg2);
+ PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) > 0);
}
Datum
@@ -587,19 +624,58 @@ float4ge(PG_FUNCTION_ARGS)
float4 arg1 = PG_GETARG_FLOAT4(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- PG_RETURN_BOOL(arg1 >= arg2);
+ PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) >= 0);
+}
+
+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));
}
/*
* float8{eq,ne,lt,le,gt,ge} - float8/float8 comparison operations
*/
+static 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 0;
+ else
+ return -1;
+ }
+}
+
Datum
float8eq(PG_FUNCTION_ARGS)
{
float8 arg1 = PG_GETARG_FLOAT8(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
- PG_RETURN_BOOL(arg1 == arg2);
+ PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
}
Datum
@@ -608,7 +684,7 @@ float8ne(PG_FUNCTION_ARGS)
float8 arg1 = PG_GETARG_FLOAT8(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
- PG_RETURN_BOOL(arg1 != arg2);
+ PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
}
Datum
@@ -617,7 +693,7 @@ float8lt(PG_FUNCTION_ARGS)
float8 arg1 = PG_GETARG_FLOAT8(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
- PG_RETURN_BOOL(arg1 < arg2);
+ PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
}
Datum
@@ -626,7 +702,7 @@ float8le(PG_FUNCTION_ARGS)
float8 arg1 = PG_GETARG_FLOAT8(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
- PG_RETURN_BOOL(arg1 <= arg2);
+ PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
}
Datum
@@ -635,7 +711,7 @@ float8gt(PG_FUNCTION_ARGS)
float8 arg1 = PG_GETARG_FLOAT8(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
- PG_RETURN_BOOL(arg1 > arg2);
+ PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
}
Datum
@@ -644,7 +720,16 @@ float8ge(PG_FUNCTION_ARGS)
float8 arg1 = PG_GETARG_FLOAT8(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
- PG_RETURN_BOOL(arg1 >= arg2);
+ PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+}
+
+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));
}
@@ -1650,7 +1735,7 @@ float48eq(PG_FUNCTION_ARGS)
float4 arg1 = PG_GETARG_FLOAT4(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
- PG_RETURN_BOOL(arg1 == arg2);
+ PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
}
Datum
@@ -1659,7 +1744,7 @@ float48ne(PG_FUNCTION_ARGS)
float4 arg1 = PG_GETARG_FLOAT4(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
- PG_RETURN_BOOL(arg1 != arg2);
+ PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
}
Datum
@@ -1668,7 +1753,7 @@ float48lt(PG_FUNCTION_ARGS)
float4 arg1 = PG_GETARG_FLOAT4(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
- PG_RETURN_BOOL(arg1 < arg2);
+ PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
}
Datum
@@ -1677,7 +1762,7 @@ float48le(PG_FUNCTION_ARGS)
float4 arg1 = PG_GETARG_FLOAT4(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
- PG_RETURN_BOOL(arg1 <= arg2);
+ PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
}
Datum
@@ -1686,7 +1771,7 @@ float48gt(PG_FUNCTION_ARGS)
float4 arg1 = PG_GETARG_FLOAT4(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
- PG_RETURN_BOOL(arg1 > arg2);
+ PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
}
Datum
@@ -1695,7 +1780,7 @@ float48ge(PG_FUNCTION_ARGS)
float4 arg1 = PG_GETARG_FLOAT4(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
- PG_RETURN_BOOL(arg1 >= arg2);
+ PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
}
/*
@@ -1707,7 +1792,7 @@ float84eq(PG_FUNCTION_ARGS)
float8 arg1 = PG_GETARG_FLOAT8(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- PG_RETURN_BOOL(arg1 == arg2);
+ PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
}
Datum
@@ -1716,7 +1801,7 @@ float84ne(PG_FUNCTION_ARGS)
float8 arg1 = PG_GETARG_FLOAT8(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- PG_RETURN_BOOL(arg1 != arg2);
+ PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
}
Datum
@@ -1725,7 +1810,7 @@ float84lt(PG_FUNCTION_ARGS)
float8 arg1 = PG_GETARG_FLOAT8(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- PG_RETURN_BOOL(arg1 < arg2);
+ PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
}
Datum
@@ -1734,7 +1819,7 @@ float84le(PG_FUNCTION_ARGS)
float8 arg1 = PG_GETARG_FLOAT8(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- PG_RETURN_BOOL(arg1 <= arg2);
+ PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
}
Datum
@@ -1743,7 +1828,7 @@ float84gt(PG_FUNCTION_ARGS)
float8 arg1 = PG_GETARG_FLOAT8(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- PG_RETURN_BOOL(arg1 > arg2);
+ PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
}
Datum
@@ -1752,7 +1837,7 @@ float84ge(PG_FUNCTION_ARGS)
float8 arg1 = PG_GETARG_FLOAT8(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- PG_RETURN_BOOL(arg1 >= arg2);
+ PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
}
/* ========== PRIVATE ROUTINES ========== */
diff --git a/src/backend/utils/adt/nabstime.c b/src/backend/utils/adt/nabstime.c
index 69ae1f1702..0f8ed87e5b 100644
--- a/src/backend/utils/adt/nabstime.c
+++ b/src/backend/utils/adt/nabstime.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.84 2001/04/26 21:52:17 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.85 2001/05/03 19:00:36 tgl Exp $
*
* NOTES
*
@@ -430,37 +430,6 @@ nabstimeout(PG_FUNCTION_ARGS)
}
-/*
- * AbsoluteTimeIsBefore -- true iff time1 is before time2.
- * AbsoluteTimeIsAfter -- true iff time1 is after time2.
- */
-bool
-AbsoluteTimeIsBefore(AbsoluteTime time1, AbsoluteTime time2)
-{
- if (time1 == CURRENT_ABSTIME)
- time1 = GetCurrentTransactionStartTime();
-
- if (time2 == CURRENT_ABSTIME)
- time2 = GetCurrentTransactionStartTime();
-
- return time1 < time2;
-}
-
-#ifdef NOT_USED
-bool
-AbsoluteTimeIsAfter(AbsoluteTime time1, AbsoluteTime time2)
-{
- if (time1 == CURRENT_ABSTIME)
- time1 = GetCurrentTransactionStartTime();
-
- if (time2 == CURRENT_ABSTIME)
- time2 = GetCurrentTransactionStartTime();
-
- return time1 > time2;
-}
-
-#endif
-
/* abstime_finite()
*/
Datum
@@ -475,27 +444,51 @@ abstime_finite(PG_FUNCTION_ARGS)
/*
- * abstimeeq - returns true iff arguments are equal
- * abstimene - returns true iff arguments are not equal
- * abstimelt - returns true iff t1 less than t2
- * abstimegt - returns true iff t1 greater than t2
- * abstimele - returns true iff t1 less than or equal to t2
- * abstimege - returns true iff t1 greater than or equal to t2
+ * abstime comparison routines
*/
+static int
+abstime_cmp_internal(AbsoluteTime a, AbsoluteTime b)
+{
+ /*
+ * We consider all INVALIDs to be equal and larger than any non-INVALID.
+ * This is somewhat arbitrary; the important thing is to have a
+ * consistent sort order.
+ */
+ if (a == INVALID_ABSTIME)
+ {
+ if (b == INVALID_ABSTIME)
+ return 0; /* INVALID = INVALID */
+ else
+ return 1; /* INVALID > non-INVALID */
+ }
+ else if (b == INVALID_ABSTIME)
+ {
+ return -1; /* non-INVALID < INVALID */
+ }
+ else
+ {
+ /* XXX this is broken, should go away: */
+ if (a == CURRENT_ABSTIME)
+ a = GetCurrentTransactionStartTime();
+ if (b == CURRENT_ABSTIME)
+ b = GetCurrentTransactionStartTime();
+
+ if (a > b)
+ return 1;
+ else if (a == b)
+ return 0;
+ else
+ return -1;
+ }
+}
+
Datum
abstimeeq(PG_FUNCTION_ARGS)
{
AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
- if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
- PG_RETURN_BOOL(false);
- if (t1 == CURRENT_ABSTIME)
- t1 = GetCurrentTransactionStartTime();
- if (t2 == CURRENT_ABSTIME)
- t2 = GetCurrentTransactionStartTime();
-
- PG_RETURN_BOOL(t1 == t2);
+ PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) == 0);
}
Datum
@@ -504,14 +497,7 @@ abstimene(PG_FUNCTION_ARGS)
AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
- if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
- PG_RETURN_BOOL(false);
- if (t1 == CURRENT_ABSTIME)
- t1 = GetCurrentTransactionStartTime();
- if (t2 == CURRENT_ABSTIME)
- t2 = GetCurrentTransactionStartTime();
-
- PG_RETURN_BOOL(t1 != t2);
+ PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) != 0);
}
Datum
@@ -520,14 +506,7 @@ abstimelt(PG_FUNCTION_ARGS)
AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
- if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
- PG_RETURN_BOOL(false);
- if (t1 == CURRENT_ABSTIME)
- t1 = GetCurrentTransactionStartTime();
- if (t2 == CURRENT_ABSTIME)
- t2 = GetCurrentTransactionStartTime();
-
- PG_RETURN_BOOL(t1 < t2);
+ PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) < 0);
}
Datum
@@ -536,14 +515,7 @@ abstimegt(PG_FUNCTION_ARGS)
AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
- if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
- PG_RETURN_BOOL(false);
- if (t1 == CURRENT_ABSTIME)
- t1 = GetCurrentTransactionStartTime();
- if (t2 == CURRENT_ABSTIME)
- t2 = GetCurrentTransactionStartTime();
-
- PG_RETURN_BOOL(t1 > t2);
+ PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) > 0);
}
Datum
@@ -552,14 +524,7 @@ abstimele(PG_FUNCTION_ARGS)
AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
- if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
- PG_RETURN_BOOL(false);
- if (t1 == CURRENT_ABSTIME)
- t1 = GetCurrentTransactionStartTime();
- if (t2 == CURRENT_ABSTIME)
- t2 = GetCurrentTransactionStartTime();
-
- PG_RETURN_BOOL(t1 <= t2);
+ PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) <= 0);
}
Datum
@@ -568,14 +533,16 @@ abstimege(PG_FUNCTION_ARGS)
AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
- if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
- PG_RETURN_BOOL(false);
- if (t1 == CURRENT_ABSTIME)
- t1 = GetCurrentTransactionStartTime();
- if (t2 == CURRENT_ABSTIME)
- t2 = GetCurrentTransactionStartTime();
+ PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) >= 0);
+}
- PG_RETURN_BOOL(t1 >= t2);
+Datum
+btabstimecmp(PG_FUNCTION_ARGS)
+{
+ AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
+ AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
+
+ PG_RETURN_INT32(abstime_cmp_internal(t1, t2));
}
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index d4e93cf875..99df5331bf 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -5,7 +5,7 @@
*
* 1998 Jan Wieck
*
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/numeric.c,v 1.40 2001/04/14 02:10:57 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/numeric.c,v 1.41 2001/05/03 19:00:36 tgl Exp $
*
* ----------
*/
@@ -153,6 +153,7 @@ static Numeric make_result(NumericVar *var);
static void apply_typmod(NumericVar *var, int32 typmod);
+static int cmp_numerics(Numeric num1, Numeric num2);
static int cmp_var(NumericVar *var1, NumericVar *var2);
static void add_var(NumericVar *var1, NumericVar *var2, NumericVar *result);
static void sub_var(NumericVar *var1, NumericVar *var2, NumericVar *result);
@@ -664,24 +665,7 @@ numeric_cmp(PG_FUNCTION_ARGS)
Numeric num2 = PG_GETARG_NUMERIC(1);
int result;
- if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
- result = 0;
- else
- {
- NumericVar arg1;
- NumericVar arg2;
-
- init_var(&arg1);
- init_var(&arg2);
-
- set_var_from_num(num1, &arg1);
- set_var_from_num(num2, &arg2);
-
- result = cmp_var(&arg1, &arg2);
-
- free_var(&arg1);
- free_var(&arg2);
- }
+ result = cmp_numerics(num1, num2);
PG_FREE_IF_COPY(num1, 0);
PG_FREE_IF_COPY(num2, 1);
@@ -697,24 +681,7 @@ numeric_eq(PG_FUNCTION_ARGS)
Numeric num2 = PG_GETARG_NUMERIC(1);
bool result;
- if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
- result = false;
- else
- {
- NumericVar arg1;
- NumericVar arg2;
-
- init_var(&arg1);
- init_var(&arg2);
-
- set_var_from_num(num1, &arg1);
- set_var_from_num(num2, &arg2);
-
- result = cmp_var(&arg1, &arg2) == 0;
-
- free_var(&arg1);
- free_var(&arg2);
- }
+ result = cmp_numerics(num1, num2) == 0;
PG_FREE_IF_COPY(num1, 0);
PG_FREE_IF_COPY(num2, 1);
@@ -729,24 +696,7 @@ numeric_ne(PG_FUNCTION_ARGS)
Numeric num2 = PG_GETARG_NUMERIC(1);
bool result;
- if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
- result = false;
- else
- {
- NumericVar arg1;
- NumericVar arg2;
-
- init_var(&arg1);
- init_var(&arg2);
-
- set_var_from_num(num1, &arg1);
- set_var_from_num(num2, &arg2);
-
- result = cmp_var(&arg1, &arg2) != 0;
-
- free_var(&arg1);
- free_var(&arg2);
- }
+ result = cmp_numerics(num1, num2) != 0;
PG_FREE_IF_COPY(num1, 0);
PG_FREE_IF_COPY(num2, 1);
@@ -761,24 +711,7 @@ numeric_gt(PG_FUNCTION_ARGS)
Numeric num2 = PG_GETARG_NUMERIC(1);
bool result;
- if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
- result = false;
- else
- {
- NumericVar arg1;
- NumericVar arg2;
-
- init_var(&arg1);
- init_var(&arg2);
-
- set_var_from_num(num1, &arg1);
- set_var_from_num(num2, &arg2);
-
- result = cmp_var(&arg1, &arg2) > 0;
-
- free_var(&arg1);
- free_var(&arg2);
- }
+ result = cmp_numerics(num1, num2) > 0;
PG_FREE_IF_COPY(num1, 0);
PG_FREE_IF_COPY(num2, 1);
@@ -793,24 +726,7 @@ numeric_ge(PG_FUNCTION_ARGS)
Numeric num2 = PG_GETARG_NUMERIC(1);
bool result;
- if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
- result = false;
- else
- {
- NumericVar arg1;
- NumericVar arg2;
-
- init_var(&arg1);
- init_var(&arg2);
-
- set_var_from_num(num1, &arg1);
- set_var_from_num(num2, &arg2);
-
- result = cmp_var(&arg1, &arg2) >= 0;
-
- free_var(&arg1);
- free_var(&arg2);
- }
+ result = cmp_numerics(num1, num2) >= 0;
PG_FREE_IF_COPY(num1, 0);
PG_FREE_IF_COPY(num2, 1);
@@ -825,24 +741,7 @@ numeric_lt(PG_FUNCTION_ARGS)
Numeric num2 = PG_GETARG_NUMERIC(1);
bool result;
- if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
- result = false;
- else
- {
- NumericVar arg1;
- NumericVar arg2;
-
- init_var(&arg1);
- init_var(&arg2);
-
- set_var_from_num(num1, &arg1);
- set_var_from_num(num2, &arg2);
-
- result = cmp_var(&arg1, &arg2) < 0;
-
- free_var(&arg1);
- free_var(&arg2);
- }
+ result = cmp_numerics(num1, num2) < 0;
PG_FREE_IF_COPY(num1, 0);
PG_FREE_IF_COPY(num2, 1);
@@ -857,8 +756,35 @@ numeric_le(PG_FUNCTION_ARGS)
Numeric num2 = PG_GETARG_NUMERIC(1);
bool result;
- if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
- result = false;
+ result = cmp_numerics(num1, num2) <= 0;
+
+ PG_FREE_IF_COPY(num1, 0);
+ PG_FREE_IF_COPY(num2, 1);
+
+ PG_RETURN_BOOL(result);
+}
+
+static int
+cmp_numerics(Numeric num1, Numeric num2)
+{
+ int result;
+
+ /*
+ * 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 (NUMERIC_IS_NAN(num1))
+ {
+ if (NUMERIC_IS_NAN(num2))
+ result = 0; /* NAN = NAN */
+ else
+ result = 1; /* NAN > non-NAN */
+ }
+ else if (NUMERIC_IS_NAN(num2))
+ {
+ result = -1; /* non-NAN < NAN */
+ }
else
{
NumericVar arg1;
@@ -870,16 +796,13 @@ numeric_le(PG_FUNCTION_ARGS)
set_var_from_num(num1, &arg1);
set_var_from_num(num2, &arg2);
- result = cmp_var(&arg1, &arg2) <= 0;
+ result = cmp_var(&arg1, &arg2);
free_var(&arg1);
free_var(&arg2);
}
- PG_FREE_IF_COPY(num1, 0);
- PG_FREE_IF_COPY(num2, 1);
-
- PG_RETURN_BOOL(result);
+ return result;
}
@@ -1663,6 +1586,7 @@ numeric_int2(PG_FUNCTION_ARGS)
char *str;
Datum result;
+ /* XXX would it be better to return NULL? */
if (NUMERIC_IS_NAN(num))
elog(ERROR, "Cannot convert NaN to int2");
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index f4c90dc372..186103252b 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.47 2001/04/03 18:05:53 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.48 2001/05/03 19:00:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -542,22 +542,34 @@ SetTimestamp(Timestamp dt)
/*
* timestamp_relop - is timestamp1 relop timestamp2
+ *
+ * collate invalid timestamp at the end
*/
+static int
+timestamp_cmp_internal(Timestamp dt1, Timestamp dt2)
+{
+ if (TIMESTAMP_IS_INVALID(dt1))
+ return (TIMESTAMP_IS_INVALID(dt2) ? 0 : 1);
+ else if (TIMESTAMP_IS_INVALID(dt2))
+ return -1;
+ else
+ {
+ if (TIMESTAMP_IS_RELATIVE(dt1))
+ dt1 = SetTimestamp(dt1);
+ if (TIMESTAMP_IS_RELATIVE(dt2))
+ dt2 = SetTimestamp(dt2);
+
+ return ((dt1 < dt2) ? -1 : ((dt1 > dt2) ? 1 : 0));
+ }
+}
+
Datum
timestamp_eq(PG_FUNCTION_ARGS)
{
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
- if (TIMESTAMP_IS_INVALID(dt1) || TIMESTAMP_IS_INVALID(dt2))
- PG_RETURN_BOOL(false);
-
- if (TIMESTAMP_IS_RELATIVE(dt1))
- dt1 = SetTimestamp(dt1);
- if (TIMESTAMP_IS_RELATIVE(dt2))
- dt2 = SetTimestamp(dt2);
-
- PG_RETURN_BOOL(dt1 == dt2);
+ PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
}
Datum
@@ -566,15 +578,7 @@ timestamp_ne(PG_FUNCTION_ARGS)
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
- if (TIMESTAMP_IS_INVALID(dt1) || TIMESTAMP_IS_INVALID(dt2))
- PG_RETURN_BOOL(false);
-
- if (TIMESTAMP_IS_RELATIVE(dt1))
- dt1 = SetTimestamp(dt1);
- if (TIMESTAMP_IS_RELATIVE(dt2))
- dt2 = SetTimestamp(dt2);
-
- PG_RETURN_BOOL(dt1 != dt2);
+ PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
}
Datum
@@ -583,15 +587,7 @@ timestamp_lt(PG_FUNCTION_ARGS)
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
- if (TIMESTAMP_IS_INVALID(dt1) || TIMESTAMP_IS_INVALID(dt2))
- PG_RETURN_BOOL(false);
-
- if (TIMESTAMP_IS_RELATIVE(dt1))
- dt1 = SetTimestamp(dt1);
- if (TIMESTAMP_IS_RELATIVE(dt2))
- dt2 = SetTimestamp(dt2);
-
- PG_RETURN_BOOL(dt1 < dt2);
+ PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
}
Datum
@@ -600,15 +596,7 @@ timestamp_gt(PG_FUNCTION_ARGS)
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
- if (TIMESTAMP_IS_INVALID(dt1) || TIMESTAMP_IS_INVALID(dt2))
- PG_RETURN_BOOL(false);
-
- if (TIMESTAMP_IS_RELATIVE(dt1))
- dt1 = SetTimestamp(dt1);
- if (TIMESTAMP_IS_RELATIVE(dt2))
- dt2 = SetTimestamp(dt2);
-
- PG_RETURN_BOOL(dt1 > dt2);
+ PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
}
Datum
@@ -617,15 +605,7 @@ timestamp_le(PG_FUNCTION_ARGS)
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
- if (TIMESTAMP_IS_INVALID(dt1) || TIMESTAMP_IS_INVALID(dt2))
- PG_RETURN_BOOL(false);
-
- if (TIMESTAMP_IS_RELATIVE(dt1))
- dt1 = SetTimestamp(dt1);
- if (TIMESTAMP_IS_RELATIVE(dt2))
- dt2 = SetTimestamp(dt2);
-
- PG_RETURN_BOOL(dt1 <= dt2);
+ PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
}
Datum
@@ -634,57 +614,54 @@ timestamp_ge(PG_FUNCTION_ARGS)
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
- if (TIMESTAMP_IS_INVALID(dt1) || TIMESTAMP_IS_INVALID(dt2))
- PG_RETURN_BOOL(false);
-
- if (TIMESTAMP_IS_RELATIVE(dt1))
- dt1 = SetTimestamp(dt1);
- if (TIMESTAMP_IS_RELATIVE(dt2))
- dt2 = SetTimestamp(dt2);
-
- PG_RETURN_BOOL(dt1 >= dt2);
+ PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
}
-
-/* timestamp_cmp - 3-state comparison for timestamp
- * collate invalid timestamp at the end
- */
Datum
timestamp_cmp(PG_FUNCTION_ARGS)
{
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
- if (TIMESTAMP_IS_INVALID(dt1))
- PG_RETURN_INT32(TIMESTAMP_IS_INVALID(dt2) ? 0 : 1);
- else if (TIMESTAMP_IS_INVALID(dt2))
- PG_RETURN_INT32(-1);
- else
- {
- if (TIMESTAMP_IS_RELATIVE(dt1))
- dt1 = SetTimestamp(dt1);
- if (TIMESTAMP_IS_RELATIVE(dt2))
- dt2 = SetTimestamp(dt2);
- }
-
- PG_RETURN_INT32((dt1 < dt2) ? -1 : ((dt1 > dt2) ? 1 : 0));
+ PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
}
/*
* interval_relop - is interval1 relop interval2
+ *
+ * collate invalid interval at the end
*/
+static int
+interval_cmp_internal(Interval *interval1, Interval *interval2)
+{
+ if (INTERVAL_IS_INVALID(*interval1))
+ return (INTERVAL_IS_INVALID(*interval2) ? 0 : 1);
+ else if (INTERVAL_IS_INVALID(*interval2))
+ return -1;
+ else
+ {
+ double span1,
+ span2;
+
+ span1 = interval1->time;
+ if (interval1->month != 0)
+ span1 += (interval1->month * (30.0 * 86400));
+ span2 = interval2->time;
+ if (interval2->month != 0)
+ span2 += (interval2->month * (30.0 * 86400));
+
+ return ((span1 < span2) ? -1 : (span1 > span2) ? 1 : 0);
+ }
+}
+
Datum
interval_eq(PG_FUNCTION_ARGS)
{
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
- if (INTERVAL_IS_INVALID(*interval1) || INTERVAL_IS_INVALID(*interval2))
- PG_RETURN_BOOL(false);
-
- PG_RETURN_BOOL((interval1->time == interval2->time) &&
- (interval1->month == interval2->month));
+ PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) == 0);
}
Datum
@@ -693,11 +670,7 @@ interval_ne(PG_FUNCTION_ARGS)
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
- if (INTERVAL_IS_INVALID(*interval1) || INTERVAL_IS_INVALID(*interval2))
- PG_RETURN_BOOL(false);
-
- PG_RETURN_BOOL((interval1->time != interval2->time) ||
- (interval1->month != interval2->month));
+ PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) != 0);
}
Datum
@@ -705,20 +678,8 @@ interval_lt(PG_FUNCTION_ARGS)
{
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
- double span1,
- span2;
- if (INTERVAL_IS_INVALID(*interval1) || INTERVAL_IS_INVALID(*interval2))
- PG_RETURN_BOOL(false);
-
- span1 = interval1->time;
- if (interval1->month != 0)
- span1 += (interval1->month * (30.0 * 86400));
- span2 = interval2->time;
- if (interval2->month != 0)
- span2 += (interval2->month * (30.0 * 86400));
-
- PG_RETURN_BOOL(span1 < span2);
+ PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) < 0);
}
Datum
@@ -726,20 +687,8 @@ interval_gt(PG_FUNCTION_ARGS)
{
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
- double span1,
- span2;
-
- if (INTERVAL_IS_INVALID(*interval1) || INTERVAL_IS_INVALID(*interval2))
- PG_RETURN_BOOL(false);
-
- span1 = interval1->time;
- if (interval1->month != 0)
- span1 += (interval1->month * (30.0 * 86400));
- span2 = interval2->time;
- if (interval2->month != 0)
- span2 += (interval2->month * (30.0 * 86400));
- PG_RETURN_BOOL(span1 > span2);
+ PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) > 0);
}
Datum
@@ -747,20 +696,8 @@ interval_le(PG_FUNCTION_ARGS)
{
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
- double span1,
- span2;
-
- if (INTERVAL_IS_INVALID(*interval1) || INTERVAL_IS_INVALID(*interval2))
- PG_RETURN_BOOL(false);
-
- span1 = interval1->time;
- if (interval1->month != 0)
- span1 += (interval1->month * (30.0 * 86400));
- span2 = interval2->time;
- if (interval2->month != 0)
- span2 += (interval2->month * (30.0 * 86400));
- PG_RETURN_BOOL(span1 <= span2);
+ PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) <= 0);
}
Datum
@@ -768,46 +705,17 @@ interval_ge(PG_FUNCTION_ARGS)
{
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
- double span1,
- span2;
- if (INTERVAL_IS_INVALID(*interval1) || INTERVAL_IS_INVALID(*interval2))
- PG_RETURN_BOOL(false);
-
- span1 = interval1->time;
- if (interval1->month != 0)
- span1 += (interval1->month * (30.0 * 86400));
- span2 = interval2->time;
- if (interval2->month != 0)
- span2 += (interval2->month * (30.0 * 86400));
-
- PG_RETURN_BOOL(span1 >= span2);
+ PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) >= 0);
}
-
-/* interval_cmp - 3-state comparison for interval
- */
Datum
interval_cmp(PG_FUNCTION_ARGS)
{
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
- double span1,
- span2;
-
- if (INTERVAL_IS_INVALID(*interval1))
- PG_RETURN_INT32(INTERVAL_IS_INVALID(*interval2) ? 0 : 1);
- else if (INTERVAL_IS_INVALID(*interval2))
- PG_RETURN_INT32(-1);
-
- span1 = interval1->time;
- if (interval1->month != 0)
- span1 += (interval1->month * (30.0 * 86400));
- span2 = interval2->time;
- if (interval2->month != 0)
- span2 += (interval2->month * (30.0 * 86400));
- PG_RETURN_INT32((span1 < span2) ? -1 : (span1 > span2) ? 1 : 0);
+ PG_RETURN_INT32(interval_cmp_internal(interval1, interval2));
}
/*
diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c
index 775382568b..5d03683dd6 100644
--- a/src/backend/utils/adt/varbit.c
+++ b/src/backend/utils/adt/varbit.c
@@ -9,7 +9,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/varbit.c,v 1.16 2001/03/22 03:59:54 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/varbit.c,v 1.17 2001/05/03 19:00:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -537,6 +537,36 @@ _varbit(PG_FUNCTION_ARGS)
* need to be so careful.
*/
+/* bit_cmp
+ *
+ * Compares two bitstrings and returns <0, 0, >0 depending on whether the first
+ * string is smaller, equal, or bigger than the second. All bits are considered
+ * and additional zero bits may make one string smaller/larger than the other,
+ * even if their zero-padded values would be the same.
+ */
+static int32
+bit_cmp(VarBit *arg1, VarBit *arg2)
+{
+ int bitlen1,
+ bytelen1,
+ bitlen2,
+ bytelen2;
+ int32 cmp;
+
+ bytelen1 = VARBITBYTES(arg1);
+ bytelen2 = VARBITBYTES(arg2);
+
+ cmp = memcmp(VARBITS(arg1), VARBITS(arg2), Min(bytelen1, bytelen2));
+ if (cmp == 0)
+ {
+ bitlen1 = VARBITLEN(arg1);
+ bitlen2 = VARBITLEN(arg2);
+ if (bitlen1 != bitlen2)
+ cmp = (bitlen1 < bitlen2) ? -1 : 1;
+ }
+ return cmp;
+}
+
Datum
biteq(PG_FUNCTION_ARGS)
{
@@ -548,13 +578,12 @@ biteq(PG_FUNCTION_ARGS)
bitlen1 = VARBITLEN(arg1);
bitlen2 = VARBITLEN(arg2);
+
+ /* fast path for different-length inputs */
if (bitlen1 != bitlen2)
result = false;
else
- {
- /* bit strings are always stored in a full number of bytes */
- result = memcmp(VARBITS(arg1), VARBITS(arg2), VARBITBYTES(arg1)) == 0;
- }
+ result = (bit_cmp(arg1, arg2) == 0);
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
@@ -573,13 +602,12 @@ bitne(PG_FUNCTION_ARGS)
bitlen1 = VARBITLEN(arg1);
bitlen2 = VARBITLEN(arg2);
+
+ /* fast path for different-length inputs */
if (bitlen1 != bitlen2)
result = true;
else
- {
- /* bit strings are always stored in a full number of bytes */
- result = memcmp(VARBITS(arg1), VARBITS(arg2), VARBITBYTES(arg1)) != 0;
- }
+ result = (bit_cmp(arg1, arg2) != 0);
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
@@ -587,36 +615,6 @@ bitne(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(result);
}
-/* bit_cmp
- *
- * Compares two bitstrings and returns <0, 0, >0 depending on whether the first
- * string is smaller, equal, or bigger than the second. All bits are considered
- * and additional zero bits may make one string smaller/larger than the other,
- * even if their zero-padded values would be the same.
- */
-static int32
-bit_cmp(VarBit *arg1, VarBit *arg2)
-{
- int bitlen1,
- bytelen1,
- bitlen2,
- bytelen2;
- int32 cmp;
-
- bytelen1 = VARBITBYTES(arg1);
- bytelen2 = VARBITBYTES(arg2);
-
- cmp = memcmp(VARBITS(arg1), VARBITS(arg2), Min(bytelen1, bytelen2));
- if (cmp == 0)
- {
- bitlen1 = VARBITLEN(arg1);
- bitlen2 = VARBITLEN(arg2);
- if (bitlen1 != bitlen2)
- cmp = (bitlen1 < bitlen2) ? -1 : 1;
- }
- return cmp;
-}
-
Datum
bitlt(PG_FUNCTION_ARGS)
{
diff --git a/src/backend/utils/adt/varchar.c b/src/backend/utils/adt/varchar.c
index adb41eed68..588c735ca1 100644
--- a/src/backend/utils/adt/varchar.c
+++ b/src/backend/utils/adt/varchar.c
@@ -8,11 +8,10 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.76 2001/04/19 19:01:23 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.77 2001/05/03 19:00:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
-
#include "postgres.h"
#include "access/hash.h"
@@ -526,10 +525,11 @@ bpchareq(PG_FUNCTION_ARGS)
len1 = bcTruelen(arg1);
len2 = bcTruelen(arg2);
+ /* fast path for different-length inputs */
if (len1 != len2)
result = false;
else
- result = (strncmp(VARDATA(arg1), VARDATA(arg2), len1) == 0);
+ result = (varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2) == 0);
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
@@ -549,10 +549,11 @@ bpcharne(PG_FUNCTION_ARGS)
len1 = bcTruelen(arg1);
len2 = bcTruelen(arg2);
+ /* fast path for different-length inputs */
if (len1 != len2)
result = true;
else
- result = (strncmp(VARDATA(arg1), VARDATA(arg2), len1) != 0);
+ result = (varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2) != 0);
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
@@ -745,10 +746,11 @@ varchareq(PG_FUNCTION_ARGS)
len1 = VARSIZE(arg1) - VARHDRSZ;
len2 = VARSIZE(arg2) - VARHDRSZ;
+ /* fast path for different-length inputs */
if (len1 != len2)
result = false;
else
- result = (strncmp(VARDATA(arg1), VARDATA(arg2), len1) == 0);
+ result = (varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2) == 0);
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
@@ -768,10 +770,11 @@ varcharne(PG_FUNCTION_ARGS)
len1 = VARSIZE(arg1) - VARHDRSZ;
len2 = VARSIZE(arg2) - VARHDRSZ;
+ /* fast path for different-length inputs */
if (len1 != len2)
result = true;
else
- result = (strncmp(VARDATA(arg1), VARDATA(arg2), len1) != 0);
+ result = (varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2) != 0);
PG_FREE_IF_COPY(arg1, 0);
PG_FREE_IF_COPY(arg2, 1);
diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c
index efa6ab6552..c534c7d92e 100644
--- a/src/backend/utils/adt/varlena.c
+++ b/src/backend/utils/adt/varlena.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.69 2001/03/22 03:59:55 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.70 2001/05/03 19:00:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -440,72 +440,6 @@ textpos(PG_FUNCTION_ARGS)
PG_RETURN_INT32(pos);
}
-/*
- * texteq - returns true iff arguments are equal
- * textne - returns true iff arguments are not equal
- *
- * Note: btree indexes need these routines not to leak memory; therefore,
- * be careful to free working copies of toasted datums. Most places don't
- * need to be so careful.
- */
-Datum
-texteq(PG_FUNCTION_ARGS)
-{
- text *arg1 = PG_GETARG_TEXT_P(0);
- text *arg2 = PG_GETARG_TEXT_P(1);
- bool result;
-
- if (VARSIZE(arg1) != VARSIZE(arg2))
- result = false;
- else
- {
- int len;
- char *a1p,
- *a2p;
-
- len = VARSIZE(arg1) - VARHDRSZ;
-
- a1p = VARDATA(arg1);
- a2p = VARDATA(arg2);
-
- result = (memcmp(a1p, a2p, len) == 0);
- }
-
- PG_FREE_IF_COPY(arg1, 0);
- PG_FREE_IF_COPY(arg2, 1);
-
- PG_RETURN_BOOL(result);
-}
-
-Datum
-textne(PG_FUNCTION_ARGS)
-{
- text *arg1 = PG_GETARG_TEXT_P(0);
- text *arg2 = PG_GETARG_TEXT_P(1);
- bool result;
-
- if (VARSIZE(arg1) != VARSIZE(arg2))
- result = true;
- else
- {
- int len;
- char *a1p,
- *a2p;
-
- len = VARSIZE(arg1) - VARHDRSZ;
-
- a1p = VARDATA(arg1);
- a2p = VARDATA(arg2);
-
- result = (memcmp(a1p, a2p, len) != 0);
- }
-
- PG_FREE_IF_COPY(arg1, 0);
- PG_FREE_IF_COPY(arg2, 1);
-
- PG_RETURN_BOOL(result);
-}
-
/* varstr_cmp()
* Comparison function for text strings with given lengths.
* Includes locale support, but must copy strings to temporary memory
@@ -520,8 +454,8 @@ varstr_cmp(char *arg1, int len1, char *arg2, int len2)
*a2p;
#ifdef USE_LOCALE
- a1p = (unsigned char *) palloc(len1 + 1);
- a2p = (unsigned char *) palloc(len2 + 1);
+ a1p = (char *) palloc(len1 + 1);
+ a2p = (char *) palloc(len2 + 1);
memcpy(a1p, arg1, len1);
*(a1p + len1) = '\0';
@@ -548,11 +482,7 @@ varstr_cmp(char *arg1, int len1, char *arg2, int len2)
/* text_cmp()
- * Comparison function for text strings.
- * Includes locale support, but must copy strings to temporary memory
- * to allow null-termination for inputs to strcoll().
- * XXX HACK code for textlen() indicates that there can be embedded nulls
- * but it appears that most routines (incl. this one) assume not! - tgl 97/04/07
+ * Internal comparison function for text strings.
* Returns -1, 0 or 1
*/
static int
@@ -581,6 +511,44 @@ text_cmp(text *arg1, text *arg2)
*/
Datum
+texteq(PG_FUNCTION_ARGS)
+{
+ text *arg1 = PG_GETARG_TEXT_P(0);
+ text *arg2 = PG_GETARG_TEXT_P(1);
+ bool result;
+
+ /* fast path for different-length inputs */
+ if (VARSIZE(arg1) != VARSIZE(arg2))
+ result = false;
+ else
+ result = (text_cmp(arg1, arg2) == 0);
+
+ PG_FREE_IF_COPY(arg1, 0);
+ PG_FREE_IF_COPY(arg2, 1);
+
+ PG_RETURN_BOOL(result);
+}
+
+Datum
+textne(PG_FUNCTION_ARGS)
+{
+ text *arg1 = PG_GETARG_TEXT_P(0);
+ text *arg2 = PG_GETARG_TEXT_P(1);
+ bool result;
+
+ /* fast path for different-length inputs */
+ if (VARSIZE(arg1) != VARSIZE(arg2))
+ result = true;
+ else
+ result = (text_cmp(arg1, arg2) != 0);
+
+ PG_FREE_IF_COPY(arg1, 0);
+ PG_FREE_IF_COPY(arg2, 1);
+
+ PG_RETURN_BOOL(result);
+}
+
+Datum
text_lt(PG_FUNCTION_ARGS)
{
text *arg1 = PG_GETARG_TEXT_P(0);
@@ -641,6 +609,22 @@ text_ge(PG_FUNCTION_ARGS)
}
Datum
+bttextcmp(PG_FUNCTION_ARGS)
+{
+ text *arg1 = PG_GETARG_TEXT_P(0);
+ text *arg2 = PG_GETARG_TEXT_P(1);
+ int32 result;
+
+ result = text_cmp(arg1, arg2);
+
+ PG_FREE_IF_COPY(arg1, 0);
+ PG_FREE_IF_COPY(arg2, 1);
+
+ PG_RETURN_INT32(result);
+}
+
+
+Datum
text_larger(PG_FUNCTION_ARGS)
{
text *arg1 = PG_GETARG_TEXT_P(0);
diff --git a/src/include/utils/nabstime.h b/src/include/utils/nabstime.h
index 1e09e82e69..d5343e5a14 100644
--- a/src/include/utils/nabstime.h
+++ b/src/include/utils/nabstime.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: nabstime.h,v 1.29 2001/03/22 04:01:13 momjian Exp $
+ * $Id: nabstime.h,v 1.30 2001/05/03 19:00:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -158,7 +158,6 @@ extern Datum timeofday(PG_FUNCTION_ARGS);
/* non-fmgr-callable support routines */
extern AbsoluteTime GetCurrentAbsoluteTime(void);
-extern bool AbsoluteTimeIsBefore(AbsoluteTime time1, AbsoluteTime time2);
extern void abstime2tm(AbsoluteTime time, int *tzp, struct tm * tm, char *tzn);
#endif /* NABSTIME_H */
diff --git a/src/test/regress/expected/abstime-solaris-1947.out b/src/test/regress/expected/abstime-solaris-1947.out
index f5b78a1b4f..569205ab6b 100644
--- a/src/test/regress/expected/abstime-solaris-1947.out
+++ b/src/test/regress/expected/abstime-solaris-1947.out
@@ -62,7 +62,8 @@ SELECT '' AS six, ABSTIME_TBL.*
| current
| infinity
| Sat May 10 23:59:12 1947 PDT
-(6 rows)
+ | invalid
+(7 rows)
SELECT '' AS six, ABSTIME_TBL.*
WHERE abstime 'May 10, 1947 23:59:12' <> ABSTIME_TBL.f1;
@@ -74,7 +75,8 @@ SELECT '' AS six, ABSTIME_TBL.*
| current
| infinity
| -infinity
-(6 rows)
+ | invalid
+(7 rows)
SELECT '' AS one, ABSTIME_TBL.*
WHERE abstime 'current' = ABSTIME_TBL.f1;
diff --git a/src/test/regress/expected/abstime.out b/src/test/regress/expected/abstime.out
index ddafc77ce0..391b4e361a 100644
--- a/src/test/regress/expected/abstime.out
+++ b/src/test/regress/expected/abstime.out
@@ -62,7 +62,8 @@ SELECT '' AS six, ABSTIME_TBL.*
| current
| infinity
| Sat May 10 23:59:12 1947 PST
-(6 rows)
+ | invalid
+(7 rows)
SELECT '' AS six, ABSTIME_TBL.*
WHERE abstime 'May 10, 1947 23:59:12' <> ABSTIME_TBL.f1;
@@ -74,7 +75,8 @@ SELECT '' AS six, ABSTIME_TBL.*
| current
| infinity
| -infinity
-(6 rows)
+ | invalid
+(7 rows)
SELECT '' AS one, ABSTIME_TBL.*
WHERE abstime 'current' = ABSTIME_TBL.f1;
diff --git a/src/test/regress/expected/timestamp.out b/src/test/regress/expected/timestamp.out
index a7f4e6c0ae..60d3673543 100644
--- a/src/test/regress/expected/timestamp.out
+++ b/src/test/regress/expected/timestamp.out
@@ -265,8 +265,11 @@ SELECT '' AS "47", d1 FROM TIMESTAMP_TBL
WHERE d1 > timestamp '1997-01-02' and d1 != timestamp 'current';
47 | d1
----+---------------------------------
+ | invalid
| infinity
| Mon Feb 10 17:32:01 1997 PST
+ | invalid
+ | invalid
| Mon Feb 10 17:32:01.00 1997 PST
| Mon Feb 10 17:32:02.00 1997 PST
| Mon Feb 10 17:32:01.40 1997 PST
@@ -312,7 +315,7 @@ SELECT '' AS "47", d1 FROM TIMESTAMP_TBL
| Sat Jan 01 17:32:01 2000 PST
| Sun Dec 31 17:32:01 2000 PST
| Mon Jan 01 17:32:01 2001 PST
-(47 rows)
+(50 rows)
SELECT '' AS "15", d1 FROM TIMESTAMP_TBL
WHERE d1 < timestamp '1997-01-02' and d1 != timestamp 'current';
@@ -346,10 +349,13 @@ SELECT '' AS "62", d1 FROM TIMESTAMP_TBL
WHERE d1 != timestamp '1997-01-02' and d1 != timestamp 'current';
62 | d1
----+---------------------------------
+ | invalid
| -infinity
| infinity
| epoch
| Mon Feb 10 17:32:01 1997 PST
+ | invalid
+ | invalid
| Mon Feb 10 17:32:01.00 1997 PST
| Mon Feb 10 17:32:02.00 1997 PST
| Mon Feb 10 17:32:01.40 1997 PST
@@ -408,7 +414,7 @@ SELECT '' AS "62", d1 FROM TIMESTAMP_TBL
| Sat Jan 01 17:32:01 2000 PST
| Sun Dec 31 17:32:01 2000 PST
| Mon Jan 01 17:32:01 2001 PST
-(62 rows)
+(65 rows)
SELECT '' AS "16", d1 FROM TIMESTAMP_TBL
WHERE d1 <= timestamp '1997-01-02' and d1 != timestamp 'current';
@@ -436,8 +442,11 @@ SELECT '' AS "48", d1 FROM TIMESTAMP_TBL
WHERE d1 >= timestamp '1997-01-02' and d1 != timestamp 'current';
48 | d1
----+---------------------------------
+ | invalid
| infinity
| Mon Feb 10 17:32:01 1997 PST
+ | invalid
+ | invalid
| Mon Feb 10 17:32:01.00 1997 PST
| Mon Feb 10 17:32:02.00 1997 PST
| Mon Feb 10 17:32:01.40 1997 PST
@@ -484,7 +493,7 @@ SELECT '' AS "48", d1 FROM TIMESTAMP_TBL
| Sat Jan 01 17:32:01 2000 PST
| Sun Dec 31 17:32:01 2000 PST
| Mon Jan 01 17:32:01 2001 PST
-(48 rows)
+(51 rows)
SELECT '' AS "66", d1 + interval '1 year' AS one_year FROM TIMESTAMP_TBL;
66 | one_year