blob: 84f1c8db9a90ad6fcd87751cbc5cae1b43b89c76 [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/SubstringOperation.hpp"
#include <algorithm>
#include <tuple>
#include <utility>
#include <vector>
#include "catalog/CatalogTypedefs.hpp"
#include "storage/ValueAccessor.hpp"
#include "storage/ValueAccessorUtil.hpp"
#include "types/Type.hpp"
#include "types/TypeID.hpp"
#include "types/TypedValue.hpp"
#include "types/containers/ColumnVector.hpp"
#include "types/containers/ColumnVectorUtil.hpp"
#include "types/operations/Operation.pb.h"
#include "types/port/strnlen.hpp"
#include "utility/TemplateUtil.hpp"
#include "glog/logging.h"
namespace quickstep {
serialization::UnaryOperation SubstringOperation::getProto() const {
serialization::UnaryOperation proto;
proto.set_operation_id(serialization::UnaryOperation::SUBSTRING);
proto.SetExtension(serialization::SubstringOperation::start_position,
start_position_);
proto.SetExtension(serialization::SubstringOperation::substring_length,
substring_length_);
return proto;
}
UncheckedUnaryOperator* SubstringOperation::makeUncheckedUnaryOperatorForType(
const Type &type) const {
DCHECK(type.getSuperTypeID() == Type::kAsciiString);
const std::size_t input_maximum_length =
static_cast<const AsciiStringSuperType&>(type).getStringLength();
const bool input_null_terminated = (type.getTypeID() == TypeID::kVarChar);
const Type *result_type = resultTypeForArgumentType(type);
DCHECK(result_type != nullptr);
return CreateBoolInstantiatedInstance<SubstringUncheckedOperator, UncheckedUnaryOperator>(
std::forward_as_tuple(start_position_,
computeMaximumSubstringLength(type),
input_maximum_length,
*result_type),
input_null_terminated, type.isNullable());
}
template <bool null_terminated, bool input_nullable>
inline void SubstringUncheckedOperator<null_terminated, input_nullable>
::computeSubstring(const char *input,
char *output) const {
std::size_t string_length =
(null_terminated ? strlen(input) : strnlen(input, maximum_input_length_));
if (start_position_ >= string_length) {
*output = '\0';
return;
}
const std::size_t actual_substring_length =
std::min(string_length - start_position_, substring_length_);
std::memcpy(output, input + start_position_, actual_substring_length);
if (actual_substring_length < substring_length_) {
output[actual_substring_length] = '\0';
}
}
template <bool null_terminated, bool input_nullable>
TypedValue SubstringUncheckedOperator<null_terminated,
input_nullable>
::applyToTypedValue(const TypedValue& argument) const {
if (input_nullable && argument.isNull()) {
return TypedValue(result_type_.getTypeID());
}
char *output_ptr = static_cast<char*>(std::malloc(substring_length_));
computeSubstring(static_cast<const char*>(argument.getOutOfLineData()),
output_ptr);
return TypedValue::CreateWithOwnedData(result_type_.getTypeID(),
output_ptr,
substring_length_);
}
template <bool null_terminated, bool input_nullable>
TypedValue SubstringUncheckedOperator<null_terminated,
input_nullable>
::applyToDataPtr(const void *argument) const {
if (input_nullable && argument == nullptr) {
return TypedValue(result_type_.getTypeID());
}
char *output_ptr = static_cast<char*>(std::malloc(substring_length_));
computeSubstring(static_cast<const char*>(argument),
output_ptr);
return TypedValue::CreateWithOwnedData(result_type_.getTypeID(),
output_ptr,
substring_length_);
}
template <bool null_terminated, bool input_nullable>
ColumnVector* SubstringUncheckedOperator<null_terminated,
input_nullable>
::applyToColumnVector(const ColumnVector &argument) const {
return InvokeOnColumnVector(
argument,
[&](const auto &column_vector) -> ColumnVector* { // NOLINT(build/c++11)
NativeColumnVector *result =
new NativeColumnVector(result_type_, column_vector.size());
for (std::size_t cv_pos = 0;
cv_pos < column_vector.size();
++cv_pos) {
const char *input_ptr = static_cast<const char *>(
column_vector.template getUntypedValue<input_nullable>(cv_pos));
if (input_nullable && input_ptr == nullptr) {
result->appendNullValue();
} else {
this->computeSubstring(input_ptr,
static_cast<char *>(result->getPtrForDirectWrite()));
}
}
return result;
});
}
#ifdef QUICKSTEP_ENABLE_VECTOR_COPY_ELISION_SELECTION
template <bool null_terminated, bool input_nullable>
ColumnVector* SubstringUncheckedOperator<null_terminated,
input_nullable>
::applyToValueAccessor(ValueAccessor *accessor,
const attribute_id argument_attr_id) const {
return InvokeOnValueAccessorMaybeTupleIdSequenceAdapter(
accessor,
[&](auto *accessor) -> ColumnVector* { // NOLINT(build/c++11)
NativeColumnVector *result =
new NativeColumnVector(result_type_, accessor->getNumTuples());
accessor->beginIteration();
while (accessor->next()) {
const char *input_ptr = static_cast<const char *>(
accessor->template getUntypedValue<input_nullable>(argument_attr_id));
if (input_nullable && (input_ptr == nullptr)) {
result->appendNullValue();
} else {
this->computeSubstring(input_ptr,
static_cast<char *>(result->getPtrForDirectWrite()));
}
}
return result;
});
}
#endif
#ifdef QUICKSTEP_ENABLE_VECTOR_COPY_ELISION_JOIN
template <bool null_terminated, bool input_nullable>
ColumnVector* SubstringUncheckedOperator<null_terminated,
input_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 {
return InvokeOnValueAccessorNotAdapter(
accessor,
[&](auto *accessor) -> ColumnVector* { // NOLINT(build/c++11)
NativeColumnVector *result =
new NativeColumnVector(result_type_, accessor->getNumTuples());
for (const std::pair<tuple_id, tuple_id> &joined_pair : joined_tuple_ids) {
const char *input_ptr = static_cast<const char *>(
accessor->template getUntypedValueAtAbsolutePosition<input_nullable>(
argument_attr_id,
use_left_relation ? joined_pair.first : joined_pair.second));
if (input_nullable && input_ptr == nullptr) {
result->appendNullValue();
} else {
this->computeSubstring(input_ptr,
static_cast<char *>(result->getPtrForDirectWrite()));
}
}
return result;
});
}
#endif
} // namespace quickstep