Commit 2792374c authored by Tom Lane's avatar Tom Lane

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.
parent 77fe28f3
......@@ -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)
{
......@@ -85,34 +97,6 @@ btint8cmp(PG_FUNCTION_ARGS)
PG_RETURN_INT32(-1);
}
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)
{
......@@ -147,20 +131,6 @@ btoidvectorcmp(PG_FUNCTION_ARGS)
PG_RETURN_INT32(0);
}
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)
{
......@@ -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);
}
......@@ -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));
}
/*
......
......@@ -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 ========== */
......
......@@ -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));
}
......
......@@ -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");
......
......@@ -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));
}
/*
......
......@@ -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)
{
......
......@@ -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);
......
......@@ -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
......@@ -580,6 +510,44 @@ text_cmp(text *arg1, text *arg2)
* 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;
/* 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)
{
......@@ -640,6 +608,22 @@ text_ge(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(result);
}
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)
{
......
......@@ -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 */
......@@ -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;
......
......@@ -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;
......
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment