Skip to content

Commit

Permalink
Merge pull request #9994 from hawkfish/interval-equals
Browse files Browse the repository at this point in the history
Internal #898: Totally Ordered Intervals
  • Loading branch information
Mytherin committed Dec 14, 2023
2 parents 0f38b47 + b1a943f commit d51e1b0
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 37 deletions.
4 changes: 3 additions & 1 deletion src/common/types/hash.cpp
Expand Up @@ -54,7 +54,9 @@ hash_t Hash(double val) {

template <>
hash_t Hash(interval_t val) {
return Hash(val.days) ^ Hash(val.months) ^ Hash(val.micros);
int64_t months, days, micros;
val.Normalize(months, days, micros);
return Hash(days) ^ Hash(months) ^ Hash(micros);
}

template <>
Expand Down
4 changes: 3 additions & 1 deletion src/core_functions/aggregate/holistic/mode.cpp
Expand Up @@ -16,7 +16,9 @@ namespace std {
template <>
struct hash<duckdb::interval_t> {
inline size_t operator()(const duckdb::interval_t &val) const {
return hash<int32_t> {}(val.days) ^ hash<int32_t> {}(val.months) ^ hash<int64_t> {}(val.micros);
int64_t months, days, micros;
val.Normalize(months, days, micros);
return hash<int32_t> {}(days) ^ hash<int32_t> {}(months) ^ hash<int64_t> {}(micros);
}
};

Expand Down
4 changes: 0 additions & 4 deletions src/include/duckdb/common/operator/comparison_operators.hpp
Expand Up @@ -210,10 +210,6 @@ inline bool GreaterThan::Operation(const interval_t &left, const interval_t &rig
return Interval::GreaterThan(left, right);
}

inline bool operator<(const interval_t &lhs, const interval_t &rhs) {
return LessThan::Operation(lhs, rhs);
}

//===--------------------------------------------------------------------===//
// Specialized Hugeint Comparison Operators
//===--------------------------------------------------------------------===//
Expand Down
84 changes: 55 additions & 29 deletions src/include/duckdb/common/types/interval.hpp
Expand Up @@ -19,13 +19,57 @@ struct timestamp_t;
class Serializer;
class Deserializer;

struct interval_t {
struct interval_t { // NOLINT
int32_t months;
int32_t days;
int64_t micros;

inline bool operator==(const interval_t &rhs) const {
return this->days == rhs.days && this->months == rhs.months && this->micros == rhs.micros;
inline void Normalize(int64_t &months, int64_t &days, int64_t &micros) const;
inline bool operator==(const interval_t &right) const {
// Quick equality check
const auto &left = *this;
if (left.months == right.months && left.days == right.days && left.micros == right.micros) {
return true;
}

int64_t lmonths, ldays, lmicros;
int64_t rmonths, rdays, rmicros;
left.Normalize(lmonths, ldays, lmicros);
right.Normalize(rmonths, rdays, rmicros);

return lmonths == rmonths && ldays == rdays && lmicros == rmicros;
}

inline bool operator>(const interval_t &right) const {
const auto &left = *this;
int64_t lmonths, ldays, lmicros;
int64_t rmonths, rdays, rmicros;
left.Normalize(lmonths, ldays, lmicros);
right.Normalize(rmonths, rdays, rmicros);

if (lmonths > rmonths) {
return true;
} else if (lmonths < rmonths) {
return false;
}
if (ldays > rdays) {
return true;
} else if (ldays < rdays) {
return false;
}
return lmicros > rmicros;
}

inline bool operator<(const interval_t &right) const {
return right > *this;
}

inline bool operator<=(const interval_t &right) const {
return !(*this > right);
}

inline bool operator>=(const interval_t &right) const {
return !(*this < right);
}

// Serialization
Expand Down Expand Up @@ -108,10 +152,15 @@ class Interval {
static dtime_t Add(dtime_t left, interval_t right, date_t &date);

//! Comparison operators
inline static bool Equals(const interval_t &left, const interval_t &right);
inline static bool GreaterThan(const interval_t &left, const interval_t &right);
inline static bool Equals(const interval_t &left, const interval_t &right) {
return left == right;
}
inline static bool GreaterThan(const interval_t &left, const interval_t &right) {
return left > right;
}
};
static void NormalizeIntervalEntries(interval_t input, int64_t &months, int64_t &days, int64_t &micros) {
void interval_t::Normalize(int64_t &months, int64_t &days, int64_t &micros) const {
auto input = *this;
int64_t extra_months_d = input.days / Interval::DAYS_PER_MONTH;
int64_t extra_months_micros = input.micros / Interval::MICROS_PER_MONTH;
input.days -= extra_months_d * Interval::DAYS_PER_MONTH;
Expand All @@ -125,27 +174,4 @@ static void NormalizeIntervalEntries(interval_t input, int64_t &months, int64_t
micros = input.micros;
}

bool Interval::Equals(const interval_t &left, const interval_t &right) {
return left.months == right.months && left.days == right.days && left.micros == right.micros;
}

bool Interval::GreaterThan(const interval_t &left, const interval_t &right) {
int64_t lmonths, ldays, lmicros;
int64_t rmonths, rdays, rmicros;
NormalizeIntervalEntries(left, lmonths, ldays, lmicros);
NormalizeIntervalEntries(right, rmonths, rdays, rmicros);

if (lmonths > rmonths) {
return true;
} else if (lmonths < rmonths) {
return false;
}
if (ldays > rdays) {
return true;
} else if (ldays < rdays) {
return false;
}
return lmicros > rmicros;
}

} // namespace duckdb
4 changes: 2 additions & 2 deletions test/sql/types/interval/test_interval_comparison.test
Expand Up @@ -5,7 +5,7 @@
statement ok
PRAGMA enable_verification

# 30 days = 1 month for ordering purposes, but NOT for equality purposes
# 30 days = 1 month for ordering purposes
query T
SELECT INTERVAL '30' DAY > INTERVAL '1' MONTH
----
Expand All @@ -14,7 +14,7 @@ SELECT INTERVAL '30' DAY > INTERVAL '1' MONTH
query T
SELECT INTERVAL '30' DAY = INTERVAL '1' MONTH
----
0
1

query T
SELECT INTERVAL '30' DAY >= INTERVAL '1' MONTH
Expand Down

0 comments on commit d51e1b0

Please sign in to comment.