diff --git a/c++/include/orc/Statistics.hh b/c++/include/orc/Statistics.hh index 1d4b0b6558..c7b078147b 100644 --- a/c++/include/orc/Statistics.hh +++ b/c++/include/orc/Statistics.hh @@ -305,26 +305,26 @@ namespace orc { virtual ~TimestampColumnStatistics(); /** - * Check whether column minimum. + * Check whether minimum timestamp exists. * @return true if has minimum */ virtual bool hasMinimum() const = 0; /** - * Check whether column maximum. + * Check whether maximum timestamp exists. * @return true if has maximum */ virtual bool hasMaximum() const = 0; /** - * Get the minimum value for the column. - * @return minimum value + * Get the millisecond of minimum timestamp in UTC. + * @return minimum value in millisecond */ virtual int64_t getMinimum() const = 0; /** - * Get the maximum value for the column. - * @return maximum value + * Get the millisecond of maximum timestamp in UTC. + * @return maximum value in millisecond */ virtual int64_t getMaximum() const = 0; @@ -352,7 +352,17 @@ namespace orc { */ virtual int64_t getUpperBound() const = 0; + /** + * Get the last 6 digits of nanosecond of minimum timestamp. + * @return last 6 digits of nanosecond of minimum timestamp. + */ + virtual int32_t getMinimumNanos() const = 0; + /** + * Get the last 6 digits of nanosecond of maximum timestamp. + * @return last 6 digits of nanosecond of maximum timestamp. + */ + virtual int32_t getMaximumNanos() const = 0; }; class Statistics { diff --git a/c++/include/orc/sargs/Literal.hh b/c++/include/orc/sargs/Literal.hh index c72ea9d2a0..36c9b37e3f 100644 --- a/c++/include/orc/sargs/Literal.hh +++ b/c++/include/orc/sargs/Literal.hh @@ -36,6 +36,33 @@ namespace orc { */ class Literal { public: + struct Timestamp { + Timestamp() = default; + Timestamp(const Timestamp&) = default; + Timestamp(Timestamp&&) = default; + ~Timestamp() = default; + Timestamp(int64_t second_, int32_t nanos_): second(second_), nanos(nanos_) { + // PASS + } + Timestamp& operator=(const Timestamp&) = default; + Timestamp& operator=(Timestamp&&) = default; + bool operator==(const Timestamp& r) const { + return second == r.second && nanos == r.nanos; + } + bool operator<(const Timestamp& r) const { + return second < r.second || (second == r.second && nanos < r.nanos); + } + bool operator<=(const Timestamp& r) const { + return second < r.second || (second == r.second && nanos <= r.nanos); + } + bool operator!=(const Timestamp& r) const { return !(*this == r); } + bool operator>(const Timestamp& r) const { return r < *this; } + bool operator>=(const Timestamp& r) const { return r <= *this; } + int64_t getMillis() const { return second * 1000 + nanos / 1000000; } + int64_t second; + int32_t nanos; + }; + Literal(const Literal &r); ~Literal(); Literal& operator=(const Literal& r); @@ -63,10 +90,15 @@ namespace orc { Literal(bool val); /** - * Create a literal of Timestamp or DATE type + * Create a literal of DATE type */ Literal(PredicateDataType type, int64_t val); + /** + * Create a literal of TIMESTAMP type + */ + Literal(int64_t second, int32_t nanos); + /** * Create a literal of STRING type */ @@ -82,7 +114,7 @@ namespace orc { */ int64_t getLong() const; int64_t getDate() const; - int64_t getTimestamp() const; + Timestamp getTimestamp() const; double getFloat() const; std::string getString() const; bool getBool() const; @@ -105,7 +137,7 @@ namespace orc { double DoubleVal; int64_t DateVal; char * Buffer; - int64_t TimeStampVal; + Timestamp TimeStampVal; Int128 DecimalVal; bool BooleanVal; diff --git a/c++/src/ColumnWriter.cc b/c++/src/ColumnWriter.cc index 6e1ec31bc6..684ce131a0 100644 --- a/c++/src/ColumnWriter.cc +++ b/c++/src/ColumnWriter.cc @@ -1802,7 +1802,7 @@ namespace orc { if (enableBloomFilter) { bloomFilter->addLong(millsUTC); } - tsStats->update(millsUTC); + tsStats->update(millsUTC, static_cast(nanos[i] % 1000000)); if (secs[i] < 0 && nanos[i] != 0) { secs[i] += 1; diff --git a/c++/src/Statistics.cc b/c++/src/Statistics.cc index 645ae31ef6..20e2fc91c8 100644 --- a/c++/src/Statistics.cc +++ b/c++/src/Statistics.cc @@ -317,6 +317,8 @@ namespace orc { _stats.setMaximum(0); _lowerBound = 0; _upperBound = 0; + _minimumNanos = DEFAULT_MIN_NANOS; + _maximumNanos = DEFAULT_MAX_NANOS; }else{ const proto::TimestampStatistics& stats = pb.timestampstatistics(); _stats.setHasMinimum( @@ -327,6 +329,12 @@ namespace orc { (stats.has_maximum() && (statContext.writerTimezone != nullptr))); _hasLowerBound = stats.has_minimumutc() || stats.has_minimum(); _hasUpperBound = stats.has_maximumutc() || stats.has_maximum(); + // to be consistent with java side, non-default minimumnanos and maximumnanos + // are added by one in their serialized form. + _minimumNanos = stats.has_minimumnanos() ? + stats.minimumnanos() - 1 : DEFAULT_MIN_NANOS; + _maximumNanos = stats.has_maximumnanos() ? + stats.maximumnanos() - 1 : DEFAULT_MAX_NANOS; // Timestamp stats are stored in milliseconds if (stats.has_minimumutc()) { diff --git a/c++/src/Statistics.hh b/c++/src/Statistics.hh index 426317f9ed..434a0adb88 100644 --- a/c++/src/Statistics.hh +++ b/c++/src/Statistics.hh @@ -1214,6 +1214,10 @@ namespace orc { bool _hasUpperBound; int64_t _lowerBound; int64_t _upperBound; + int32_t _minimumNanos; // last 6 digits of nanosecond of minimum timestamp + int32_t _maximumNanos; // last 6 digits of nanosecond of maximum timestamp + static constexpr int32_t DEFAULT_MIN_NANOS = 0; + static constexpr int32_t DEFAULT_MAX_NANOS = 999999; public: TimestampColumnStatisticsImpl() { reset(); } @@ -1279,14 +1283,68 @@ namespace orc { _stats.updateMinMax(value); } + void update(int64_t milli, int32_t nano) { + if (!_stats.hasMinimum()) { + _stats.setHasMinimum(true); + _stats.setHasMaximum(true); + _stats.setMinimum(milli); + _stats.setMaximum(milli); + _maximumNanos = _minimumNanos = nano; + } else { + if (milli <= _stats.getMinimum()) { + if (milli < _stats.getMinimum() || nano < _minimumNanos) { + _minimumNanos = nano; + } + _stats.setMinimum(milli); + } + + if (milli >= _stats.getMaximum()) { + if (milli > _stats.getMaximum() || nano > _maximumNanos) { + _maximumNanos = nano; + } + _stats.setMaximum(milli); + } + } + } + void merge(const MutableColumnStatistics& other) override { const TimestampColumnStatisticsImpl& tsStats = dynamic_cast(other); - _stats.merge(tsStats._stats); + + _stats.setHasNull(_stats.hasNull() || tsStats.hasNull()); + _stats.setNumberOfValues(_stats.getNumberOfValues() + tsStats.getNumberOfValues()); + + if (tsStats.hasMinimum()) { + if (!_stats.hasMinimum()) { + _stats.setHasMinimum(true); + _stats.setHasMaximum(true); + _stats.setMinimum(tsStats.getMinimum()); + _stats.setMaximum(tsStats.getMaximum()); + _minimumNanos = tsStats.getMinimumNanos(); + _maximumNanos = tsStats.getMaximumNanos(); + } else { + if (tsStats.getMaximum() >= _stats.getMaximum()) { + if (tsStats.getMaximum() > _stats.getMaximum() || + tsStats.getMaximumNanos() > _maximumNanos) { + _maximumNanos = tsStats.getMaximumNanos(); + } + _stats.setMaximum(tsStats.getMaximum()); + } + if (tsStats.getMinimum() <= _stats.getMinimum()) { + if (tsStats.getMinimum() < _stats.getMinimum() || + tsStats.getMinimumNanos() < _minimumNanos) { + _minimumNanos = tsStats.getMinimumNanos(); + } + _stats.setMinimum(tsStats.getMinimum()); + } + } + } } void reset() override { _stats.reset(); + _minimumNanos = DEFAULT_MIN_NANOS; + _maximumNanos = DEFAULT_MAX_NANOS; } void toProtoBuf(proto::ColumnStatistics& pbStats) const override { @@ -1298,9 +1356,17 @@ namespace orc { if (_stats.hasMinimum()) { tsStats->set_minimumutc(_stats.getMinimum()); tsStats->set_maximumutc(_stats.getMaximum()); + if (_minimumNanos != DEFAULT_MIN_NANOS) { + tsStats->set_minimumnanos(_minimumNanos + 1); + } + if (_maximumNanos != DEFAULT_MAX_NANOS) { + tsStats->set_maximumnanos(_maximumNanos + 1); + } } else { tsStats->clear_minimumutc(); tsStats->clear_maximumutc(); + tsStats->clear_minimumnanos(); + tsStats->clear_maximumnanos(); } } @@ -1379,6 +1445,22 @@ namespace orc { throw ParseError("UpperBound is not defined."); } } + + int32_t getMinimumNanos() const override { + if (hasMinimum()) { + return _minimumNanos; + } else { + throw ParseError("Minimum is not defined."); + } + } + + int32_t getMaximumNanos() const override { + if (hasMaximum()) { + return _maximumNanos; + } else { + throw ParseError("Maximum is not defined."); + } + } }; ColumnStatistics* convertColumnStatistics(const proto::ColumnStatistics& s, diff --git a/c++/src/sargs/Literal.cc b/c++/src/sargs/Literal.cc index 10dc7277ef..da4cdd0d47 100644 --- a/c++/src/sargs/Literal.cc +++ b/c++/src/sargs/Literal.cc @@ -66,8 +66,8 @@ namespace orc { } Literal::Literal(PredicateDataType type, int64_t val) { - if (type != PredicateDataType::DATE && type != PredicateDataType::TIMESTAMP) { - throw std::invalid_argument("only DATE & TIMESTAMP are supported here!"); + if (type != PredicateDataType::DATE) { + throw std::invalid_argument("only DATE is supported here!"); } mType = type; mValue.IntVal = val; @@ -99,6 +99,17 @@ namespace orc { mHashCode = hashCode(); } + Literal::Literal(int64_t second, int32_t nanos) { + mType = PredicateDataType::TIMESTAMP; + mValue.TimeStampVal.second = second; + mValue.TimeStampVal.nanos = nanos; + mPrecision = 0; + mScale = 0; + mSize = sizeof(Timestamp); + mIsNull = false; + mHashCode = hashCode(); + } + Literal::Literal(const Literal& r): mType(r.mType) , mSize(r.mSize) , mIsNull(r.mIsNull) @@ -112,6 +123,8 @@ namespace orc { mPrecision = r.mPrecision; mScale = r.mScale; mValue = r.mValue; + } else if (mType == PredicateDataType::TIMESTAMP) { + mValue.TimeStampVal = r.mValue.TimeStampVal; } else { mValue = r.mValue; mPrecision = 0; @@ -141,6 +154,8 @@ namespace orc { if (mType == PredicateDataType::STRING) { mValue.Buffer = new char[r.mSize]; memcpy(mValue.Buffer, r.mValue.Buffer, r.mSize); + } else if (mType == PredicateDataType::TIMESTAMP) { + mValue.TimeStampVal = r.mValue.TimeStampVal; } else { mValue = r.mValue; } @@ -163,7 +178,8 @@ namespace orc { sstream << mValue.DateVal; break; case PredicateDataType::TIMESTAMP: - sstream << mValue.TimeStampVal; + sstream << mValue.TimeStampVal.second << "." + << mValue.TimeStampVal.nanos; break; case PredicateDataType::FLOAT: sstream << mValue.DoubleVal; @@ -192,7 +208,8 @@ namespace orc { case PredicateDataType::DATE: return std::hash{}(mValue.DateVal); case PredicateDataType::TIMESTAMP: - return std::hash{}(mValue.TimeStampVal); + return std::hash{}(mValue.TimeStampVal.second) * 17 + + std::hash{}(mValue.TimeStampVal.nanos); case PredicateDataType::FLOAT: return std::hash{}(mValue.DoubleVal); case PredicateDataType::BOOLEAN: @@ -267,7 +284,7 @@ namespace orc { return mValue.DateVal; } - int64_t Literal::getTimestamp() const { + Literal::Timestamp Literal::getTimestamp() const { validate(mIsNull, mType, PredicateDataType::TIMESTAMP); return mValue.TimeStampVal; } diff --git a/c++/src/sargs/PredicateLeaf.cc b/c++/src/sargs/PredicateLeaf.cc index ad125e1ded..80a2f8729f 100644 --- a/c++/src/sargs/PredicateLeaf.cc +++ b/c++/src/sargs/PredicateLeaf.cc @@ -18,8 +18,8 @@ #include "orc/BloomFilter.hh" #include "orc/Common.hh" -#include "PredicateLeaf.hh" #include "orc/Type.hh" +#include "PredicateLeaf.hh" #include #include @@ -427,9 +427,9 @@ namespace orc { return result; } - static std::vector literal2Timestamp( + static std::vector literal2Timestamp( const std::vector& values) { - std::vector result; + std::vector result; std::for_each(values.cbegin(), values.cend(), [&](const Literal& val) { if (!val.isNull()) { result.emplace_back(val.getTimestamp()); @@ -510,6 +510,7 @@ namespace orc { break; } case PredicateDataType::STRING: { + ///TODO: check lowerBound and upperBound as well if (colStats.has_stringstatistics() && colStats.stringstatistics().has_minimum() && colStats.stringstatistics().has_maximum()) { @@ -542,11 +543,23 @@ namespace orc { colStats.timestampstatistics().has_minimumutc() && colStats.timestampstatistics().has_maximumutc()) { const auto& stats = colStats.timestampstatistics(); + constexpr int32_t DEFAULT_MIN_NANOS = 0; + constexpr int32_t DEFAULT_MAX_NANOS = 999999; + int32_t minNano = stats.has_minimumnanos() ? + stats.minimumnanos() - 1 : DEFAULT_MIN_NANOS; + int32_t maxNano = stats.has_maximumnanos() ? + stats.maximumnanos() - 1 : DEFAULT_MAX_NANOS; + Literal::Timestamp minTimestamp( + stats.minimumutc() / 1000, + static_cast((stats.minimumutc() % 1000) * 1000000) + minNano); + Literal::Timestamp maxTimestamp( + stats.maximumutc() / 1000, + static_cast((stats.maximumutc() % 1000) * 1000000) + maxNano); result = evaluatePredicateRange( mOperator, literal2Timestamp(mLiterals), - stats.minimumutc(), - stats.maximumutc(), + minTimestamp, + maxTimestamp, colStats.hasnull()); } break; @@ -634,7 +647,7 @@ namespace orc { result = TruthValue::YES_NO_NULL; } } else if (type == PredicateDataType::TIMESTAMP) { - if (bf->testLong(literal.getTimestamp())) { + if (bf->testLong(literal.getTimestamp().getMillis())) { result = TruthValue::YES_NO_NULL; } } else if (type == PredicateDataType::DATE) { diff --git a/c++/test/TestColumnStatistics.cc b/c++/test/TestColumnStatistics.cc index 315ac47010..4d187b9244 100644 --- a/c++/test/TestColumnStatistics.cc +++ b/c++/test/TestColumnStatistics.cc @@ -257,10 +257,14 @@ namespace orc { tsStats->update(100); EXPECT_EQ(100, tsStats->getMaximum()); EXPECT_EQ(100, tsStats->getMinimum()); + EXPECT_EQ(0, tsStats->getMinimumNanos()); + EXPECT_EQ(999999, tsStats->getMaximumNanos()); tsStats->update(150); EXPECT_EQ(150, tsStats->getMaximum()); EXPECT_EQ(100, tsStats->getMinimum()); + EXPECT_EQ(0, tsStats->getMinimumNanos()); + EXPECT_EQ(999999, tsStats->getMaximumNanos()); // test merge std::unique_ptr other( @@ -270,8 +274,10 @@ namespace orc { other->setMinimum(90); tsStats->merge(*other); - EXPECT_EQ(160, other->getMaximum()); - EXPECT_EQ(90, other->getMinimum()); + EXPECT_EQ(160, tsStats->getMaximum()); + EXPECT_EQ(90, tsStats->getMinimum()); + EXPECT_EQ(0, tsStats->getMinimumNanos()); + EXPECT_EQ(999999, tsStats->getMaximumNanos()); } TEST(ColumnStatistics, dateColumnStatistics) { @@ -383,4 +389,105 @@ namespace orc { decStats->update(Decimal(Int128("123456789012345678901234567890"), 10)); EXPECT_FALSE(decStats->hasSum()); } + + TEST(ColumnStatistics, timestampColumnStatisticsWithNanos) { + std::unique_ptr tsStats( + new TimestampColumnStatisticsImpl()); + + // normal operations + for (int32_t i = 1; i <= 1024; ++i) { + tsStats->update(i * 100, i * 1000); + tsStats->increase(1); + } + EXPECT_EQ(102400, tsStats->getMaximum()); + EXPECT_EQ(1024000, tsStats->getMaximumNanos()); + EXPECT_EQ(100, tsStats->getMinimum()); + EXPECT_EQ(1000, tsStats->getMinimumNanos()); + + // update with same milli but different nanos + tsStats->update(102400, 1024001); + tsStats->update(102400, 1023999); + tsStats->update(100, 1001); + tsStats->update(100, 999); + EXPECT_EQ(102400, tsStats->getMaximum()); + EXPECT_EQ(1024001, tsStats->getMaximumNanos()); + EXPECT_EQ(100, tsStats->getMinimum()); + EXPECT_EQ(999, tsStats->getMinimumNanos()); + + // test merge with no change + std::unique_ptr other1( + new TimestampColumnStatisticsImpl()); + for (int32_t i = 1; i <= 1024; ++i) { + other1->update(i * 100, i * 1000); + other1->increase(1); + } + tsStats->merge(*other1); + EXPECT_EQ(102400, tsStats->getMaximum()); + EXPECT_EQ(1024001, tsStats->getMaximumNanos()); + EXPECT_EQ(100, tsStats->getMinimum()); + EXPECT_EQ(999, tsStats->getMinimumNanos()); + + // test merge with min/max change only in nano + std::unique_ptr other2( + new TimestampColumnStatisticsImpl()); + other2->update(102400, 1024002); + other2->update(100, 998); + tsStats->merge(*other2); + EXPECT_EQ(102400, tsStats->getMaximum()); + EXPECT_EQ(1024002, tsStats->getMaximumNanos()); + EXPECT_EQ(100, tsStats->getMinimum()); + EXPECT_EQ(998, tsStats->getMinimumNanos()); + + // test merge with min/max change in milli + std::unique_ptr other3( + new TimestampColumnStatisticsImpl()); + other3->update(102401, 1); + other3->update(99, 1); + tsStats->merge(*other3); + EXPECT_EQ(102401, tsStats->getMaximum()); + EXPECT_EQ(1, tsStats->getMaximumNanos()); + EXPECT_EQ(99, tsStats->getMinimum()); + EXPECT_EQ(1, tsStats->getMinimumNanos()); + } + + TEST(ColumnStatistics, timestampColumnStatisticsProbubuf) { + std::unique_ptr tsStats( + new TimestampColumnStatisticsImpl()); + tsStats->increase(2); + tsStats->update(100); + tsStats->update(200); + + proto::ColumnStatistics pbStats; + tsStats->toProtoBuf(pbStats); + EXPECT_EQ(100, pbStats.timestampstatistics().minimumutc()); + EXPECT_EQ(200, pbStats.timestampstatistics().maximumutc()); + EXPECT_FALSE(pbStats.timestampstatistics().has_minimumnanos()); + EXPECT_FALSE(pbStats.timestampstatistics().has_maximumnanos()); + + StatContext ctx(true, nullptr); + std::unique_ptr tsStatsFromPb( + new TimestampColumnStatisticsImpl(pbStats, ctx)); + EXPECT_EQ(100, tsStatsFromPb->getMinimum()); + EXPECT_EQ(200, tsStatsFromPb->getMaximum()); + EXPECT_EQ(0, tsStatsFromPb->getMinimumNanos()); + EXPECT_EQ(999999, tsStatsFromPb->getMaximumNanos()); + + tsStats->update(50, 5555); + tsStats->update(500, 9999); + pbStats.Clear(); + tsStats->toProtoBuf(pbStats); + EXPECT_EQ(50, pbStats.timestampstatistics().minimumutc()); + EXPECT_EQ(500, pbStats.timestampstatistics().maximumutc()); + EXPECT_TRUE(pbStats.timestampstatistics().has_minimumnanos()); + EXPECT_TRUE(pbStats.timestampstatistics().has_maximumnanos()); + EXPECT_EQ(5555 + 1, pbStats.timestampstatistics().minimumnanos()); + EXPECT_EQ(9999 + 1, pbStats.timestampstatistics().maximumnanos()); + + tsStatsFromPb.reset(new TimestampColumnStatisticsImpl(pbStats, ctx)); + EXPECT_EQ(50, tsStatsFromPb->getMinimum()); + EXPECT_EQ(500, tsStatsFromPb->getMaximum()); + EXPECT_EQ(5555, tsStatsFromPb->getMinimumNanos()); + EXPECT_EQ(9999, tsStatsFromPb->getMaximumNanos()); + } + } diff --git a/c++/test/TestPredicateLeaf.cc b/c++/test/TestPredicateLeaf.cc index dd026cdd20..1740aa3564 100644 --- a/c++/test/TestPredicateLeaf.cc +++ b/c++/test/TestPredicateLeaf.cc @@ -145,6 +145,22 @@ namespace orc { return colStats; } + static proto::ColumnStatistics createTimestampStats( + int64_t minSecond, int32_t minNano, + int64_t maxSecond, int32_t maxNano, + bool hasNull = false) { + proto::ColumnStatistics colStats; + colStats.set_hasnull(hasNull); + colStats.set_numberofvalues(10); + + proto::TimestampStatistics * tsStats = colStats.mutable_timestampstatistics(); + tsStats->set_minimumutc(minSecond * 1000 + minNano / 1000000); + tsStats->set_maximumutc(maxSecond * 1000 + maxNano / 1000000); + tsStats->set_minimumnanos((minNano % 1000000) + 1); + tsStats->set_maximumnanos((maxNano % 1000000) + 1); + return colStats; + } + static proto::ColumnStatistics createStringStats( std::string min, std::string max, bool hasNull = false) { proto::ColumnStatistics colStats; @@ -241,7 +257,7 @@ namespace orc { PredicateLeaf::Operator::NULL_SAFE_EQUALS, PredicateDataType::TIMESTAMP, "x", - Literal(PredicateDataType::TIMESTAMP, 500L)); + Literal(500L, 0)); EXPECT_EQ(TruthValue::NO, evaluate(pred8, createTimestampStats(450LL, 490L))); @@ -843,4 +859,64 @@ namespace orc { pred, createDecimalStats(Decimal("10"), Decimal("200"), true), &bf)); } + TEST(TestPredicateLeaf, testTimestampWithNanos) { + // 1970-01-01 00:00:00 + PredicateLeaf pred1(PredicateLeaf::Operator::EQUALS, + PredicateDataType::TIMESTAMP, + "x", + Literal(static_cast(0), 500000)); + EXPECT_EQ(TruthValue::YES, evaluate( + pred1, createTimestampStats(0, 500000, 0, 500000))); + + PredicateLeaf pred2(PredicateLeaf::Operator::LESS_THAN_EQUALS, + PredicateDataType::TIMESTAMP, + "x", + Literal(static_cast(0), 500000)); + EXPECT_EQ(TruthValue::YES_NO, evaluate( + pred2, createTimestampStats(0, 500000, 0, 500000))); + + PredicateLeaf pred3(PredicateLeaf::Operator::LESS_THAN, + PredicateDataType::TIMESTAMP, + "x", + Literal(static_cast(0), 500000)); + EXPECT_EQ(TruthValue::NO, evaluate( + pred3, createTimestampStats(0, 500000, 0, 500000))); + + // 2037-01-01 00:00:00 + PredicateLeaf pred4(PredicateLeaf::Operator::EQUALS, + PredicateDataType::TIMESTAMP, + "x", + Literal(2114380800, 1109000)); + EXPECT_EQ(TruthValue::YES_NO, evaluate( + pred4, createTimestampStats(2114380800, 1109000, 2114380800, 6789100))); + + PredicateLeaf pred5(PredicateLeaf::Operator::EQUALS, + PredicateDataType::TIMESTAMP, + "x", + Literal(2114380800, 1000000)); + EXPECT_EQ(TruthValue::NO, evaluate( + pred5, createTimestampStats(2114380800, 1109000, 2114380800, 6789100))); + + PredicateLeaf pred6(PredicateLeaf::Operator::LESS_THAN, + PredicateDataType::TIMESTAMP, + "x", + Literal(2114380800, 6789000)); + EXPECT_EQ(TruthValue::YES_NO, evaluate( + pred6, createTimestampStats(2114380800, 1109000, 2114380800, 6789100))); + + PredicateLeaf pred7(PredicateLeaf::Operator::LESS_THAN, + PredicateDataType::TIMESTAMP, + "x", + Literal(2114380800, 2000000)); + EXPECT_EQ(TruthValue::YES_NO, evaluate( + pred7, createTimestampStats(2114380800, 1109000, 2114380800, 6789100))); + + PredicateLeaf pred8(PredicateLeaf::Operator::LESS_THAN, + PredicateDataType::TIMESTAMP, + "x", + Literal(2114380800, 1000000)); + EXPECT_EQ(TruthValue::NO, evaluate( + pred8, createTimestampStats(2114380800, 1109000, 2114380800, 6789100))); + } + } // namespace orc diff --git a/c++/test/TestSearchArgument.cc b/c++/test/TestSearchArgument.cc index 05784a91e7..e29a76b213 100644 --- a/c++/test/TestSearchArgument.cc +++ b/c++/test/TestSearchArgument.cc @@ -36,9 +36,10 @@ namespace orc { EXPECT_EQ(PredicateDataType::BOOLEAN, literal2.getType()); EXPECT_TRUE("false" == literal2.toString()); - Literal literal3(PredicateDataType::TIMESTAMP, 123456L); + Literal literal3(static_cast(123456), 123456789); EXPECT_EQ(PredicateDataType::TIMESTAMP, literal3.getType()); - EXPECT_TRUE("123456" == literal3.toString()); + EXPECT_TRUE("123456.123456789" == literal3.toString()); + EXPECT_EQ(123456123, literal3.getTimestamp().getMillis()); Literal literal4(Int128(54321), 6, 2); EXPECT_EQ(PredicateDataType::DECIMAL, literal4.getType());