blob: 036eeba2b4f60e6b6ec7407e30e54518e81c1c87 [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 "expressions/scalar/ScalarAttribute.hpp"
#include <string>
#include <utility>
#include <vector>
#include "catalog/CatalogAttribute.hpp"
#include "catalog/CatalogRelationSchema.hpp"
#include "catalog/CatalogTypedefs.hpp"
#include "expressions/Expressions.pb.h"
#include "storage/StorageBlockInfo.hpp"
#include "storage/ValueAccessor.hpp"
#include "storage/ValueAccessorUtil.hpp"
#include "types/Type.hpp"
#include "types/TypedValue.hpp"
#include "types/containers/ColumnVector.hpp"
#include "utility/Macros.hpp"
#include "glog/logging.h"
namespace quickstep {
ScalarAttribute::ScalarAttribute(const CatalogAttribute &attribute)
: Scalar(attribute.getType()),
attribute_(attribute) {
}
serialization::Scalar ScalarAttribute::getProto() const {
serialization::Scalar proto;
proto.set_data_source(serialization::Scalar::ATTRIBUTE);
proto.SetExtension(serialization::ScalarAttribute::relation_id, attribute_.getParent().getID());
proto.SetExtension(serialization::ScalarAttribute::attribute_id, attribute_.getID());
return proto;
}
Scalar* ScalarAttribute::clone() const {
return new ScalarAttribute(attribute_);
}
TypedValue ScalarAttribute::getValueForSingleTuple(const ValueAccessor &accessor,
const tuple_id tuple) const {
return accessor.getTypedValueAtAbsolutePositionVirtual(attribute_.getID(), tuple);
}
TypedValue ScalarAttribute::getValueForJoinedTuples(
const ValueAccessor &left_accessor,
const relation_id left_relation_id,
const tuple_id left_tuple_id,
const ValueAccessor &right_accessor,
const relation_id right_relation_id,
const tuple_id right_tuple_id) const {
// FIXME(chasseur): This can get confused and break for self-joins.
DCHECK((attribute_.getParent().getID() == left_relation_id)
|| (attribute_.getParent().getID() == right_relation_id));
if (attribute_.getParent().getID() == left_relation_id) {
return left_accessor.getTypedValueAtAbsolutePositionVirtual(attribute_.getID(),
left_tuple_id);
} else {
return right_accessor.getTypedValueAtAbsolutePositionVirtual(attribute_.getID(),
right_tuple_id);
}
}
attribute_id ScalarAttribute::getAttributeIdForValueAccessor() const {
return attribute_.getID();
}
relation_id ScalarAttribute::getRelationIdForValueAccessor() const {
return attribute_.getParent().getID();
}
ColumnVectorPtr ScalarAttribute::getAllValues(
ValueAccessor *accessor,
const SubBlocksReference *sub_blocks_ref,
ColumnVectorCache *cv_cache) const {
const attribute_id attr_id = attribute_.getID();
const Type &result_type = attribute_.getType();
return InvokeOnValueAccessorMaybeTupleIdSequenceAdapter(
accessor,
[&attr_id, &result_type](auto *accessor) -> ColumnVectorPtr { // NOLINT(build/c++11)
if (NativeColumnVector::UsableForType(result_type)) {
NativeColumnVector *result = new NativeColumnVector(result_type,
accessor->getNumTuples());
accessor->beginIteration();
if (result_type.isNullable()) {
if (accessor->isColumnAccessorSupported()) {
// If ColumnAccessor is supported on the underlying accessor, we have a fast strided
// column accessor available for the iteration on the underlying block.
// Since the attributes can be null, ColumnAccessor template takes a 'true' argument.
std::unique_ptr<const ColumnAccessor<true>>
column_accessor(accessor->template getColumnAccessor<true>(attr_id));
while (accessor->next()) {
const void *value = column_accessor->getUntypedValue(); // Fast strided access.
if (value == nullptr) {
result->appendNullValue();
} else {
result->appendUntypedValue(value);
}
}
} else {
while (accessor->next()) {
const void *value = accessor->template getUntypedValue<true>(attr_id);
if (value == nullptr) {
result->appendNullValue();
} else {
result->appendUntypedValue(value);
}
}
}
} else {
if (accessor->isColumnAccessorSupported()) {
// Since the attributes cannot be null, ColumnAccessor template takes a 'false' argument.
std::unique_ptr<const ColumnAccessor<false>>
column_accessor(accessor->template getColumnAccessor<false>(attr_id));
while (accessor->next()) {
result->appendUntypedValue(column_accessor->getUntypedValue()); // Fast strided access.
}
} else {
while (accessor->next()) {
result->appendUntypedValue(
accessor->template getUntypedValue<false>(attr_id));
}
}
}
return ColumnVectorPtr(result);
} else {
IndirectColumnVector *result = new IndirectColumnVector(result_type,
accessor->getNumTuples());
accessor->beginIteration();
while (accessor->next()) {
result->appendTypedValue(accessor->getTypedValue(attr_id));
}
return ColumnVectorPtr(result);
}
});
}
ColumnVectorPtr ScalarAttribute::getAllValuesForJoin(
const relation_id left_relation_id,
ValueAccessor *left_accessor,
const relation_id right_relation_id,
ValueAccessor *right_accessor,
const std::vector<std::pair<tuple_id, tuple_id>> &joined_tuple_ids,
ColumnVectorCache *cv_cache) const {
DCHECK((attribute_.getParent().getID() == left_relation_id)
|| (attribute_.getParent().getID() == right_relation_id));
const attribute_id attr_id = attribute_.getID();
const Type &result_type = attribute_.getType();
const bool using_left_relation = (attribute_.getParent().getID() == left_relation_id);
ValueAccessor *accessor = using_left_relation ? left_accessor
: right_accessor;
return InvokeOnAnyValueAccessor(
accessor,
[&joined_tuple_ids,
&attr_id,
&result_type,
&using_left_relation](auto *accessor) -> ColumnVectorPtr { // NOLINT(build/c++11)
if (NativeColumnVector::UsableForType(result_type)) {
NativeColumnVector *result = new NativeColumnVector(result_type,
joined_tuple_ids.size());
if (result_type.isNullable()) {
for (const std::pair<tuple_id, tuple_id> &joined_pair : joined_tuple_ids) {
const void *value = accessor->template getUntypedValueAtAbsolutePosition<true>(
attr_id,
using_left_relation ? joined_pair.first : joined_pair.second);
if (value == nullptr) {
result->appendNullValue();
} else {
result->appendUntypedValue(value);
}
}
} else {
for (const std::pair<tuple_id, tuple_id> &joined_pair : joined_tuple_ids) {
result->appendUntypedValue(
accessor->template getUntypedValueAtAbsolutePosition<false>(
attr_id,
using_left_relation ? joined_pair.first : joined_pair.second));
}
}
return ColumnVectorPtr(result);
} else {
IndirectColumnVector *result = new IndirectColumnVector(result_type,
joined_tuple_ids.size());
for (const std::pair<tuple_id, tuple_id> &joined_pair : joined_tuple_ids) {
result->appendTypedValue(
accessor->getTypedValueAtAbsolutePosition(
attr_id,
using_left_relation ? joined_pair.first : joined_pair.second));
}
return ColumnVectorPtr(result);
}
});
}
void ScalarAttribute::getFieldStringItems(
std::vector<std::string> *inline_field_names,
std::vector<std::string> *inline_field_values,
std::vector<std::string> *non_container_child_field_names,
std::vector<const Expression*> *non_container_child_fields,
std::vector<std::string> *container_child_field_names,
std::vector<std::vector<const Expression*>> *container_child_fields) const {
Scalar::getFieldStringItems(inline_field_names,
inline_field_values,
non_container_child_field_names,
non_container_child_fields,
container_child_field_names,
container_child_fields);
inline_field_names->emplace_back("attribute");
inline_field_values->emplace_back(std::to_string(attribute_.getID()));
}
} // namespace quickstep