mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
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.
This commit is contained in:
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* NOTES
|
||||||
*
|
*
|
||||||
@ -25,7 +25,20 @@
|
|||||||
* NOTE: although any negative int32 is acceptable for reporting "<",
|
* NOTE: although any negative int32 is acceptable for reporting "<",
|
||||||
* and any positive int32 is acceptable for reporting ">", routines
|
* and any positive int32 is acceptable for reporting ">", routines
|
||||||
* that work on 32-bit or wider datatypes can't just return "a - b".
|
* 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
|
* NOTE: these routines must not leak memory, since memory allocated
|
||||||
* during an index access won't be recovered till end of query. This
|
* 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.
|
* they have to be careful to free any detoasted copy of an input datum.
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "utils/nabstime.h"
|
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
|
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
btboolcmp(PG_FUNCTION_ARGS)
|
btboolcmp(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
@ -85,34 +97,6 @@ btint8cmp(PG_FUNCTION_ARGS)
|
|||||||
PG_RETURN_INT32(-1);
|
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
|
Datum
|
||||||
btoidcmp(PG_FUNCTION_ARGS)
|
btoidcmp(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
@ -147,20 +131,6 @@ btoidvectorcmp(PG_FUNCTION_ARGS)
|
|||||||
PG_RETURN_INT32(0);
|
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
|
Datum
|
||||||
btcharcmp(PG_FUNCTION_ARGS)
|
btcharcmp(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
@ -179,79 +149,3 @@ btnamecmp(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
PG_RETURN_INT32(strncmp(NameStr(*a), NameStr(*b), NAMEDATALEN));
|
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
|
* 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
|
Datum
|
||||||
timetz_eq(PG_FUNCTION_ARGS)
|
timetz_eq(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
|
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
|
||||||
TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
|
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
|
Datum
|
||||||
@ -914,7 +936,7 @@ timetz_ne(PG_FUNCTION_ARGS)
|
|||||||
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
|
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
|
||||||
TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
|
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
|
Datum
|
||||||
@ -923,7 +945,7 @@ timetz_lt(PG_FUNCTION_ARGS)
|
|||||||
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
|
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
|
||||||
TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
|
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
|
Datum
|
||||||
@ -932,7 +954,7 @@ timetz_le(PG_FUNCTION_ARGS)
|
|||||||
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
|
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
|
||||||
TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
|
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
|
Datum
|
||||||
@ -941,7 +963,7 @@ timetz_gt(PG_FUNCTION_ARGS)
|
|||||||
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
|
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
|
||||||
TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
|
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
|
Datum
|
||||||
@ -950,7 +972,7 @@ timetz_ge(PG_FUNCTION_ARGS)
|
|||||||
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
|
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
|
||||||
TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
|
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
|
Datum
|
||||||
@ -959,15 +981,7 @@ timetz_cmp(PG_FUNCTION_ARGS)
|
|||||||
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
|
TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
|
||||||
TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
|
TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
|
||||||
|
|
||||||
if (DatumGetBool(DirectFunctionCall2(timetz_lt,
|
PG_RETURN_INT32(timetz_cmp_internal(time1, time2));
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -8,11 +8,11 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* OLD COMMENTS
|
||||||
* Basic float4 ops:
|
* Basic float4 ops:
|
||||||
* float4in, float4out, float4abs, float4um
|
* float4in, float4out, float4abs, float4um
|
||||||
@ -22,8 +22,8 @@
|
|||||||
* float4pl, float4mi, float4mul, float4div
|
* float4pl, float4mi, float4mul, float4div
|
||||||
* float8pl, float8mi, float8mul, float8div
|
* float8pl, float8mi, float8mul, float8div
|
||||||
* Comparison operators:
|
* Comparison operators:
|
||||||
* float4eq, float4ne, float4lt, float4le, float4gt, float4ge
|
* float4eq, float4ne, float4lt, float4le, float4gt, float4ge, float4cmp
|
||||||
* float8eq, float8ne, float8lt, float8le, float8gt, float8ge
|
* float8eq, float8ne, float8lt, float8le, float8gt, float8ge, float8cmp
|
||||||
* Conversion routines:
|
* Conversion routines:
|
||||||
* ftod, dtof, i4tod, dtoi4, i2tod, dtoi2, itof, ftoi, i2tof, ftoi2
|
* ftod, dtof, i4tod, dtoi4, i2tod, dtoi2, itof, ftoi, i2tof, ftoi2
|
||||||
*
|
*
|
||||||
@ -37,7 +37,8 @@
|
|||||||
* float84eq, float84ne, float84lt, float84le, float84gt, float84ge
|
* float84eq, float84ne, float84lt, float84le, float84gt, float84ge
|
||||||
*
|
*
|
||||||
* (You can do the arithmetic and comparison stuff using conversion
|
* (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
|
* XXX GLUESOME STUFF. FIX IT! -AY '94
|
||||||
*
|
*
|
||||||
@ -45,14 +46,15 @@
|
|||||||
* a bit of the existing code. Need to change the error checking
|
* a bit of the existing code. Need to change the error checking
|
||||||
* for calls to pow(), exp() since on some machines (my Linux box
|
* for calls to pow(), exp() since on some machines (my Linux box
|
||||||
* included) these routines do not set errno. - tgl 97/05/10
|
* included) these routines do not set errno. - tgl 97/05/10
|
||||||
|
*----------
|
||||||
*/
|
*/
|
||||||
|
#include "postgres.h"
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <float.h> /* faked on sunos4 */
|
#include <float.h> /* faked on sunos4 */
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include "postgres.h"
|
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
/* for finite() on Solaris */
|
/* for finite() on Solaris */
|
||||||
#ifdef HAVE_IEEEFP_H
|
#ifdef HAVE_IEEEFP_H
|
||||||
@ -197,7 +199,7 @@ float4in(PG_FUNCTION_ARGS)
|
|||||||
val = strtod(num, &endptr);
|
val = strtod(num, &endptr);
|
||||||
if (*endptr != '\0')
|
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);
|
elog(ERROR, "Bad float4 input format '%s'", num);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -225,6 +227,11 @@ float4out(PG_FUNCTION_ARGS)
|
|||||||
float4 num = PG_GETARG_FLOAT4(0);
|
float4 num = PG_GETARG_FLOAT4(0);
|
||||||
char *ascii = (char *) palloc(MAXFLOATWIDTH + 1);
|
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);
|
sprintf(ascii, "%.*g", FLT_DIG, num);
|
||||||
PG_RETURN_CSTRING(ascii);
|
PG_RETURN_CSTRING(ascii);
|
||||||
}
|
}
|
||||||
@ -536,13 +543,43 @@ float8div(PG_FUNCTION_ARGS)
|
|||||||
/*
|
/*
|
||||||
* float4{eq,ne,lt,le,gt,ge} - float4/float4 comparison operations
|
* 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
|
Datum
|
||||||
float4eq(PG_FUNCTION_ARGS)
|
float4eq(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
float4 arg1 = PG_GETARG_FLOAT4(0);
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
||||||
float4 arg2 = PG_GETARG_FLOAT4(1);
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
||||||
|
|
||||||
PG_RETURN_BOOL(arg1 == arg2);
|
PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -551,7 +588,7 @@ float4ne(PG_FUNCTION_ARGS)
|
|||||||
float4 arg1 = PG_GETARG_FLOAT4(0);
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
||||||
float4 arg2 = PG_GETARG_FLOAT4(1);
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
||||||
|
|
||||||
PG_RETURN_BOOL(arg1 != arg2);
|
PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -560,7 +597,7 @@ float4lt(PG_FUNCTION_ARGS)
|
|||||||
float4 arg1 = PG_GETARG_FLOAT4(0);
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
||||||
float4 arg2 = PG_GETARG_FLOAT4(1);
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
||||||
|
|
||||||
PG_RETURN_BOOL(arg1 < arg2);
|
PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -569,7 +606,7 @@ float4le(PG_FUNCTION_ARGS)
|
|||||||
float4 arg1 = PG_GETARG_FLOAT4(0);
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
||||||
float4 arg2 = PG_GETARG_FLOAT4(1);
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
||||||
|
|
||||||
PG_RETURN_BOOL(arg1 <= arg2);
|
PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) <= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -578,7 +615,7 @@ float4gt(PG_FUNCTION_ARGS)
|
|||||||
float4 arg1 = PG_GETARG_FLOAT4(0);
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
||||||
float4 arg2 = PG_GETARG_FLOAT4(1);
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
||||||
|
|
||||||
PG_RETURN_BOOL(arg1 > arg2);
|
PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -587,19 +624,58 @@ float4ge(PG_FUNCTION_ARGS)
|
|||||||
float4 arg1 = PG_GETARG_FLOAT4(0);
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
||||||
float4 arg2 = PG_GETARG_FLOAT4(1);
|
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
|
* 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
|
Datum
|
||||||
float8eq(PG_FUNCTION_ARGS)
|
float8eq(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
float8 arg1 = PG_GETARG_FLOAT8(0);
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
||||||
float8 arg2 = PG_GETARG_FLOAT8(1);
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
||||||
|
|
||||||
PG_RETURN_BOOL(arg1 == arg2);
|
PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -608,7 +684,7 @@ float8ne(PG_FUNCTION_ARGS)
|
|||||||
float8 arg1 = PG_GETARG_FLOAT8(0);
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
||||||
float8 arg2 = PG_GETARG_FLOAT8(1);
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
||||||
|
|
||||||
PG_RETURN_BOOL(arg1 != arg2);
|
PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -617,7 +693,7 @@ float8lt(PG_FUNCTION_ARGS)
|
|||||||
float8 arg1 = PG_GETARG_FLOAT8(0);
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
||||||
float8 arg2 = PG_GETARG_FLOAT8(1);
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
||||||
|
|
||||||
PG_RETURN_BOOL(arg1 < arg2);
|
PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -626,7 +702,7 @@ float8le(PG_FUNCTION_ARGS)
|
|||||||
float8 arg1 = PG_GETARG_FLOAT8(0);
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
||||||
float8 arg2 = PG_GETARG_FLOAT8(1);
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
||||||
|
|
||||||
PG_RETURN_BOOL(arg1 <= arg2);
|
PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -635,7 +711,7 @@ float8gt(PG_FUNCTION_ARGS)
|
|||||||
float8 arg1 = PG_GETARG_FLOAT8(0);
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
||||||
float8 arg2 = PG_GETARG_FLOAT8(1);
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
||||||
|
|
||||||
PG_RETURN_BOOL(arg1 > arg2);
|
PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -644,7 +720,16 @@ float8ge(PG_FUNCTION_ARGS)
|
|||||||
float8 arg1 = PG_GETARG_FLOAT8(0);
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
||||||
float8 arg2 = PG_GETARG_FLOAT8(1);
|
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);
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
||||||
float8 arg2 = PG_GETARG_FLOAT8(1);
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
||||||
|
|
||||||
PG_RETURN_BOOL(arg1 == arg2);
|
PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -1659,7 +1744,7 @@ float48ne(PG_FUNCTION_ARGS)
|
|||||||
float4 arg1 = PG_GETARG_FLOAT4(0);
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
||||||
float8 arg2 = PG_GETARG_FLOAT8(1);
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
||||||
|
|
||||||
PG_RETURN_BOOL(arg1 != arg2);
|
PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -1668,7 +1753,7 @@ float48lt(PG_FUNCTION_ARGS)
|
|||||||
float4 arg1 = PG_GETARG_FLOAT4(0);
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
||||||
float8 arg2 = PG_GETARG_FLOAT8(1);
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
||||||
|
|
||||||
PG_RETURN_BOOL(arg1 < arg2);
|
PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -1677,7 +1762,7 @@ float48le(PG_FUNCTION_ARGS)
|
|||||||
float4 arg1 = PG_GETARG_FLOAT4(0);
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
||||||
float8 arg2 = PG_GETARG_FLOAT8(1);
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
||||||
|
|
||||||
PG_RETURN_BOOL(arg1 <= arg2);
|
PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -1686,7 +1771,7 @@ float48gt(PG_FUNCTION_ARGS)
|
|||||||
float4 arg1 = PG_GETARG_FLOAT4(0);
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
||||||
float8 arg2 = PG_GETARG_FLOAT8(1);
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
||||||
|
|
||||||
PG_RETURN_BOOL(arg1 > arg2);
|
PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -1695,7 +1780,7 @@ float48ge(PG_FUNCTION_ARGS)
|
|||||||
float4 arg1 = PG_GETARG_FLOAT4(0);
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
||||||
float8 arg2 = PG_GETARG_FLOAT8(1);
|
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);
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
||||||
float4 arg2 = PG_GETARG_FLOAT4(1);
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
||||||
|
|
||||||
PG_RETURN_BOOL(arg1 == arg2);
|
PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -1716,7 +1801,7 @@ float84ne(PG_FUNCTION_ARGS)
|
|||||||
float8 arg1 = PG_GETARG_FLOAT8(0);
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
||||||
float4 arg2 = PG_GETARG_FLOAT4(1);
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
||||||
|
|
||||||
PG_RETURN_BOOL(arg1 != arg2);
|
PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -1725,7 +1810,7 @@ float84lt(PG_FUNCTION_ARGS)
|
|||||||
float8 arg1 = PG_GETARG_FLOAT8(0);
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
||||||
float4 arg2 = PG_GETARG_FLOAT4(1);
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
||||||
|
|
||||||
PG_RETURN_BOOL(arg1 < arg2);
|
PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -1734,7 +1819,7 @@ float84le(PG_FUNCTION_ARGS)
|
|||||||
float8 arg1 = PG_GETARG_FLOAT8(0);
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
||||||
float4 arg2 = PG_GETARG_FLOAT4(1);
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
||||||
|
|
||||||
PG_RETURN_BOOL(arg1 <= arg2);
|
PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -1743,7 +1828,7 @@ float84gt(PG_FUNCTION_ARGS)
|
|||||||
float8 arg1 = PG_GETARG_FLOAT8(0);
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
||||||
float4 arg2 = PG_GETARG_FLOAT4(1);
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
||||||
|
|
||||||
PG_RETURN_BOOL(arg1 > arg2);
|
PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -1752,7 +1837,7 @@ float84ge(PG_FUNCTION_ARGS)
|
|||||||
float8 arg1 = PG_GETARG_FLOAT8(0);
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
||||||
float4 arg2 = PG_GETARG_FLOAT4(1);
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
||||||
|
|
||||||
PG_RETURN_BOOL(arg1 >= arg2);
|
PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========== PRIVATE ROUTINES ========== */
|
/* ========== PRIVATE ROUTINES ========== */
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* 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()
|
/* abstime_finite()
|
||||||
*/
|
*/
|
||||||
Datum
|
Datum
|
||||||
@ -475,27 +444,51 @@ abstime_finite(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* abstimeeq - returns true iff arguments are equal
|
* abstime comparison routines
|
||||||
* 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
|
|
||||||
*/
|
*/
|
||||||
|
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
|
Datum
|
||||||
abstimeeq(PG_FUNCTION_ARGS)
|
abstimeeq(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
|
AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
|
||||||
AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
|
AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
|
||||||
|
|
||||||
if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
|
PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) == 0);
|
||||||
PG_RETURN_BOOL(false);
|
|
||||||
if (t1 == CURRENT_ABSTIME)
|
|
||||||
t1 = GetCurrentTransactionStartTime();
|
|
||||||
if (t2 == CURRENT_ABSTIME)
|
|
||||||
t2 = GetCurrentTransactionStartTime();
|
|
||||||
|
|
||||||
PG_RETURN_BOOL(t1 == t2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -504,14 +497,7 @@ abstimene(PG_FUNCTION_ARGS)
|
|||||||
AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
|
AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
|
||||||
AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
|
AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
|
||||||
|
|
||||||
if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
|
PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) != 0);
|
||||||
PG_RETURN_BOOL(false);
|
|
||||||
if (t1 == CURRENT_ABSTIME)
|
|
||||||
t1 = GetCurrentTransactionStartTime();
|
|
||||||
if (t2 == CURRENT_ABSTIME)
|
|
||||||
t2 = GetCurrentTransactionStartTime();
|
|
||||||
|
|
||||||
PG_RETURN_BOOL(t1 != t2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -520,14 +506,7 @@ abstimelt(PG_FUNCTION_ARGS)
|
|||||||
AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
|
AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
|
||||||
AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
|
AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
|
||||||
|
|
||||||
if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
|
PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) < 0);
|
||||||
PG_RETURN_BOOL(false);
|
|
||||||
if (t1 == CURRENT_ABSTIME)
|
|
||||||
t1 = GetCurrentTransactionStartTime();
|
|
||||||
if (t2 == CURRENT_ABSTIME)
|
|
||||||
t2 = GetCurrentTransactionStartTime();
|
|
||||||
|
|
||||||
PG_RETURN_BOOL(t1 < t2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -536,14 +515,7 @@ abstimegt(PG_FUNCTION_ARGS)
|
|||||||
AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
|
AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
|
||||||
AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
|
AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
|
||||||
|
|
||||||
if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
|
PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) > 0);
|
||||||
PG_RETURN_BOOL(false);
|
|
||||||
if (t1 == CURRENT_ABSTIME)
|
|
||||||
t1 = GetCurrentTransactionStartTime();
|
|
||||||
if (t2 == CURRENT_ABSTIME)
|
|
||||||
t2 = GetCurrentTransactionStartTime();
|
|
||||||
|
|
||||||
PG_RETURN_BOOL(t1 > t2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -552,14 +524,7 @@ abstimele(PG_FUNCTION_ARGS)
|
|||||||
AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
|
AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
|
||||||
AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
|
AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
|
||||||
|
|
||||||
if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
|
PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) <= 0);
|
||||||
PG_RETURN_BOOL(false);
|
|
||||||
if (t1 == CURRENT_ABSTIME)
|
|
||||||
t1 = GetCurrentTransactionStartTime();
|
|
||||||
if (t2 == CURRENT_ABSTIME)
|
|
||||||
t2 = GetCurrentTransactionStartTime();
|
|
||||||
|
|
||||||
PG_RETURN_BOOL(t1 <= t2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -568,14 +533,16 @@ abstimege(PG_FUNCTION_ARGS)
|
|||||||
AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
|
AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
|
||||||
AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
|
AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
|
||||||
|
|
||||||
if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
|
PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) >= 0);
|
||||||
PG_RETURN_BOOL(false);
|
}
|
||||||
if (t1 == CURRENT_ABSTIME)
|
|
||||||
t1 = GetCurrentTransactionStartTime();
|
|
||||||
if (t2 == CURRENT_ABSTIME)
|
|
||||||
t2 = GetCurrentTransactionStartTime();
|
|
||||||
|
|
||||||
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
|
* 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 void apply_typmod(NumericVar *var, int32 typmod);
|
||||||
|
|
||||||
|
static int cmp_numerics(Numeric num1, Numeric num2);
|
||||||
static int cmp_var(NumericVar *var1, NumericVar *var2);
|
static int cmp_var(NumericVar *var1, NumericVar *var2);
|
||||||
static void add_var(NumericVar *var1, NumericVar *var2, NumericVar *result);
|
static void add_var(NumericVar *var1, NumericVar *var2, NumericVar *result);
|
||||||
static void sub_var(NumericVar *var1, NumericVar *var2, NumericVar *result);
|
static void sub_var(NumericVar *var1, NumericVar *var2, NumericVar *result);
|
||||||
@ -664,8 +665,126 @@ numeric_cmp(PG_FUNCTION_ARGS)
|
|||||||
Numeric num2 = PG_GETARG_NUMERIC(1);
|
Numeric num2 = PG_GETARG_NUMERIC(1);
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
|
result = cmp_numerics(num1, num2);
|
||||||
result = 0;
|
|
||||||
|
PG_FREE_IF_COPY(num1, 0);
|
||||||
|
PG_FREE_IF_COPY(num2, 1);
|
||||||
|
|
||||||
|
PG_RETURN_INT32(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Datum
|
||||||
|
numeric_eq(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Numeric num1 = PG_GETARG_NUMERIC(0);
|
||||||
|
Numeric num2 = PG_GETARG_NUMERIC(1);
|
||||||
|
bool result;
|
||||||
|
|
||||||
|
result = cmp_numerics(num1, num2) == 0;
|
||||||
|
|
||||||
|
PG_FREE_IF_COPY(num1, 0);
|
||||||
|
PG_FREE_IF_COPY(num2, 1);
|
||||||
|
|
||||||
|
PG_RETURN_BOOL(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
Datum
|
||||||
|
numeric_ne(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Numeric num1 = PG_GETARG_NUMERIC(0);
|
||||||
|
Numeric num2 = PG_GETARG_NUMERIC(1);
|
||||||
|
bool result;
|
||||||
|
|
||||||
|
result = cmp_numerics(num1, num2) != 0;
|
||||||
|
|
||||||
|
PG_FREE_IF_COPY(num1, 0);
|
||||||
|
PG_FREE_IF_COPY(num2, 1);
|
||||||
|
|
||||||
|
PG_RETURN_BOOL(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
Datum
|
||||||
|
numeric_gt(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Numeric num1 = PG_GETARG_NUMERIC(0);
|
||||||
|
Numeric num2 = PG_GETARG_NUMERIC(1);
|
||||||
|
bool result;
|
||||||
|
|
||||||
|
result = cmp_numerics(num1, num2) > 0;
|
||||||
|
|
||||||
|
PG_FREE_IF_COPY(num1, 0);
|
||||||
|
PG_FREE_IF_COPY(num2, 1);
|
||||||
|
|
||||||
|
PG_RETURN_BOOL(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
Datum
|
||||||
|
numeric_ge(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Numeric num1 = PG_GETARG_NUMERIC(0);
|
||||||
|
Numeric num2 = PG_GETARG_NUMERIC(1);
|
||||||
|
bool result;
|
||||||
|
|
||||||
|
result = cmp_numerics(num1, num2) >= 0;
|
||||||
|
|
||||||
|
PG_FREE_IF_COPY(num1, 0);
|
||||||
|
PG_FREE_IF_COPY(num2, 1);
|
||||||
|
|
||||||
|
PG_RETURN_BOOL(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
Datum
|
||||||
|
numeric_lt(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Numeric num1 = PG_GETARG_NUMERIC(0);
|
||||||
|
Numeric num2 = PG_GETARG_NUMERIC(1);
|
||||||
|
bool result;
|
||||||
|
|
||||||
|
result = cmp_numerics(num1, num2) < 0;
|
||||||
|
|
||||||
|
PG_FREE_IF_COPY(num1, 0);
|
||||||
|
PG_FREE_IF_COPY(num2, 1);
|
||||||
|
|
||||||
|
PG_RETURN_BOOL(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
Datum
|
||||||
|
numeric_le(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Numeric num1 = PG_GETARG_NUMERIC(0);
|
||||||
|
Numeric num2 = PG_GETARG_NUMERIC(1);
|
||||||
|
bool result;
|
||||||
|
|
||||||
|
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
|
else
|
||||||
{
|
{
|
||||||
NumericVar arg1;
|
NumericVar arg1;
|
||||||
@ -683,203 +802,7 @@ numeric_cmp(PG_FUNCTION_ARGS)
|
|||||||
free_var(&arg2);
|
free_var(&arg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
PG_FREE_IF_COPY(num1, 0);
|
return result;
|
||||||
PG_FREE_IF_COPY(num2, 1);
|
|
||||||
|
|
||||||
PG_RETURN_INT32(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Datum
|
|
||||||
numeric_eq(PG_FUNCTION_ARGS)
|
|
||||||
{
|
|
||||||
Numeric num1 = PG_GETARG_NUMERIC(0);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
PG_FREE_IF_COPY(num1, 0);
|
|
||||||
PG_FREE_IF_COPY(num2, 1);
|
|
||||||
|
|
||||||
PG_RETURN_BOOL(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
Datum
|
|
||||||
numeric_ne(PG_FUNCTION_ARGS)
|
|
||||||
{
|
|
||||||
Numeric num1 = PG_GETARG_NUMERIC(0);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
PG_FREE_IF_COPY(num1, 0);
|
|
||||||
PG_FREE_IF_COPY(num2, 1);
|
|
||||||
|
|
||||||
PG_RETURN_BOOL(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
Datum
|
|
||||||
numeric_gt(PG_FUNCTION_ARGS)
|
|
||||||
{
|
|
||||||
Numeric num1 = PG_GETARG_NUMERIC(0);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
PG_FREE_IF_COPY(num1, 0);
|
|
||||||
PG_FREE_IF_COPY(num2, 1);
|
|
||||||
|
|
||||||
PG_RETURN_BOOL(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
Datum
|
|
||||||
numeric_ge(PG_FUNCTION_ARGS)
|
|
||||||
{
|
|
||||||
Numeric num1 = PG_GETARG_NUMERIC(0);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
PG_FREE_IF_COPY(num1, 0);
|
|
||||||
PG_FREE_IF_COPY(num2, 1);
|
|
||||||
|
|
||||||
PG_RETURN_BOOL(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
Datum
|
|
||||||
numeric_lt(PG_FUNCTION_ARGS)
|
|
||||||
{
|
|
||||||
Numeric num1 = PG_GETARG_NUMERIC(0);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
PG_FREE_IF_COPY(num1, 0);
|
|
||||||
PG_FREE_IF_COPY(num2, 1);
|
|
||||||
|
|
||||||
PG_RETURN_BOOL(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
Datum
|
|
||||||
numeric_le(PG_FUNCTION_ARGS)
|
|
||||||
{
|
|
||||||
Numeric num1 = PG_GETARG_NUMERIC(0);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
PG_FREE_IF_COPY(num1, 0);
|
|
||||||
PG_FREE_IF_COPY(num2, 1);
|
|
||||||
|
|
||||||
PG_RETURN_BOOL(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1663,6 +1586,7 @@ numeric_int2(PG_FUNCTION_ARGS)
|
|||||||
char *str;
|
char *str;
|
||||||
Datum result;
|
Datum result;
|
||||||
|
|
||||||
|
/* XXX would it be better to return NULL? */
|
||||||
if (NUMERIC_IS_NAN(num))
|
if (NUMERIC_IS_NAN(num))
|
||||||
elog(ERROR, "Cannot convert NaN to int2");
|
elog(ERROR, "Cannot convert NaN to int2");
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* 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
|
Datum
|
||||||
timestamp_eq(PG_FUNCTION_ARGS)
|
timestamp_eq(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
||||||
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
||||||
|
|
||||||
if (TIMESTAMP_IS_INVALID(dt1) || TIMESTAMP_IS_INVALID(dt2))
|
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -566,15 +578,7 @@ timestamp_ne(PG_FUNCTION_ARGS)
|
|||||||
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
||||||
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
||||||
|
|
||||||
if (TIMESTAMP_IS_INVALID(dt1) || TIMESTAMP_IS_INVALID(dt2))
|
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -583,15 +587,7 @@ timestamp_lt(PG_FUNCTION_ARGS)
|
|||||||
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
||||||
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
||||||
|
|
||||||
if (TIMESTAMP_IS_INVALID(dt1) || TIMESTAMP_IS_INVALID(dt2))
|
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -600,15 +596,7 @@ timestamp_gt(PG_FUNCTION_ARGS)
|
|||||||
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
||||||
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
||||||
|
|
||||||
if (TIMESTAMP_IS_INVALID(dt1) || TIMESTAMP_IS_INVALID(dt2))
|
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -617,15 +605,7 @@ timestamp_le(PG_FUNCTION_ARGS)
|
|||||||
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
||||||
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
||||||
|
|
||||||
if (TIMESTAMP_IS_INVALID(dt1) || TIMESTAMP_IS_INVALID(dt2))
|
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -634,57 +614,54 @@ timestamp_ge(PG_FUNCTION_ARGS)
|
|||||||
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
||||||
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
||||||
|
|
||||||
if (TIMESTAMP_IS_INVALID(dt1) || TIMESTAMP_IS_INVALID(dt2))
|
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* timestamp_cmp - 3-state comparison for timestamp
|
|
||||||
* collate invalid timestamp at the end
|
|
||||||
*/
|
|
||||||
Datum
|
Datum
|
||||||
timestamp_cmp(PG_FUNCTION_ARGS)
|
timestamp_cmp(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
|
||||||
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
|
||||||
|
|
||||||
if (TIMESTAMP_IS_INVALID(dt1))
|
PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* interval_relop - is interval1 relop interval2
|
* 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
|
Datum
|
||||||
interval_eq(PG_FUNCTION_ARGS)
|
interval_eq(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
|
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
|
||||||
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
|
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
|
||||||
|
|
||||||
if (INTERVAL_IS_INVALID(*interval1) || INTERVAL_IS_INVALID(*interval2))
|
PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) == 0);
|
||||||
PG_RETURN_BOOL(false);
|
|
||||||
|
|
||||||
PG_RETURN_BOOL((interval1->time == interval2->time) &&
|
|
||||||
(interval1->month == interval2->month));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -693,11 +670,7 @@ interval_ne(PG_FUNCTION_ARGS)
|
|||||||
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
|
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
|
||||||
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
|
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
|
||||||
|
|
||||||
if (INTERVAL_IS_INVALID(*interval1) || INTERVAL_IS_INVALID(*interval2))
|
PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) != 0);
|
||||||
PG_RETURN_BOOL(false);
|
|
||||||
|
|
||||||
PG_RETURN_BOOL((interval1->time != interval2->time) ||
|
|
||||||
(interval1->month != interval2->month));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -705,20 +678,8 @@ interval_lt(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
|
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
|
||||||
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
|
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
|
||||||
double span1,
|
|
||||||
span2;
|
|
||||||
|
|
||||||
if (INTERVAL_IS_INVALID(*interval1) || INTERVAL_IS_INVALID(*interval2))
|
PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) < 0);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -726,20 +687,8 @@ interval_gt(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
|
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
|
||||||
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
|
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
|
||||||
double span1,
|
|
||||||
span2;
|
|
||||||
|
|
||||||
if (INTERVAL_IS_INVALID(*interval1) || INTERVAL_IS_INVALID(*interval2))
|
PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) > 0);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -747,20 +696,8 @@ interval_le(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
|
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
|
||||||
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
|
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
|
||||||
double span1,
|
|
||||||
span2;
|
|
||||||
|
|
||||||
if (INTERVAL_IS_INVALID(*interval1) || INTERVAL_IS_INVALID(*interval2))
|
PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) <= 0);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -768,46 +705,17 @@ interval_ge(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
|
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
|
||||||
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
|
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
|
||||||
double span1,
|
|
||||||
span2;
|
|
||||||
|
|
||||||
if (INTERVAL_IS_INVALID(*interval1) || INTERVAL_IS_INVALID(*interval2))
|
PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) >= 0);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* interval_cmp - 3-state comparison for interval
|
|
||||||
*/
|
|
||||||
Datum
|
Datum
|
||||||
interval_cmp(PG_FUNCTION_ARGS)
|
interval_cmp(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
|
Interval *interval1 = PG_GETARG_INTERVAL_P(0);
|
||||||
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
|
Interval *interval2 = PG_GETARG_INTERVAL_P(1);
|
||||||
double span1,
|
|
||||||
span2;
|
|
||||||
|
|
||||||
if (INTERVAL_IS_INVALID(*interval1))
|
PG_RETURN_INT32(interval_cmp_internal(interval1, interval2));
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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,56 +537,6 @@ _varbit(PG_FUNCTION_ARGS)
|
|||||||
* need to be so careful.
|
* need to be so careful.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Datum
|
|
||||||
biteq(PG_FUNCTION_ARGS)
|
|
||||||
{
|
|
||||||
VarBit *arg1 = PG_GETARG_VARBIT_P(0);
|
|
||||||
VarBit *arg2 = PG_GETARG_VARBIT_P(1);
|
|
||||||
bool result;
|
|
||||||
int bitlen1,
|
|
||||||
bitlen2;
|
|
||||||
|
|
||||||
bitlen1 = VARBITLEN(arg1);
|
|
||||||
bitlen2 = VARBITLEN(arg2);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
PG_FREE_IF_COPY(arg1, 0);
|
|
||||||
PG_FREE_IF_COPY(arg2, 1);
|
|
||||||
|
|
||||||
PG_RETURN_BOOL(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
Datum
|
|
||||||
bitne(PG_FUNCTION_ARGS)
|
|
||||||
{
|
|
||||||
VarBit *arg1 = PG_GETARG_VARBIT_P(0);
|
|
||||||
VarBit *arg2 = PG_GETARG_VARBIT_P(1);
|
|
||||||
bool result;
|
|
||||||
int bitlen1,
|
|
||||||
bitlen2;
|
|
||||||
|
|
||||||
bitlen1 = VARBITLEN(arg1);
|
|
||||||
bitlen2 = VARBITLEN(arg2);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
PG_FREE_IF_COPY(arg1, 0);
|
|
||||||
PG_FREE_IF_COPY(arg2, 1);
|
|
||||||
|
|
||||||
PG_RETURN_BOOL(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* bit_cmp
|
/* bit_cmp
|
||||||
*
|
*
|
||||||
* Compares two bitstrings and returns <0, 0, >0 depending on whether the first
|
* Compares two bitstrings and returns <0, 0, >0 depending on whether the first
|
||||||
@ -617,6 +567,54 @@ bit_cmp(VarBit *arg1, VarBit *arg2)
|
|||||||
return cmp;
|
return cmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Datum
|
||||||
|
biteq(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
VarBit *arg1 = PG_GETARG_VARBIT_P(0);
|
||||||
|
VarBit *arg2 = PG_GETARG_VARBIT_P(1);
|
||||||
|
bool result;
|
||||||
|
int bitlen1,
|
||||||
|
bitlen2;
|
||||||
|
|
||||||
|
bitlen1 = VARBITLEN(arg1);
|
||||||
|
bitlen2 = VARBITLEN(arg2);
|
||||||
|
|
||||||
|
/* fast path for different-length inputs */
|
||||||
|
if (bitlen1 != bitlen2)
|
||||||
|
result = false;
|
||||||
|
else
|
||||||
|
result = (bit_cmp(arg1, arg2) == 0);
|
||||||
|
|
||||||
|
PG_FREE_IF_COPY(arg1, 0);
|
||||||
|
PG_FREE_IF_COPY(arg2, 1);
|
||||||
|
|
||||||
|
PG_RETURN_BOOL(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
Datum
|
||||||
|
bitne(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
VarBit *arg1 = PG_GETARG_VARBIT_P(0);
|
||||||
|
VarBit *arg2 = PG_GETARG_VARBIT_P(1);
|
||||||
|
bool result;
|
||||||
|
int bitlen1,
|
||||||
|
bitlen2;
|
||||||
|
|
||||||
|
bitlen1 = VARBITLEN(arg1);
|
||||||
|
bitlen2 = VARBITLEN(arg2);
|
||||||
|
|
||||||
|
/* fast path for different-length inputs */
|
||||||
|
if (bitlen1 != bitlen2)
|
||||||
|
result = true;
|
||||||
|
else
|
||||||
|
result = (bit_cmp(arg1, arg2) != 0);
|
||||||
|
|
||||||
|
PG_FREE_IF_COPY(arg1, 0);
|
||||||
|
PG_FREE_IF_COPY(arg2, 1);
|
||||||
|
|
||||||
|
PG_RETURN_BOOL(result);
|
||||||
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
bitlt(PG_FUNCTION_ARGS)
|
bitlt(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
@ -8,11 +8,10 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 "postgres.h"
|
||||||
|
|
||||||
#include "access/hash.h"
|
#include "access/hash.h"
|
||||||
@ -526,10 +525,11 @@ bpchareq(PG_FUNCTION_ARGS)
|
|||||||
len1 = bcTruelen(arg1);
|
len1 = bcTruelen(arg1);
|
||||||
len2 = bcTruelen(arg2);
|
len2 = bcTruelen(arg2);
|
||||||
|
|
||||||
|
/* fast path for different-length inputs */
|
||||||
if (len1 != len2)
|
if (len1 != len2)
|
||||||
result = false;
|
result = false;
|
||||||
else
|
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(arg1, 0);
|
||||||
PG_FREE_IF_COPY(arg2, 1);
|
PG_FREE_IF_COPY(arg2, 1);
|
||||||
@ -549,10 +549,11 @@ bpcharne(PG_FUNCTION_ARGS)
|
|||||||
len1 = bcTruelen(arg1);
|
len1 = bcTruelen(arg1);
|
||||||
len2 = bcTruelen(arg2);
|
len2 = bcTruelen(arg2);
|
||||||
|
|
||||||
|
/* fast path for different-length inputs */
|
||||||
if (len1 != len2)
|
if (len1 != len2)
|
||||||
result = true;
|
result = true;
|
||||||
else
|
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(arg1, 0);
|
||||||
PG_FREE_IF_COPY(arg2, 1);
|
PG_FREE_IF_COPY(arg2, 1);
|
||||||
@ -745,10 +746,11 @@ varchareq(PG_FUNCTION_ARGS)
|
|||||||
len1 = VARSIZE(arg1) - VARHDRSZ;
|
len1 = VARSIZE(arg1) - VARHDRSZ;
|
||||||
len2 = VARSIZE(arg2) - VARHDRSZ;
|
len2 = VARSIZE(arg2) - VARHDRSZ;
|
||||||
|
|
||||||
|
/* fast path for different-length inputs */
|
||||||
if (len1 != len2)
|
if (len1 != len2)
|
||||||
result = false;
|
result = false;
|
||||||
else
|
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(arg1, 0);
|
||||||
PG_FREE_IF_COPY(arg2, 1);
|
PG_FREE_IF_COPY(arg2, 1);
|
||||||
@ -768,10 +770,11 @@ varcharne(PG_FUNCTION_ARGS)
|
|||||||
len1 = VARSIZE(arg1) - VARHDRSZ;
|
len1 = VARSIZE(arg1) - VARHDRSZ;
|
||||||
len2 = VARSIZE(arg2) - VARHDRSZ;
|
len2 = VARSIZE(arg2) - VARHDRSZ;
|
||||||
|
|
||||||
|
/* fast path for different-length inputs */
|
||||||
if (len1 != len2)
|
if (len1 != len2)
|
||||||
result = true;
|
result = true;
|
||||||
else
|
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(arg1, 0);
|
||||||
PG_FREE_IF_COPY(arg2, 1);
|
PG_FREE_IF_COPY(arg2, 1);
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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);
|
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()
|
/* varstr_cmp()
|
||||||
* Comparison function for text strings with given lengths.
|
* Comparison function for text strings with given lengths.
|
||||||
* Includes locale support, but must copy strings to temporary memory
|
* 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;
|
*a2p;
|
||||||
|
|
||||||
#ifdef USE_LOCALE
|
#ifdef USE_LOCALE
|
||||||
a1p = (unsigned char *) palloc(len1 + 1);
|
a1p = (char *) palloc(len1 + 1);
|
||||||
a2p = (unsigned char *) palloc(len2 + 1);
|
a2p = (char *) palloc(len2 + 1);
|
||||||
|
|
||||||
memcpy(a1p, arg1, len1);
|
memcpy(a1p, arg1, len1);
|
||||||
*(a1p + len1) = '\0';
|
*(a1p + len1) = '\0';
|
||||||
@ -548,11 +482,7 @@ varstr_cmp(char *arg1, int len1, char *arg2, int len2)
|
|||||||
|
|
||||||
|
|
||||||
/* text_cmp()
|
/* text_cmp()
|
||||||
* Comparison function for text strings.
|
* Internal 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
|
|
||||||
* Returns -1, 0 or 1
|
* Returns -1, 0 or 1
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
@ -580,6 +510,44 @@ text_cmp(text *arg1, text *arg2)
|
|||||||
* need to be so careful.
|
* 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
|
Datum
|
||||||
text_lt(PG_FUNCTION_ARGS)
|
text_lt(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
@ -640,6 +608,22 @@ text_ge(PG_FUNCTION_ARGS)
|
|||||||
PG_RETURN_BOOL(result);
|
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
|
Datum
|
||||||
text_larger(PG_FUNCTION_ARGS)
|
text_larger(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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 */
|
/* non-fmgr-callable support routines */
|
||||||
extern AbsoluteTime GetCurrentAbsoluteTime(void);
|
extern AbsoluteTime GetCurrentAbsoluteTime(void);
|
||||||
extern bool AbsoluteTimeIsBefore(AbsoluteTime time1, AbsoluteTime time2);
|
|
||||||
extern void abstime2tm(AbsoluteTime time, int *tzp, struct tm * tm, char *tzn);
|
extern void abstime2tm(AbsoluteTime time, int *tzp, struct tm * tm, char *tzn);
|
||||||
|
|
||||||
#endif /* NABSTIME_H */
|
#endif /* NABSTIME_H */
|
||||||
|
@ -62,7 +62,8 @@ SELECT '' AS six, ABSTIME_TBL.*
|
|||||||
| current
|
| current
|
||||||
| infinity
|
| infinity
|
||||||
| Sat May 10 23:59:12 1947 PDT
|
| Sat May 10 23:59:12 1947 PDT
|
||||||
(6 rows)
|
| invalid
|
||||||
|
(7 rows)
|
||||||
|
|
||||||
SELECT '' AS six, ABSTIME_TBL.*
|
SELECT '' AS six, ABSTIME_TBL.*
|
||||||
WHERE abstime 'May 10, 1947 23:59:12' <> ABSTIME_TBL.f1;
|
WHERE abstime 'May 10, 1947 23:59:12' <> ABSTIME_TBL.f1;
|
||||||
@ -74,7 +75,8 @@ SELECT '' AS six, ABSTIME_TBL.*
|
|||||||
| current
|
| current
|
||||||
| infinity
|
| infinity
|
||||||
| -infinity
|
| -infinity
|
||||||
(6 rows)
|
| invalid
|
||||||
|
(7 rows)
|
||||||
|
|
||||||
SELECT '' AS one, ABSTIME_TBL.*
|
SELECT '' AS one, ABSTIME_TBL.*
|
||||||
WHERE abstime 'current' = ABSTIME_TBL.f1;
|
WHERE abstime 'current' = ABSTIME_TBL.f1;
|
||||||
|
@ -62,7 +62,8 @@ SELECT '' AS six, ABSTIME_TBL.*
|
|||||||
| current
|
| current
|
||||||
| infinity
|
| infinity
|
||||||
| Sat May 10 23:59:12 1947 PST
|
| Sat May 10 23:59:12 1947 PST
|
||||||
(6 rows)
|
| invalid
|
||||||
|
(7 rows)
|
||||||
|
|
||||||
SELECT '' AS six, ABSTIME_TBL.*
|
SELECT '' AS six, ABSTIME_TBL.*
|
||||||
WHERE abstime 'May 10, 1947 23:59:12' <> ABSTIME_TBL.f1;
|
WHERE abstime 'May 10, 1947 23:59:12' <> ABSTIME_TBL.f1;
|
||||||
@ -74,7 +75,8 @@ SELECT '' AS six, ABSTIME_TBL.*
|
|||||||
| current
|
| current
|
||||||
| infinity
|
| infinity
|
||||||
| -infinity
|
| -infinity
|
||||||
(6 rows)
|
| invalid
|
||||||
|
(7 rows)
|
||||||
|
|
||||||
SELECT '' AS one, ABSTIME_TBL.*
|
SELECT '' AS one, ABSTIME_TBL.*
|
||||||
WHERE abstime 'current' = ABSTIME_TBL.f1;
|
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';
|
WHERE d1 > timestamp '1997-01-02' and d1 != timestamp 'current';
|
||||||
47 | d1
|
47 | d1
|
||||||
----+---------------------------------
|
----+---------------------------------
|
||||||
|
| invalid
|
||||||
| infinity
|
| infinity
|
||||||
| Mon Feb 10 17:32:01 1997 PST
|
| Mon Feb 10 17:32:01 1997 PST
|
||||||
|
| invalid
|
||||||
|
| invalid
|
||||||
| Mon Feb 10 17:32:01.00 1997 PST
|
| Mon Feb 10 17:32:01.00 1997 PST
|
||||||
| Mon Feb 10 17:32:02.00 1997 PST
|
| Mon Feb 10 17:32:02.00 1997 PST
|
||||||
| Mon Feb 10 17:32:01.40 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
|
| Sat Jan 01 17:32:01 2000 PST
|
||||||
| Sun Dec 31 17:32:01 2000 PST
|
| Sun Dec 31 17:32:01 2000 PST
|
||||||
| Mon Jan 01 17:32:01 2001 PST
|
| Mon Jan 01 17:32:01 2001 PST
|
||||||
(47 rows)
|
(50 rows)
|
||||||
|
|
||||||
SELECT '' AS "15", d1 FROM TIMESTAMP_TBL
|
SELECT '' AS "15", d1 FROM TIMESTAMP_TBL
|
||||||
WHERE d1 < timestamp '1997-01-02' and d1 != timestamp 'current';
|
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';
|
WHERE d1 != timestamp '1997-01-02' and d1 != timestamp 'current';
|
||||||
62 | d1
|
62 | d1
|
||||||
----+---------------------------------
|
----+---------------------------------
|
||||||
|
| invalid
|
||||||
| -infinity
|
| -infinity
|
||||||
| infinity
|
| infinity
|
||||||
| epoch
|
| epoch
|
||||||
| Mon Feb 10 17:32:01 1997 PST
|
| Mon Feb 10 17:32:01 1997 PST
|
||||||
|
| invalid
|
||||||
|
| invalid
|
||||||
| Mon Feb 10 17:32:01.00 1997 PST
|
| Mon Feb 10 17:32:01.00 1997 PST
|
||||||
| Mon Feb 10 17:32:02.00 1997 PST
|
| Mon Feb 10 17:32:02.00 1997 PST
|
||||||
| Mon Feb 10 17:32:01.40 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
|
| Sat Jan 01 17:32:01 2000 PST
|
||||||
| Sun Dec 31 17:32:01 2000 PST
|
| Sun Dec 31 17:32:01 2000 PST
|
||||||
| Mon Jan 01 17:32:01 2001 PST
|
| Mon Jan 01 17:32:01 2001 PST
|
||||||
(62 rows)
|
(65 rows)
|
||||||
|
|
||||||
SELECT '' AS "16", d1 FROM TIMESTAMP_TBL
|
SELECT '' AS "16", d1 FROM TIMESTAMP_TBL
|
||||||
WHERE d1 <= timestamp '1997-01-02' and d1 != timestamp 'current';
|
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';
|
WHERE d1 >= timestamp '1997-01-02' and d1 != timestamp 'current';
|
||||||
48 | d1
|
48 | d1
|
||||||
----+---------------------------------
|
----+---------------------------------
|
||||||
|
| invalid
|
||||||
| infinity
|
| infinity
|
||||||
| Mon Feb 10 17:32:01 1997 PST
|
| Mon Feb 10 17:32:01 1997 PST
|
||||||
|
| invalid
|
||||||
|
| invalid
|
||||||
| Mon Feb 10 17:32:01.00 1997 PST
|
| Mon Feb 10 17:32:01.00 1997 PST
|
||||||
| Mon Feb 10 17:32:02.00 1997 PST
|
| Mon Feb 10 17:32:02.00 1997 PST
|
||||||
| Mon Feb 10 17:32:01.40 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
|
| Sat Jan 01 17:32:01 2000 PST
|
||||||
| Sun Dec 31 17:32:01 2000 PST
|
| Sun Dec 31 17:32:01 2000 PST
|
||||||
| Mon Jan 01 17:32:01 2001 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;
|
SELECT '' AS "66", d1 + interval '1 year' AS one_year FROM TIMESTAMP_TBL;
|
||||||
66 | one_year
|
66 | one_year
|
||||||
|
Reference in New Issue
Block a user