// 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 "runtime/raw_value.h" #include #include "olap/utils.h" #include "runtime/collection_value.h" #include "runtime/string_value.hpp" #include "runtime/tuple.h" #include "util/types.h" namespace doris { const int RawValue::ASCII_PRECISION = 16; // print 16 digits for double/float void RawValue::print_value_as_bytes(const void* value, const TypeDescriptor& type, std::stringstream* stream) { if (value == NULL) { return; } const char* chars = reinterpret_cast(value); const StringValue* string_val = NULL; switch (type.type) { case TYPE_NULL: break; case TYPE_BOOLEAN: stream->write(chars, sizeof(bool)); return; case TYPE_TINYINT: stream->write(chars, sizeof(int8_t)); break; case TYPE_SMALLINT: stream->write(chars, sizeof(int16_t)); break; case TYPE_INT: stream->write(chars, sizeof(int32_t)); break; case TYPE_BIGINT: stream->write(chars, sizeof(int64_t)); break; case TYPE_FLOAT: stream->write(chars, sizeof(float)); break; case TYPE_DOUBLE: stream->write(chars, sizeof(double)); break; case TYPE_VARCHAR: case TYPE_HLL: case TYPE_CHAR: case TYPE_STRING: string_val = reinterpret_cast(value); stream->write(static_cast(string_val->ptr), string_val->len); return; case TYPE_DATE: case TYPE_DATETIME: stream->write(chars, sizeof(DateTimeValue)); break; case TYPE_DECIMALV2: stream->write(chars, sizeof(DecimalV2Value)); break; case TYPE_LARGEINT: stream->write(chars, sizeof(__int128)); break; default: DCHECK(false) << "bad RawValue::print_value() type: " << type; } } void RawValue::print_value(const void* value, const TypeDescriptor& type, int scale, std::stringstream* stream) { if (value == NULL) { *stream << "NULL"; return; } int old_precision = stream->precision(); std::ios_base::fmtflags old_flags = stream->flags(); if (scale > -1) { stream->precision(scale); // Setting 'fixed' causes precision to set the number of digits printed after the // decimal (by default it sets the maximum number of digits total). *stream << std::fixed; } std::string tmp; const StringValue* string_val = NULL; switch (type.type) { case TYPE_BOOLEAN: { bool val = *reinterpret_cast(value); *stream << (val ? "true" : "false"); return; } case TYPE_TINYINT: // Extra casting for chars since they should not be interpreted as ASCII. *stream << static_cast(*reinterpret_cast(value)); break; case TYPE_SMALLINT: *stream << *reinterpret_cast(value); break; case TYPE_INT: *stream << *reinterpret_cast(value); break; case TYPE_BIGINT: *stream << *reinterpret_cast(value); break; case TYPE_FLOAT: *stream << *reinterpret_cast(value); break; case TYPE_DOUBLE: *stream << *reinterpret_cast(value); break; case TYPE_HLL: case TYPE_CHAR: case TYPE_VARCHAR: case TYPE_STRING: string_val = reinterpret_cast(value); tmp.assign(static_cast(string_val->ptr), string_val->len); *stream << tmp; return; case TYPE_DATE: case TYPE_DATETIME: *stream << *reinterpret_cast(value); break; case TYPE_DECIMALV2: *stream << DecimalV2Value(reinterpret_cast(value)->value).to_string(); break; case TYPE_LARGEINT: *stream << reinterpret_cast(value)->value; break; case TYPE_ARRAY: { const CollectionValue* src = reinterpret_cast(value); auto children_type = type.children.at(0); auto iter = src->iterator(children_type.type); *stream << "["; print_value(iter.value(), children_type, scale, stream); iter.next(); for (; iter.has_next(); iter.next()) { *stream << ", "; print_value(iter.value(), children_type, scale, stream); } *stream << "]"; break; } default: DCHECK(false) << "bad RawValue::print_value() type: " << type; } stream->precision(old_precision); // Undo setting stream to fixed stream->flags(old_flags); } void RawValue::print_value(const void* value, const TypeDescriptor& type, int scale, std::string* str) { if (value == NULL) { *str = "NULL"; return; } std::stringstream out; out.precision(ASCII_PRECISION); const StringValue* string_val = NULL; std::string tmp; bool val = false; // Special case types that we can print more efficiently without using a std::stringstream switch (type.type) { case TYPE_BOOLEAN: val = *reinterpret_cast(value); *str = (val ? "true" : "false"); return; case TYPE_CHAR: case TYPE_VARCHAR: case TYPE_OBJECT: case TYPE_HLL: case TYPE_STRING: { string_val = reinterpret_cast(value); std::stringstream ss; ss << "ptr:" << (void*)string_val->ptr << " len:" << string_val->len; tmp = ss.str(); if (string_val->len <= 1000) { tmp.assign(static_cast(string_val->ptr), string_val->len); } str->swap(tmp); return; } case TYPE_NULL: { *str = "NULL"; return; } default: print_value(value, type, scale, &out); } *str = out.str(); } void RawValue::write(const void* value, void* dst, const TypeDescriptor& type, MemPool* pool) { DCHECK(value != NULL); switch (type.type) { case TYPE_NULL: break; case TYPE_BOOLEAN: { *reinterpret_cast(dst) = *reinterpret_cast(value); break; } case TYPE_TINYINT: { *reinterpret_cast(dst) = *reinterpret_cast(value); break; } case TYPE_SMALLINT: { *reinterpret_cast(dst) = *reinterpret_cast(value); break; } case TYPE_INT: { *reinterpret_cast(dst) = *reinterpret_cast(value); break; } case TYPE_BIGINT: { *reinterpret_cast(dst) = *reinterpret_cast(value); break; } case TYPE_LARGEINT: { *reinterpret_cast(dst) = *reinterpret_cast(value); break; } case TYPE_FLOAT: { *reinterpret_cast(dst) = *reinterpret_cast(value); break; } case TYPE_TIME: case TYPE_DOUBLE: { *reinterpret_cast(dst) = *reinterpret_cast(value); break; } case TYPE_DATE: case TYPE_DATETIME: *reinterpret_cast(dst) = *reinterpret_cast(value); break; case TYPE_DECIMALV2: *reinterpret_cast(dst) = *reinterpret_cast(value); break; case TYPE_OBJECT: case TYPE_HLL: case TYPE_VARCHAR: case TYPE_CHAR: case TYPE_STRING: { const StringValue* src = reinterpret_cast(value); StringValue* dest = reinterpret_cast(dst); dest->len = src->len; if (pool != NULL) { dest->ptr = reinterpret_cast(pool->allocate(dest->len)); memcpy(dest->ptr, src->ptr, dest->len); } else { dest->ptr = src->ptr; } break; } case TYPE_ARRAY: { DCHECK_EQ(type.children.size(), 1); const CollectionValue* src = reinterpret_cast(value); CollectionValue* val = reinterpret_cast(dst); if (pool != NULL) { auto children_type = type.children.at(0).type; CollectionValue::init_collection(pool, src->size(), children_type, val); ArrayIterator src_iter = src->iterator(children_type); ArrayIterator val_iter = val->iterator(children_type); val->copy_null_signs(src); while (src_iter.has_next() && val_iter.has_next()) { if (!src_iter.is_null()) { // write children write(src_iter.value(), val_iter.value(), children_type, pool); } src_iter.next(); val_iter.next(); } } else { val->shallow_copy(src); } break; } default: DCHECK(false) << "RawValue::write(): bad type: " << type; } } // TODO: can we remove some of this code duplication? Templated allocator? void RawValue::write(const void* value, const TypeDescriptor& type, void* dst, uint8_t** buf) { DCHECK(value != NULL); switch (type.type) { case TYPE_BOOLEAN: *reinterpret_cast(dst) = *reinterpret_cast(value); break; case TYPE_TINYINT: *reinterpret_cast(dst) = *reinterpret_cast(value); break; case TYPE_SMALLINT: *reinterpret_cast(dst) = *reinterpret_cast(value); break; case TYPE_INT: *reinterpret_cast(dst) = *reinterpret_cast(value); break; case TYPE_BIGINT: *reinterpret_cast(dst) = *reinterpret_cast(value); break; case TYPE_LARGEINT: *reinterpret_cast(dst) = *reinterpret_cast(value); break; case TYPE_FLOAT: *reinterpret_cast(dst) = *reinterpret_cast(value); break; case TYPE_DOUBLE: *reinterpret_cast(dst) = *reinterpret_cast(value); break; case TYPE_DATE: case TYPE_DATETIME: *reinterpret_cast(dst) = *reinterpret_cast(value); break; case TYPE_VARCHAR: case TYPE_CHAR: case TYPE_STRING: { DCHECK(buf != NULL); const StringValue* src = reinterpret_cast(value); StringValue* dest = reinterpret_cast(dst); dest->len = src->len; dest->ptr = reinterpret_cast(*buf); memcpy(dest->ptr, src->ptr, dest->len); *buf += dest->len; break; } case TYPE_DECIMALV2: *reinterpret_cast(dst) = *reinterpret_cast(value); break; default: DCHECK(false) << "RawValue::write(): bad type: " << type.debug_string(); } } void RawValue::write(const void* value, Tuple* tuple, const SlotDescriptor* slot_desc, MemPool* pool) { if (value == NULL) { tuple->set_null(slot_desc->null_indicator_offset()); } else { void* slot = tuple->get_slot(slot_desc->tuple_offset()); RawValue::write(value, slot, slot_desc->type(), pool); } } } // namespace doris