blob: 9f23f15af5d32f0b78137180a1423884dfa63a37 [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 "types/operations/unary_operations/DateExtractOperation.hpp"
#include <cstddef>
#include <cstdint>
#include <memory>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
#include "catalog/CatalogTypedefs.hpp"
#include "storage/StorageBlockInfo.hpp"
#include "storage/ValueAccessor.hpp"
#include "storage/ValueAccessorUtil.hpp"
#include "types/DatetimeLit.hpp"
#include "types/IntType.hpp"
#include "types/LongType.hpp"
#include "types/Type.hpp"
#include "types/TypeFactory.hpp"
#include "types/TypeID.hpp"
#include "types/TypedValue.hpp"
#include "types/containers/ColumnVector.hpp"
#include "types/operations/Operation.pb.h"
#include "utility/Macros.hpp"
#include "glog/logging.h"
using std::int32_t;
using std::int64_t;
namespace quickstep {
template <DateExtractUnit unit, bool argument_nullable>
TypedValue DatetimeExtractUncheckedOperator<unit, argument_nullable>::applyToTypedValue(
const TypedValue &argument) const {
if (argument_nullable && argument.isNull()) {
return TypedValue(kLong);
}
return TypedValue(dateExtract(argument.getLiteral<DatetimeLit>()));
}
template <DateExtractUnit unit, bool argument_nullable>
TypedValue DateExtractUncheckedOperator<unit, argument_nullable>::applyToTypedValue(
const TypedValue &argument) const {
if (argument_nullable && argument.isNull()) {
return TypedValue(kInt);
}
return TypedValue(dateExtract(argument.getLiteral<DateLit>()));
}
template <DateExtractUnit unit, bool argument_nullable>
TypedValue DatetimeExtractUncheckedOperator<unit, argument_nullable>::applyToDataPtr(const void *argument) const {
if (argument_nullable && argument == nullptr) {
return TypedValue(kLong);
}
return TypedValue(dateExtract(*static_cast<const DatetimeLit*>(argument)));
}
template <DateExtractUnit unit, bool argument_nullable>
TypedValue DateExtractUncheckedOperator<unit, argument_nullable>::applyToDataPtr(const void *argument) const {
if (argument_nullable && argument == nullptr) {
return TypedValue(kInt);
}
return TypedValue(dateExtract(*static_cast<const DateLit*>(argument)));
}
template <DateExtractUnit unit, bool argument_nullable>
ColumnVector* DatetimeExtractUncheckedOperator<unit, argument_nullable>::applyToColumnVector(
const ColumnVector &argument) const {
// Datetime are usable with NativeColumnVector, so 'argument' should always
// be native.
DCHECK(argument.isNative());
const NativeColumnVector &native_argument = static_cast<const NativeColumnVector&>(argument);
std::unique_ptr<NativeColumnVector> result(
new NativeColumnVector(LongType::Instance(argument_nullable), native_argument.size()));
for (std::size_t pos = 0;
pos < native_argument.size();
++pos) {
const DatetimeLit *datetime_arg =
static_cast<const DatetimeLit*>(native_argument.getUntypedValue<argument_nullable>(pos));
if (argument_nullable && (datetime_arg == nullptr)) {
result->appendNullValue();
} else {
*static_cast<int64_t*>(result->getPtrForDirectWrite())
= dateExtract(*datetime_arg);
}
}
return result.release();
}
template <DateExtractUnit unit, bool argument_nullable>
ColumnVector* DateExtractUncheckedOperator<unit, argument_nullable>::applyToColumnVector(
const ColumnVector &argument) const {
// Date is usable with NativeColumnVector, so 'argument' should always
// be native.
DCHECK(argument.isNative());
const NativeColumnVector &native_argument = static_cast<const NativeColumnVector&>(argument);
std::unique_ptr<NativeColumnVector> result(
new NativeColumnVector(IntType::Instance(argument_nullable), native_argument.size()));
for (std::size_t pos = 0;
pos < native_argument.size();
++pos) {
const DateLit *date_arg =
static_cast<const DateLit*>(native_argument.getUntypedValue<argument_nullable>(pos));
if (argument_nullable && (date_arg == nullptr)) {
result->appendNullValue();
} else {
*static_cast<int32_t*>(result->getPtrForDirectWrite())
= dateExtract(*date_arg);
}
}
return result.release();
}
#ifdef QUICKSTEP_ENABLE_VECTOR_COPY_ELISION_SELECTION
template <DateExtractUnit unit, bool argument_nullable>
ColumnVector* DatetimeExtractUncheckedOperator<unit, argument_nullable>::applyToValueAccessor(
ValueAccessor *accessor,
const attribute_id argument_attr_id) const {
return InvokeOnValueAccessorMaybeTupleIdSequenceAdapter(
accessor,
[&](auto *accessor) -> ColumnVector* { // NOLINT(build/c++11)
std::unique_ptr<NativeColumnVector> result(
new NativeColumnVector(LongType::Instance(argument_nullable), accessor->getNumTuples()));
accessor->beginIteration();
while (accessor->next()) {
const DatetimeLit *datetime_arg =
static_cast<const DatetimeLit*>(
accessor->template getUntypedValue<argument_nullable>(argument_attr_id));
if (argument_nullable && (datetime_arg == nullptr)) {
result->appendNullValue();
} else {
*static_cast<int64_t*>(result->getPtrForDirectWrite())
= this->dateExtract(*datetime_arg);
}
}
return result.release();
});
}
template <DateExtractUnit unit, bool argument_nullable>
ColumnVector* DateExtractUncheckedOperator<unit, argument_nullable>::applyToValueAccessor(
ValueAccessor *accessor,
const attribute_id argument_attr_id) const {
return InvokeOnValueAccessorMaybeTupleIdSequenceAdapter(
accessor,
[&](auto *accessor) -> ColumnVector* { // NOLINT(build/c++11)
std::unique_ptr<NativeColumnVector> result(
new NativeColumnVector(IntType::Instance(argument_nullable), accessor->getNumTuples()));
accessor->beginIteration();
while (accessor->next()) {
const DateLit *date_arg =
static_cast<const DateLit*>(
accessor->template getUntypedValue<argument_nullable>(argument_attr_id));
if (argument_nullable && (date_arg == nullptr)) {
result->appendNullValue();
} else {
*static_cast<int32_t*>(result->getPtrForDirectWrite())
= this->dateExtract(*date_arg);
}
}
return result.release();
});
}
#endif // QUICKSTEP_ENABLE_VECTOR_COPY_ELISION_SELECTION
#ifdef QUICKSTEP_ENABLE_VECTOR_COPY_ELISION_JOIN
template <DateExtractUnit unit, bool argument_nullable>
ColumnVector* DatetimeExtractUncheckedOperator<unit, argument_nullable>::applyToValueAccessorForJoin(
ValueAccessor *accessor,
const bool use_left_relation,
const attribute_id argument_attr_id,
const std::vector<std::pair<tuple_id, tuple_id>> &joined_tuple_ids) const {
std::unique_ptr<NativeColumnVector> result(
new NativeColumnVector(LongType::Instance(argument_nullable), joined_tuple_ids.size()));
return InvokeOnValueAccessorNotAdapter(
accessor,
[&](auto *accessor) -> ColumnVector* { // NOLINT(build/c++11)
for (const std::pair<tuple_id, tuple_id> &joined_pair : joined_tuple_ids) {
const DatetimeLit *datetime_arg =
static_cast<const DatetimeLit*>(
accessor->template getUntypedValueAtAbsolutePosition<argument_nullable>(
argument_attr_id,
use_left_relation ? joined_pair.first : joined_pair.second));
if (argument_nullable && (datetime_arg == nullptr)) {
result->appendNullValue();
} else {
*static_cast<int64_t*>(result->getPtrForDirectWrite())
= this->dateExtract(*datetime_arg);
}
}
return result.release();
});
}
template <DateExtractUnit unit, bool argument_nullable>
ColumnVector* DateExtractUncheckedOperator<unit, argument_nullable>::applyToValueAccessorForJoin(
ValueAccessor *accessor,
const bool use_left_relation,
const attribute_id argument_attr_id,
const std::vector<std::pair<tuple_id, tuple_id>> &joined_tuple_ids) const {
std::unique_ptr<NativeColumnVector> result(
new NativeColumnVector(IntType::Instance(argument_nullable), joined_tuple_ids.size()));
return InvokeOnValueAccessorNotAdapter(
accessor,
[&](auto *accessor) -> ColumnVector* { // NOLINT(build/c++11)
for (const std::pair<tuple_id, tuple_id> &joined_pair : joined_tuple_ids) {
const DateLit *date_arg =
static_cast<const DateLit*>(
accessor->template getUntypedValueAtAbsolutePosition<argument_nullable>(
argument_attr_id,
use_left_relation ? joined_pair.first : joined_pair.second));
if (argument_nullable && (date_arg == nullptr)) {
result->appendNullValue();
} else {
*static_cast<int32_t*>(result->getPtrForDirectWrite())
= this->dateExtract(*date_arg);
}
}
return result.release();
});
}
#endif // QUICKSTEP_ENABLE_VECTOR_COPY_ELISION_JOIN
template <DateExtractUnit unit, bool argument_nullable>
inline int64_t
DatetimeExtractUncheckedOperator<unit, argument_nullable>::dateExtract(
const DatetimeLit &argument) const {
switch (unit) {
case DateExtractUnit::kYear:
return argument.yearField();
case DateExtractUnit::kMonth:
return argument.monthField();
case DateExtractUnit::kDay:
return argument.dayField();
case DateExtractUnit::kHour:
return argument.hourField();
case DateExtractUnit::kMinute:
return argument.minuteField();
case DateExtractUnit::kSecond:
return argument.secondField();
default:
FATAL_ERROR("Unsupported DateExtractUnit in DatetimeExtractUncheckedOperator::dateExtract.");
}
}
template <DateExtractUnit unit, bool argument_nullable>
inline int32_t DateExtractUncheckedOperator<unit, argument_nullable>::dateExtract(const DateLit &argument) const {
switch (unit) {
case DateExtractUnit::kYear:
return argument.yearField();
case DateExtractUnit::kMonth:
return argument.monthField();
default:
FATAL_ERROR("Unsupported DateExtractUnit in DateExtractUncheckedOperator::dateExtract.");
}
}
const DateExtractOperation& DateExtractOperation::Instance(const DateExtractUnit unit) {
switch (unit) {
case DateExtractUnit::kYear: {
static DateExtractOperation instance(DateExtractUnit::kYear);
return instance;
}
case DateExtractUnit::kMonth: {
static DateExtractOperation instance(DateExtractUnit::kMonth);
return instance;
}
case DateExtractUnit::kDay: {
static DateExtractOperation instance(DateExtractUnit::kDay);
return instance;
}
case DateExtractUnit::kHour: {
static DateExtractOperation instance(DateExtractUnit::kHour);
return instance;
}
case DateExtractUnit::kMinute: {
static DateExtractOperation instance(DateExtractUnit::kMinute);
return instance;
}
case DateExtractUnit::kSecond: {
static DateExtractOperation instance(DateExtractUnit::kSecond);
return instance;
}
default: {
FATAL_ERROR("Unsupported DateExtractUnit in DateExtractOperation::Instance.");
}
}
}
serialization::UnaryOperation DateExtractOperation::getProto() const {
serialization::UnaryOperation proto;
proto.set_operation_id(serialization::UnaryOperation::DATE_EXTRACT);
switch (unit_) {
case DateExtractUnit::kYear:
proto.SetExtension(serialization::DateExtractOperation::unit, serialization::DateExtractOperation::YEAR);
break;
case DateExtractUnit::kMonth:
proto.SetExtension(serialization::DateExtractOperation::unit, serialization::DateExtractOperation::MONTH);
break;
case DateExtractUnit::kDay:
proto.SetExtension(serialization::DateExtractOperation::unit, serialization::DateExtractOperation::DAY);
break;
case DateExtractUnit::kHour:
proto.SetExtension(serialization::DateExtractOperation::unit, serialization::DateExtractOperation::HOUR);
break;
case DateExtractUnit::kMinute:
proto.SetExtension(serialization::DateExtractOperation::unit, serialization::DateExtractOperation::MINUTE);
break;
case DateExtractUnit::kSecond:
proto.SetExtension(serialization::DateExtractOperation::unit, serialization::DateExtractOperation::SECOND);
break;
default:
FATAL_ERROR("Unsupported DateExtractUnit in DateExtractOperation::getProto.");
}
return proto;
}
std::string DateExtractOperation::getName() const {
std::string name(kUnaryOperationNames[static_cast<std::size_t>(operation_id_)]);
name.push_back('(');
switch (unit_) {
case DateExtractUnit::kYear:
name.append("YEAR)");
break;
case DateExtractUnit::kMonth:
name.append("MONTH)");
break;
case DateExtractUnit::kDay:
name.append("DAY)");
break;
case DateExtractUnit::kHour:
name.append("HOUR)");
break;
case DateExtractUnit::kMinute:
name.append("MINUTE)");
break;
case DateExtractUnit::kSecond:
name.append("SECOND)");
break;
default:
name.append("UNKNOWN)");
break;
}
return name;
}
const Type* DateExtractOperation::pushDownTypeHint(const Type *type_hint) const {
if (type_hint == nullptr) {
return nullptr;
}
if (type_hint->getTypeID() == kLong) {
switch (unit_) {
case DateExtractUnit::kYear: // Fall through.
case DateExtractUnit::kMonth:
// There are two possibilities for the return type, based on whether we
// have Datetime or Date as the underlying date implementation.
return nullptr;
case DateExtractUnit::kDay: // Fall through.
case DateExtractUnit::kHour:
case DateExtractUnit::kMinute:
case DateExtractUnit::kSecond:
return &TypeFactory::GetType(kDatetime, type_hint->isNullable());
default:
return nullptr;
}
} else {
return nullptr;
}
}
TypedValue DateExtractOperation::applyToChecked(const TypedValue &argument,
const Type &argument_type) const {
if (((argument.getTypeID() != TypeID::kDatetime) ||
(argument_type.getTypeID() != TypeID::kDatetime)) &&
((argument.getTypeID() != TypeID::kDate) ||
(argument_type.getTypeID() != TypeID::kDate))) {
LOG(FATAL) << "UnaryOperation " << getName() << " is only applicable to Type "
<< kTypeNames[TypeID::kDatetime] << ", but applyToChecked() was "
<< "called with 'argument' of Type " << kTypeNames[argument.getTypeID()]
<< " and explicit 'argument_type' parameter of "
<< argument_type.getName();
}
if (argument.isNull()) {
if (argument.getTypeID() == TypeID::kDatetime) {
return TypedValue(kLong);
} else {
// argument type is kDate.
DCHECK_EQ(TypeID::kDate, argument.getTypeID());
return TypedValue(kInt);
}
}
switch (unit_) {
case DateExtractUnit::kYear: {
if (argument.getTypeID() == TypeID::kDatetime) {
return TypedValue(argument.getLiteral<DatetimeLit>().yearField());
} else {
// argument type is kDate.
DCHECK_EQ(TypeID::kDate, argument.getTypeID());
return TypedValue(argument.getLiteral<DateLit>().yearField());
}
}
case DateExtractUnit::kMonth: {
if (argument.getTypeID() == TypeID::kDatetime) {
return TypedValue(argument.getLiteral<DatetimeLit>().monthField());
} else {
// argument type is kDate.
DCHECK_EQ(TypeID::kDate, argument.getTypeID());
return TypedValue(argument.getLiteral<DateLit>().monthField());
}
}
case DateExtractUnit::kDay:
return TypedValue(argument.getLiteral<DatetimeLit>().dayField());
case DateExtractUnit::kHour:
return TypedValue(argument.getLiteral<DatetimeLit>().hourField());
case DateExtractUnit::kMinute:
return TypedValue(argument.getLiteral<DatetimeLit>().minuteField());
case DateExtractUnit::kSecond:
return TypedValue(argument.getLiteral<DatetimeLit>().secondField());
default: {
LOG(FATAL) << "Unsupported DateExtractUnit in DateExtractOperation::applyToChecked().";
}
}
}
UncheckedUnaryOperator* DateExtractOperation::makeUncheckedUnaryOperatorForTypeHelper(const Type &type) const {
switch (unit_) {
case DateExtractUnit::kYear: {
if (type.getTypeID() == TypeID::kDatetime) {
if (type.isNullable()) {
return new DatetimeExtractUncheckedOperator<DateExtractUnit::kYear, true>();
} else {
return new DatetimeExtractUncheckedOperator<DateExtractUnit::kYear, false>();
}
} else {
DCHECK_EQ(TypeID::kDate, type.getTypeID());
// type is kDate.
if (type.isNullable()) {
return new DateExtractUncheckedOperator<DateExtractUnit::kYear, true>();
} else {
return new DateExtractUncheckedOperator<DateExtractUnit::kYear, false>();
}
}
}
case DateExtractUnit::kMonth: {
if (type.getTypeID() == TypeID::kDatetime) {
if (type.isNullable()) {
return new DatetimeExtractUncheckedOperator<DateExtractUnit::kMonth, true>();
} else {
return new DatetimeExtractUncheckedOperator<DateExtractUnit::kMonth, false>();
}
} else {
// type is kDate.
DCHECK_EQ(TypeID::kDate, type.getTypeID());
if (type.isNullable()) {
return new DateExtractUncheckedOperator<DateExtractUnit::kMonth, true>();
} else {
return new DateExtractUncheckedOperator<DateExtractUnit::kMonth, false>();
}
}
}
case DateExtractUnit::kDay:
if (type.isNullable()) {
return new DatetimeExtractUncheckedOperator<DateExtractUnit::kDay, true>();
} else {
return new DatetimeExtractUncheckedOperator<DateExtractUnit::kDay, false>();
}
case DateExtractUnit::kHour:
if (type.isNullable()) {
return new DatetimeExtractUncheckedOperator<DateExtractUnit::kHour, true>();
} else {
return new DatetimeExtractUncheckedOperator<DateExtractUnit::kHour, false>();
}
case DateExtractUnit::kMinute:
if (type.isNullable()) {
return new DatetimeExtractUncheckedOperator<DateExtractUnit::kMinute, true>();
} else {
return new DatetimeExtractUncheckedOperator<DateExtractUnit::kMinute, false>();
}
case DateExtractUnit::kSecond:
if (type.isNullable()) {
return new DatetimeExtractUncheckedOperator<DateExtractUnit::kSecond, true>();
} else {
return new DatetimeExtractUncheckedOperator<DateExtractUnit::kSecond, false>();
}
default:
FATAL_ERROR("Unsupported DateExtractUnit in DateExtractOperation::makeUncheckedUnaryOperatorForTypeHelper.");
}
}
const Type* DateExtractOperation::resultTypeForArgumentType(const Type &type) const {
if (canApplyToType(type)) {
if (type.getTypeID() == kDatetime) {
return &LongType::Instance(type.isNullable());
} else {
DCHECK_EQ(kDate, type.getTypeID());
return &IntType::Instance(type.isNullable());
}
} else {
return nullptr;
}
}
} // namespace quickstep