You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@orc.apache.org by om...@apache.org on 2017/05/02 18:13:29 UTC
orc git commit: ORC-87: Fix timestamp statistics
Repository: orc
Updated Branches:
refs/heads/master 9175b3e22 -> dd464406f
ORC-87: Fix timestamp statistics
Fixes #110
Signed-off-by: Owen O'Malley <om...@apache.org>
Project: http://git-wip-us.apache.org/repos/asf/orc/repo
Commit: http://git-wip-us.apache.org/repos/asf/orc/commit/dd464406
Tree: http://git-wip-us.apache.org/repos/asf/orc/tree/dd464406
Diff: http://git-wip-us.apache.org/repos/asf/orc/diff/dd464406
Branch: refs/heads/master
Commit: dd464406f7cb86b34e79576a50312fff367581e1
Parents: 9175b3e
Author: Deepak Majeti <de...@hpe.com>
Authored: Tue Apr 18 16:59:44 2017 -0400
Committer: Owen O'Malley <om...@apache.org>
Committed: Tue May 2 11:13:03 2017 -0700
----------------------------------------------------------------------
c++/include/orc/Statistics.hh | 26 +++++++++
c++/src/Reader.cc | 38 ++++++++-----
c++/src/Reader.hh | 4 +-
c++/src/Statistics.cc | 93 +++++++++++++++++++++-----------
c++/src/Statistics.hh | 92 +++++++++++++++++++++++++++----
c++/src/Timezone.cc | 2 -
c++/src/Timezone.hh | 3 ++
c++/test/CMakeLists.txt | 1 +
c++/test/TestTimestampStatistics.cc | 60 +++++++++++++++++++++
9 files changed, 261 insertions(+), 58 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/orc/blob/dd464406/c++/include/orc/Statistics.hh
----------------------------------------------------------------------
diff --git a/c++/include/orc/Statistics.hh b/c++/include/orc/Statistics.hh
index c65eb3c..9643ec6 100644
--- a/c++/include/orc/Statistics.hh
+++ b/c++/include/orc/Statistics.hh
@@ -321,6 +321,32 @@ namespace orc {
* @return maximum value
*/
virtual int64_t getMaximum() const = 0;
+
+ /**
+ * check whether column has a lowerBound
+ * @return true if column has a lowerBound
+ */
+ virtual bool hasLowerBound() const = 0;
+
+ /**
+ * check whether column has an upperBound
+ * @return true if column has an upperBound
+ */
+ virtual bool hasUpperBound() const = 0;
+
+ /**
+ * Get the lowerBound value for the column.
+ * @return lowerBound value
+ */
+ virtual int64_t getLowerBound() const = 0;
+
+ /**
+ * Get the upperBound value for the column.
+ * @return upperBound value
+ */
+ virtual int64_t getUpperBound() const = 0;
+
+
};
class Statistics {
http://git-wip-us.apache.org/repos/asf/orc/blob/dd464406/c++/src/Reader.cc
----------------------------------------------------------------------
diff --git a/c++/src/Reader.cc b/c++/src/Reader.cc
index 034586d..9c423bd 100644
--- a/c++/src/Reader.cc
+++ b/c++/src/Reader.cc
@@ -339,20 +339,20 @@ namespace orc {
return forcedScaleOnHive11Decimal;
}
- proto::StripeFooter RowReaderImpl::getStripeFooter
- (const proto::StripeInformation& info) {
+ proto::StripeFooter getStripeFooter(const proto::StripeInformation& info,
+ const FileContents& contents) {
uint64_t stripeFooterStart = info.offset() + info.indexlength() +
info.datalength();
uint64_t stripeFooterLength = info.footerlength();
std::unique_ptr<SeekableInputStream> pbStream =
- createDecompressor(contents->compression,
+ createDecompressor(contents.compression,
std::unique_ptr<SeekableInputStream>
- (new SeekableFileInputStream(contents->stream.get(),
+ (new SeekableFileInputStream(contents.stream.get(),
stripeFooterStart,
stripeFooterLength,
- *contents->pool)),
- contents->blockSize,
- *contents->pool);
+ *contents.pool)),
+ contents.blockSize,
+ *contents.pool);
proto::StripeFooter result;
if (!result.ParseFromZeroCopyStream(pbStream.get())) {
throw ParseError(std::string("bad StripeFooter from ") +
@@ -526,16 +526,25 @@ namespace orc {
if (metadata.get() == nullptr) {
throw std::logic_error("No stripe statistics in file");
}
+ proto::StripeInformation currentStripeInfo =
+ footer->stripes(static_cast<int>(stripeIndex));
+ proto::StripeFooter currentStripeFooter =
+ getStripeFooter(currentStripeInfo, *contents.get());
+
+ const Timezone& writerTZ =
+ currentStripeFooter.has_writertimezone() ?
+ getTimezoneByName(currentStripeFooter.writertimezone()) :
+ getLocalTimezone();
+ StatContext statContext(hasCorrectStatistics(), &writerTZ);
return std::unique_ptr<Statistics>
(new StatisticsImpl(metadata->stripestats
- (static_cast<int>(stripeIndex)),
- hasCorrectStatistics()));
+ (static_cast<int>(stripeIndex)), statContext));
}
std::unique_ptr<Statistics> ReaderImpl::getStatistics() const {
+ StatContext statContext(hasCorrectStatistics());
return std::unique_ptr<Statistics>
- (new StatisticsImpl(*footer,
- hasCorrectStatistics()));
+ (new StatisticsImpl(*footer, statContext));
}
std::unique_ptr<ColumnStatistics>
@@ -545,8 +554,9 @@ namespace orc {
}
proto::ColumnStatistics col =
footer->statistics(static_cast<int32_t>(index));
- return std::unique_ptr<ColumnStatistics> (convertColumnStatistics
- (col, hasCorrectStatistics()));
+
+ StatContext statContext(hasCorrectStatistics());
+ return std::unique_ptr<ColumnStatistics> (convertColumnStatistics(col, statContext));
}
void ReaderImpl::readMetadata() const {
@@ -763,7 +773,7 @@ namespace orc {
void RowReaderImpl::startNextStripe() {
reader.reset(); // ColumnReaders use lots of memory; free old memory first
currentStripeInfo = footer->stripes(static_cast<int>(currentStripe));
- currentStripeFooter = getStripeFooter(currentStripeInfo);
+ currentStripeFooter = getStripeFooter(currentStripeInfo, *contents.get());
rowsInCurrentStripe = currentStripeInfo.numberofrows();
const Timezone& writerTimezone =
currentStripeFooter.has_writertimezone() ?
http://git-wip-us.apache.org/repos/asf/orc/blob/dd464406/c++/src/Reader.hh
----------------------------------------------------------------------
diff --git a/c++/src/Reader.hh b/c++/src/Reader.hh
index 040d60a..02f2260 100644
--- a/c++/src/Reader.hh
+++ b/c++/src/Reader.hh
@@ -46,6 +46,9 @@ namespace orc {
std::ostream *errorStream;
};
+ proto::StripeFooter getStripeFooter(const proto::StripeInformation& info,
+ const FileContents& contents);
+
class ReaderImpl;
class ColumnSelector {
@@ -116,7 +119,6 @@ namespace orc {
std::unique_ptr<ColumnReader> reader;
// internal methods
- proto::StripeFooter getStripeFooter(const proto::StripeInformation& info);
void startNextStripe();
public:
http://git-wip-us.apache.org/repos/asf/orc/blob/dd464406/c++/src/Statistics.cc
----------------------------------------------------------------------
diff --git a/c++/src/Statistics.cc b/c++/src/Statistics.cc
index 083b722..54da928 100644
--- a/c++/src/Statistics.cc
+++ b/c++/src/Statistics.cc
@@ -25,39 +25,37 @@
namespace orc {
ColumnStatistics* convertColumnStatistics(const proto::ColumnStatistics& s,
- bool correctStats) {
+ const StatContext& statContext) {
if (s.has_intstatistics()) {
return new IntegerColumnStatisticsImpl(s);
} else if (s.has_doublestatistics()) {
return new DoubleColumnStatisticsImpl(s);
} else if (s.has_stringstatistics()) {
- return new StringColumnStatisticsImpl(s, correctStats);
+ return new StringColumnStatisticsImpl(s, statContext);
} else if (s.has_bucketstatistics()) {
- return new BooleanColumnStatisticsImpl(s, correctStats);
+ return new BooleanColumnStatisticsImpl(s, statContext);
} else if (s.has_decimalstatistics()) {
- return new DecimalColumnStatisticsImpl(s, correctStats);
+ return new DecimalColumnStatisticsImpl(s, statContext);
} else if (s.has_timestampstatistics()) {
- return new TimestampColumnStatisticsImpl(s, correctStats);
+ return new TimestampColumnStatisticsImpl(s, statContext);
} else if (s.has_datestatistics()) {
- return new DateColumnStatisticsImpl(s, correctStats);
+ return new DateColumnStatisticsImpl(s, statContext);
} else if (s.has_binarystatistics()) {
- return new BinaryColumnStatisticsImpl(s, correctStats);
+ return new BinaryColumnStatisticsImpl(s, statContext);
} else {
return new ColumnStatisticsImpl(s);
}
}
- StatisticsImpl::StatisticsImpl(const proto::StripeStatistics& stripeStats, bool correctStats) {
+ StatisticsImpl::StatisticsImpl(const proto::StripeStatistics& stripeStats, const StatContext& statContext) {
for(int i = 0; i < stripeStats.colstats_size(); i++) {
- colStats.push_back(convertColumnStatistics
- (stripeStats.colstats(i), correctStats));
+ colStats.push_back(convertColumnStatistics(stripeStats.colstats(i), statContext));
}
}
- StatisticsImpl::StatisticsImpl(const proto::Footer& footer, bool correctStats) {
+ StatisticsImpl::StatisticsImpl(const proto::Footer& footer, const StatContext& statContext) {
for(int i = 0; i < footer.statistics_size(); i++) {
- colStats.push_back(convertColumnStatistics
- (footer.statistics(i), correctStats));
+ colStats.push_back(convertColumnStatistics(footer.statistics(i), statContext));
}
}
@@ -151,9 +149,9 @@ namespace orc {
}
BinaryColumnStatisticsImpl::BinaryColumnStatisticsImpl
- (const proto::ColumnStatistics& pb, bool correctStats){
+ (const proto::ColumnStatistics& pb, const StatContext& statContext){
valueCount = pb.numberofvalues();
- if (!pb.has_binarystatistics() || !correctStats) {
+ if (!pb.has_binarystatistics() || !statContext.correctStats) {
_hasTotalLength = false;
totalLength = 0;
@@ -164,9 +162,9 @@ namespace orc {
}
BooleanColumnStatisticsImpl::BooleanColumnStatisticsImpl
- (const proto::ColumnStatistics& pb, bool correctStats){
+ (const proto::ColumnStatistics& pb, const StatContext& statContext){
valueCount = pb.numberofvalues();
- if (!pb.has_bucketstatistics() || !correctStats) {
+ if (!pb.has_bucketstatistics() || !statContext.correctStats) {
_hasCount = false;
trueCount = 0;
}else{
@@ -176,9 +174,9 @@ namespace orc {
}
DateColumnStatisticsImpl::DateColumnStatisticsImpl
- (const proto::ColumnStatistics& pb, bool correctStats){
+ (const proto::ColumnStatistics& pb, const StatContext& statContext){
valueCount = pb.numberofvalues();
- if (!pb.has_datestatistics() || !correctStats) {
+ if (!pb.has_datestatistics() || !statContext.correctStats) {
_hasMinimum = false;
_hasMaximum = false;
@@ -193,9 +191,9 @@ namespace orc {
}
DecimalColumnStatisticsImpl::DecimalColumnStatisticsImpl
- (const proto::ColumnStatistics& pb, bool correctStats){
+ (const proto::ColumnStatistics& pb, const StatContext& statContext){
valueCount = pb.numberofvalues();
- if (!pb.has_decimalstatistics() || !correctStats) {
+ if (!pb.has_decimalstatistics() || !statContext.correctStats) {
_hasMinimum = false;
_hasMaximum = false;
_hasSum = false;
@@ -258,9 +256,9 @@ namespace orc {
}
StringColumnStatisticsImpl::StringColumnStatisticsImpl
- (const proto::ColumnStatistics& pb, bool correctStats){
+ (const proto::ColumnStatistics& pb, const StatContext& statContext){
valueCount = pb.numberofvalues();
- if (!pb.has_stringstatistics() || !correctStats) {
+ if (!pb.has_stringstatistics() || !statContext.correctStats) {
_hasMinimum = false;
_hasMaximum = false;
_hasTotalLength = false;
@@ -279,20 +277,55 @@ namespace orc {
}
TimestampColumnStatisticsImpl::TimestampColumnStatisticsImpl
- (const proto::ColumnStatistics& pb, bool correctStats) {
+ (const proto::ColumnStatistics& pb, const StatContext& statContext) {
valueCount = pb.numberofvalues();
- if (!pb.has_timestampstatistics() || !correctStats) {
+ if (!pb.has_timestampstatistics() || !statContext.correctStats) {
_hasMinimum = false;
_hasMaximum = false;
+ _hasLowerBound = false;
+ _hasUpperBound = false;
minimum = 0;
maximum = 0;
+ lowerBound = 0;
+ upperBound = 0;
}else{
const proto::TimestampStatistics& stats = pb.timestampstatistics();
- _hasMinimum = stats.has_minimum();
- _hasMaximum = stats.has_maximum();
-
- minimum = stats.minimum();
- maximum = stats.maximum();
+ _hasMinimum = stats.has_minimumutc() || (stats.has_minimum() && (statContext.writerTimezone != NULL));
+ _hasMaximum = stats.has_maximumutc() || (stats.has_maximum() && (statContext.writerTimezone != NULL));
+ _hasLowerBound = stats.has_minimumutc() || stats.has_minimum();
+ _hasUpperBound = stats.has_maximumutc() || stats.has_maximum();
+
+ // Timestamp stats are stored in milliseconds
+ if (stats.has_minimumutc()) {
+ minimum = stats.minimumutc();
+ lowerBound = minimum;
+ } else if (statContext.writerTimezone) {
+ int64_t writerTimeSec = stats.minimum() / 1000;
+ // multiply the offset by 1000 to convert to millisecond
+ minimum = stats.minimum() + (statContext.writerTimezone->getVariant(writerTimeSec).gmtOffset) * 1000;
+ lowerBound = minimum;
+ } else {
+ minimum = 0;
+ // subtract 1 day 1 hour (25 hours) in milliseconds to handle unknown TZ and daylight savings
+ lowerBound = stats.minimum() - (25 * SECONDS_PER_HOUR * 1000);
+ }
+
+ // Timestamp stats are stored in milliseconds
+ if (stats.has_maximumutc()) {
+ maximum = stats.maximumutc();
+ upperBound = maximum;
+ } else if (statContext.writerTimezone) {
+ int64_t writerTimeSec = stats.maximum() / 1000;
+ // multiply the offset by 1000 to convert to millisecond
+ maximum = stats.maximum() + (statContext.writerTimezone->getVariant(writerTimeSec).gmtOffset) * 1000;
+ upperBound = maximum;
+ } else {
+ maximum = 0;
+ // add 1 day 1 hour (25 hours) in milliseconds to handle unknown TZ and daylight savings
+ upperBound = stats.maximum() + (25 * SECONDS_PER_HOUR * 1000);
+ }
+ // Add 1 millisecond to account for microsecond precision of values
+ upperBound += 1;
}
}
http://git-wip-us.apache.org/repos/asf/orc/blob/dd464406/c++/src/Statistics.hh
----------------------------------------------------------------------
diff --git a/c++/src/Statistics.hh b/c++/src/Statistics.hh
index 1d1006e..de9c9f3 100644
--- a/c++/src/Statistics.hh
+++ b/c++/src/Statistics.hh
@@ -23,11 +23,24 @@
#include "orc/OrcFile.hh"
#include "orc/Reader.hh"
+#include "Timezone.hh"
#include "TypeImpl.hh"
namespace orc {
/**
+ * StatContext contains fields required to compute statistics
+ */
+
+ struct StatContext {
+ const bool correctStats;
+ const Timezone* const writerTimezone;
+ StatContext() : correctStats(false), writerTimezone(NULL) {}
+ StatContext(bool cStat, const Timezone* const timezone = NULL) :
+ correctStats(cStat), writerTimezone(timezone) {}
+ };
+
+/**
* ColumnStatistics Implementation
*/
@@ -58,7 +71,7 @@ namespace orc {
public:
BinaryColumnStatisticsImpl(const proto::ColumnStatistics& stats,
- bool correctStats);
+ const StatContext& statContext);
virtual ~BinaryColumnStatisticsImpl();
bool hasTotalLength() const override {
@@ -96,7 +109,7 @@ namespace orc {
uint64_t trueCount;
public:
- BooleanColumnStatisticsImpl(const proto::ColumnStatistics& stats, bool correctStats);
+ BooleanColumnStatisticsImpl(const proto::ColumnStatistics& stats, const StatContext& statContext);
virtual ~BooleanColumnStatisticsImpl();
bool hasCount() const override {
@@ -147,7 +160,7 @@ namespace orc {
int32_t maximum;
public:
- DateColumnStatisticsImpl(const proto::ColumnStatistics& stats, bool correctStats);
+ DateColumnStatisticsImpl(const proto::ColumnStatistics& stats, const StatContext& statContext);
virtual ~DateColumnStatisticsImpl();
bool hasMinimum() const override {
@@ -208,7 +221,7 @@ namespace orc {
std::string sum;
public:
- DecimalColumnStatisticsImpl(const proto::ColumnStatistics& stats, bool correctStats);
+ DecimalColumnStatisticsImpl(const proto::ColumnStatistics& stats, const StatContext& statContext);
virtual ~DecimalColumnStatisticsImpl();
bool hasMinimum() const override {
@@ -446,7 +459,7 @@ namespace orc {
uint64_t totalLength;
public:
- StringColumnStatisticsImpl(const proto::ColumnStatistics& stats, bool correctStats);
+ StringColumnStatisticsImpl(const proto::ColumnStatistics& stats, const StatContext& statContext);
virtual ~StringColumnStatisticsImpl();
bool hasMinimum() const override {
@@ -521,10 +534,14 @@ namespace orc {
uint64_t valueCount;
int64_t minimum;
int64_t maximum;
+ bool _hasLowerBound;
+ bool _hasUpperBound;
+ int64_t lowerBound;
+ int64_t upperBound;
public:
TimestampColumnStatisticsImpl(const proto::ColumnStatistics& stats,
- bool correctStats);
+ const StatContext& statContext);
virtual ~TimestampColumnStatisticsImpl();
bool hasMinimum() const override {
@@ -557,26 +574,79 @@ namespace orc {
std::string toString() const override {
std::ostringstream buffer;
+ struct tm tmValue;
+ char timeBuffer[20];
+ time_t secs = 0;
+
buffer << "Data type: Timestamp" << std::endl
<< "Values: " << valueCount << std::endl;
if(_hasMinimum){
- buffer << "Minimum: " << minimum << std::endl;
+ secs = static_cast<time_t>(minimum/1000);
+ gmtime_r(&secs, &tmValue);
+ strftime(timeBuffer, sizeof(timeBuffer), "%Y-%m-%d %H:%M:%S", &tmValue);
+ buffer << "Minimum: " << timeBuffer << "." << (minimum % 1000) << std::endl;
}else{
buffer << "Minimum is not defined" << std::endl;
}
+ if(_hasLowerBound){
+ secs = static_cast<time_t>(lowerBound/1000);
+ gmtime_r(&secs, &tmValue);
+ strftime(timeBuffer, sizeof(timeBuffer), "%Y-%m-%d %H:%M:%S", &tmValue);
+ buffer << "LowerBound: " << timeBuffer << "." << (lowerBound % 1000) << std::endl;
+ }else{
+ buffer << "LowerBound is not defined" << std::endl;
+ }
+
if(_hasMaximum){
- buffer << "Maximum: " << maximum << std::endl;
+ secs = static_cast<time_t>(maximum/1000);
+ gmtime_r(&secs, &tmValue);
+ strftime(timeBuffer, sizeof(timeBuffer), "%Y-%m-%d %H:%M:%S", &tmValue);
+ buffer << "Maximum: " << timeBuffer << "." << (maximum % 1000) << std::endl;
}else{
buffer << "Maximum is not defined" << std::endl;
}
+
+ if(_hasUpperBound){
+ secs = static_cast<time_t>(upperBound/1000);
+ gmtime_r(&secs, &tmValue);
+ strftime(timeBuffer, sizeof(timeBuffer), "%Y-%m-%d %H:%M:%S", &tmValue);
+ buffer << "UpperBound: " << timeBuffer << "." << (upperBound % 1000) << std::endl;
+ }else{
+ buffer << "UpperBound is not defined" << std::endl;
+ }
+
return buffer.str();
}
+
+ bool hasLowerBound() const override {
+ return _hasLowerBound;
+ }
+
+ bool hasUpperBound() const override {
+ return _hasUpperBound;
+ }
+
+ int64_t getLowerBound() const override {
+ if(_hasLowerBound){
+ return lowerBound;
+ }else{
+ throw ParseError("LowerBound is not defined.");
+ }
+ }
+
+ int64_t getUpperBound() const override {
+ if(_hasUpperBound){
+ return upperBound;
+ }else{
+ throw ParseError("UpperBound is not defined.");
+ }
+ }
};
ColumnStatistics* convertColumnStatistics(const proto::ColumnStatistics& s,
- bool correctStats);
+ const StatContext& statContext);
class StatisticsImpl: public Statistics {
private:
@@ -587,9 +657,9 @@ namespace orc {
StatisticsImpl& operator=(const StatisticsImpl&);
public:
- StatisticsImpl(const proto::StripeStatistics& stripeStats, bool correctStats);
+ StatisticsImpl(const proto::StripeStatistics& stripeStats, const StatContext& statContext);
- StatisticsImpl(const proto::Footer& footer, bool correctStats);
+ StatisticsImpl(const proto::Footer& footer, const StatContext& statContext);
virtual const ColumnStatistics* getColumnStatistics(uint32_t columnId
) const override {
http://git-wip-us.apache.org/repos/asf/orc/blob/dd464406/c++/src/Timezone.cc
----------------------------------------------------------------------
diff --git a/c++/src/Timezone.cc b/c++/src/Timezone.cc
index 5ffec3c..bc2ffb6 100644
--- a/c++/src/Timezone.cc
+++ b/c++/src/Timezone.cc
@@ -52,8 +52,6 @@ namespace orc {
static const int64_t DAYS_PER_MONTH[2][MONTHS_PER_YEAR] =
{{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
- static const int64_t SECONDS_PER_HOUR = 60 * 60;
- static const int64_t SECONDS_PER_DAY = SECONDS_PER_HOUR * 24;
static const int64_t DAYS_PER_WEEK = 7;
// Leap years and day of the week repeat every 400 years, which makes it
http://git-wip-us.apache.org/repos/asf/orc/blob/dd464406/c++/src/Timezone.hh
----------------------------------------------------------------------
diff --git a/c++/src/Timezone.hh b/c++/src/Timezone.hh
index 1cf04cf..b1dbd6a 100644
--- a/c++/src/Timezone.hh
+++ b/c++/src/Timezone.hh
@@ -31,6 +31,9 @@
namespace orc {
+ static const int64_t SECONDS_PER_HOUR = 60 * 60;
+ static const int64_t SECONDS_PER_DAY = SECONDS_PER_HOUR * 24;
+
/**
* A variant (eg. PST or PDT) of a timezone (eg. America/Los_Angeles).
*/
http://git-wip-us.apache.org/repos/asf/orc/blob/dd464406/c++/test/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/c++/test/CMakeLists.txt b/c++/test/CMakeLists.txt
index 775e15f..83c48a3 100644
--- a/c++/test/CMakeLists.txt
+++ b/c++/test/CMakeLists.txt
@@ -32,6 +32,7 @@ add_executable (orc-test
TestReader.cc
TestRle.cc
TestTimezone.cc
+ TestTimestampStatistics.cc
TestType.cc
)
http://git-wip-us.apache.org/repos/asf/orc/blob/dd464406/c++/test/TestTimestampStatistics.cc
----------------------------------------------------------------------
diff --git a/c++/test/TestTimestampStatistics.cc b/c++/test/TestTimestampStatistics.cc
new file mode 100644
index 0000000..8fe47f2
--- /dev/null
+++ b/c++/test/TestTimestampStatistics.cc
@@ -0,0 +1,60 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "orc/OrcFile.hh"
+#include "orc/Reader.hh"
+
+#include "Adaptor.hh"
+
+#include "wrap/gmock.h"
+#include "wrap/gtest-wrapper.h"
+
+namespace orc {
+
+ TEST(TestTimestampStatistics, testOldFile) {
+
+ std::stringstream ss;
+ if(const char* example_dir = std::getenv("ORC_EXAMPLE_DIR")) {
+ ss << example_dir;
+ } else {
+ ss << "../../../examples";
+ }
+ ss << "/TestOrcFile.testTimestamp.orc";
+ std::unique_ptr<orc::Reader> reader =
+ createReader(readLocalFile(ss.str().c_str()), ReaderOptions());
+
+ std::unique_ptr<orc::ColumnStatistics> footerStats = reader->getColumnStatistics(0);
+ const orc::TimestampColumnStatistics* footerColStats =
+ reinterpret_cast<const orc::TimestampColumnStatistics*>(footerStats.get());
+
+ std::unique_ptr<orc::Statistics> stripeStats = reader->getStripeStatistics(0);
+ const orc::TimestampColumnStatistics* stripeColStats =
+ reinterpret_cast<const orc::TimestampColumnStatistics*>(stripeStats->getColumnStatistics(0));
+
+ EXPECT_FALSE(footerColStats->hasMinimum());
+ EXPECT_FALSE(footerColStats->hasMaximum());
+ EXPECT_TRUE(footerColStats->hasLowerBound());
+ EXPECT_TRUE(footerColStats->hasUpperBound());
+ EXPECT_EQ("Data type: Timestamp\nValues: 12\nMinimum is not defined\nLowerBound: 1994-12-31 07:00:00.688\nMaximum is not defined\nUpperBound: 2037-01-02 09:00:00.1\n", footerColStats->toString());
+
+ EXPECT_TRUE(stripeColStats->hasMinimum());
+ EXPECT_TRUE(stripeColStats->hasMaximum());
+ EXPECT_EQ("Data type: Timestamp\nValues: 12\nMinimum: 1995-01-01 00:00:00.688\nLowerBound: 1995-01-01 00:00:00.688\nMaximum: 2037-01-01 00:00:00.0\nUpperBound: 2037-01-01 00:00:00.1\n", stripeColStats->toString());
+ }
+
+} // namespace