blob: 8f4dfc4d8721f0a9b66752da317a3348fa9fadfb [file] [log] [blame]
/**
* 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 <cstdint>
#include <limits>
#include <memory>
#include <vector>
#include "types/DatetimeLit.hpp"
#include "types/Type.hpp"
#include "types/TypeFactory.hpp"
#include "types/TypeID.hpp"
#include "types/TypedValue.hpp"
#include "types/operations/Operation.pb.h"
#include "types/operations/unary_operations/DateExtractOperation.hpp"
#include "types/operations/unary_operations/UnaryOperation.hpp"
#include "types/operations/unary_operations/UnaryOperationFactory.hpp"
#include "utility/EqualsAnyConstant.hpp"
#include "gtest/gtest.h"
using std::int64_t;
using std::numeric_limits;
using std::unique_ptr;
using std::vector;
namespace quickstep {
class DateExtractOperationTest : public ::testing::Test {
protected:
virtual void SetUp() {
datetime_literal_.ticks = 1431359664 * DatetimeLit::kTicksPerSecond; // Mon, 11 May 2015 15:54:24 GMT.
datetime_.reset(new TypedValue(datetime_literal_));
datetime_null_.reset(new TypedValue(kDatetime));
date_literal_ = DateLit::Create(2015, 05, 11); // 11 May 2015.
date_.reset(new TypedValue(date_literal_));
date_null_.reset(new TypedValue(kDate));
}
void checkDateExtractOperationSerialization(const DateExtractOperation &operation) {
serialization::UnaryOperation proto = operation.getProto();
EXPECT_EQ(serialization::UnaryOperation::DATE_EXTRACT, proto.operation_id());
EXPECT_TRUE(UnaryOperationFactory::ProtoIsValid(proto));
EXPECT_TRUE(operation.equals(UnaryOperationFactory::ReconstructFromProto(proto)));
}
void checkDatetimeExtract(int64_t expected, const DateExtractUnit unit) {
const DateExtractOperation &operation = DateExtractOperation::Instance(unit);
checkDateExtractOperationSerialization(operation);
EXPECT_EQ(expected,
operation.applyToChecked(*datetime_,
TypeFactory::GetType(kDatetime, true)).getLiteral<int64_t>());
EXPECT_TRUE(operation.applyToChecked(*datetime_null_,
TypeFactory::GetType(kDatetime, true)).isNull());
unchecked_operator_.reset(
operation.makeUncheckedUnaryOperatorForType(TypeFactory::GetType(kDatetime, true)));
EXPECT_EQ(expected, unchecked_operator_->applyToTypedValue(*datetime_).getLiteral<int64_t>());
EXPECT_TRUE(unchecked_operator_->applyToTypedValue(*datetime_null_).isNull());
}
void checkDateExtract(int32_t expected, const DateExtractUnit unit) {
const DateExtractOperation &operation = DateExtractOperation::Instance(unit);
checkDateExtractOperationSerialization(operation);
EXPECT_EQ(expected,
operation.applyToChecked(*date_,
TypeFactory::GetType(kDate, true)).getLiteral<int32_t>());
EXPECT_TRUE(operation.applyToChecked(*date_null_,
TypeFactory::GetType(kDate, true)).isNull());
unchecked_operator_.reset(
operation.makeUncheckedUnaryOperatorForType(TypeFactory::GetType(kDate, true)));
EXPECT_EQ(expected, unchecked_operator_->applyToTypedValue(*date_).getLiteral<int32_t>());
EXPECT_TRUE(unchecked_operator_->applyToTypedValue(*date_null_).isNull());
}
static void CheckFixedNullableResultTypeForField(const DateExtractUnit field) {
const Type *fixed_result_type
= DateExtractOperation::Instance(field).fixedNullableResultType();
ASSERT_EQ(fixed_result_type, nullptr);
}
static void CheckResultTypeIsPlausibleForField(const DateExtractUnit field) {
// Long and Int are plausible.
EXPECT_TRUE(DateExtractOperation::Instance(field).resultTypeIsPlausible(
TypeFactory::GetType(kLong, false)));
EXPECT_TRUE(DateExtractOperation::Instance(field).resultTypeIsPlausible(
TypeFactory::GetType(kLong, true)));
EXPECT_TRUE(DateExtractOperation::Instance(field).resultTypeIsPlausible(
TypeFactory::GetType(kInt, false)));
EXPECT_TRUE(DateExtractOperation::Instance(field).resultTypeIsPlausible(
TypeFactory::GetType(kInt, true)));
for (const TypeID type_id
: {kFloat, kDouble, kDatetime, kDatetimeInterval, kYearMonthInterval}) {
EXPECT_FALSE(DateExtractOperation::Instance(field).resultTypeIsPlausible(
TypeFactory::GetType(type_id, false)));
EXPECT_FALSE(DateExtractOperation::Instance(field).resultTypeIsPlausible(
TypeFactory::GetType(type_id, true)));
}
EXPECT_FALSE(DateExtractOperation::Instance(field).resultTypeIsPlausible(
TypeFactory::GetType(kChar, 10, false)));
EXPECT_FALSE(DateExtractOperation::Instance(field).resultTypeIsPlausible(
TypeFactory::GetType(kChar, 10, true)));
EXPECT_FALSE(DateExtractOperation::Instance(field).resultTypeIsPlausible(
TypeFactory::GetType(kVarChar, 10, false)));
EXPECT_FALSE(DateExtractOperation::Instance(field).resultTypeIsPlausible(
TypeFactory::GetType(kVarChar, 10, true)));
}
static void CheckPushDownTypeHintForField(const DateExtractUnit field) {
const UnaryOperation &op = DateExtractOperation::Instance(field);
// For nullable types.
const Type *argument_hint
= op.pushDownTypeHint(&TypeFactory::GetType(kLong, true));
if ((field == DateExtractUnit::kMonth) || (field == DateExtractUnit::kYear)) {
// If field is either Year or Month, the argument is NULL.
ASSERT_EQ(argument_hint, nullptr);
} else if (QUICKSTEP_EQUALS_ANY_CONSTANT(field,
DateExtractUnit::kDay,
DateExtractUnit::kHour,
DateExtractUnit::kMinute,
DateExtractUnit::kSecond)) {
// Otherwise, if hint is Long, then the argument is a Datetime with the
// same nullability.
ASSERT_NE(argument_hint, nullptr);
EXPECT_TRUE(TypeFactory::GetType(kDatetime, true).equals(*argument_hint));
}
// For non-nullable types.
argument_hint = op.pushDownTypeHint(&TypeFactory::GetType(kLong, false));
if ((field == DateExtractUnit::kMonth) || (field == DateExtractUnit::kYear)) {
// If field is either Year or Month, the argument is NULL.
ASSERT_EQ(argument_hint, nullptr);
} else {
// Otherwise, if hint is Long, then the argument is a Datetime with the
// same nullability.
ASSERT_NE(argument_hint, nullptr);
EXPECT_TRUE(TypeFactory::GetType(kDatetime, false).equals(*argument_hint));
}
// Anything else can't be returned, so there is no hint for argument type.
EXPECT_EQ(nullptr, op.pushDownTypeHint(nullptr));
for (const TypeID type_id
: {kInt, kFloat, kDouble, kDatetime, kDatetimeInterval, kYearMonthInterval}) {
EXPECT_EQ(nullptr, op.pushDownTypeHint(&TypeFactory::GetType(type_id, false)));
EXPECT_EQ(nullptr, op.pushDownTypeHint(&TypeFactory::GetType(type_id, true)));
}
EXPECT_EQ(nullptr, op.pushDownTypeHint(&TypeFactory::GetType(kChar, 10, false)));
EXPECT_EQ(nullptr, op.pushDownTypeHint(&TypeFactory::GetType(kChar, 10, true)));
EXPECT_EQ(nullptr, op.pushDownTypeHint(&TypeFactory::GetType(kVarChar, 10, false)));
EXPECT_EQ(nullptr, op.pushDownTypeHint(&TypeFactory::GetType(kVarChar, 10, true)));
}
DatetimeLit datetime_literal_;
DateLit date_literal_;
unique_ptr<TypedValue> datetime_, datetime_null_;
unique_ptr<TypedValue> date_, date_null_;
unique_ptr<UncheckedUnaryOperator> unchecked_operator_;
};
TEST_F(DateExtractOperationTest, DateTimeExtractUnaryOperationTest) {
checkDatetimeExtract(datetime_literal_.yearField(), DateExtractUnit::kYear);
checkDatetimeExtract(datetime_literal_.monthField(), DateExtractUnit::kMonth);
checkDatetimeExtract(datetime_literal_.dayField(), DateExtractUnit::kDay);
checkDatetimeExtract(datetime_literal_.hourField(), DateExtractUnit::kHour);
checkDatetimeExtract(datetime_literal_.minuteField(), DateExtractUnit::kMinute);
checkDatetimeExtract(datetime_literal_.secondField(), DateExtractUnit::kSecond);
}
TEST_F(DateExtractOperationTest, DateExtractUnaryOperationTest) {
checkDateExtract(date_literal_.yearField(), DateExtractUnit::kYear);
checkDateExtract(date_literal_.monthField(), DateExtractUnit::kMonth);
}
TEST_F(DateExtractOperationTest, FixedNullableResultTypeTest) {
CheckFixedNullableResultTypeForField(DateExtractUnit::kYear);
CheckFixedNullableResultTypeForField(DateExtractUnit::kMonth);
CheckFixedNullableResultTypeForField(DateExtractUnit::kDay);
CheckFixedNullableResultTypeForField(DateExtractUnit::kHour);
CheckFixedNullableResultTypeForField(DateExtractUnit::kMinute);
CheckFixedNullableResultTypeForField(DateExtractUnit::kSecond);
}
TEST_F(DateExtractOperationTest, ResultTypeIsPlausibleTest) {
CheckResultTypeIsPlausibleForField(DateExtractUnit::kYear);
CheckResultTypeIsPlausibleForField(DateExtractUnit::kMonth);
CheckResultTypeIsPlausibleForField(DateExtractUnit::kDay);
CheckResultTypeIsPlausibleForField(DateExtractUnit::kHour);
CheckResultTypeIsPlausibleForField(DateExtractUnit::kMinute);
CheckResultTypeIsPlausibleForField(DateExtractUnit::kSecond);
}
TEST_F(DateExtractOperationTest, PushDownTypeHintTest) {
CheckPushDownTypeHintForField(DateExtractUnit::kYear);
CheckPushDownTypeHintForField(DateExtractUnit::kMonth);
CheckPushDownTypeHintForField(DateExtractUnit::kDay);
CheckPushDownTypeHintForField(DateExtractUnit::kHour);
CheckPushDownTypeHintForField(DateExtractUnit::kMinute);
CheckPushDownTypeHintForField(DateExtractUnit::kSecond);
}
} // namespace quickstep