1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-31 22:04:40 +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:
Tom Lane
2001-05-03 19:00:37 +00:00
parent 77fe28f33e
commit 2792374cff
13 changed files with 536 additions and 747 deletions

View File

@ -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));
}
/*