// 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 "exec/orc_scanner.h" #include "exec/broker_reader.h" #include "exec/local_file_reader.h" #include "exprs/expr.h" #include "runtime/descriptors.h" #include "runtime/exec_env.h" #include "runtime/mem_tracker.h" #include "runtime/raw_value.h" #include "runtime/runtime_state.h" #include "runtime/tuple.h" namespace doris { class ORCFileStream : public orc::InputStream { public: ORCFileStream(FileReader* file, std::string filename) : _file(file), _filename(std::move(filename)) { } ~ORCFileStream() override { if (_file != nullptr) { _file->close(); delete _file; _file = nullptr; } } /** * Get the total length of the file in bytes. */ uint64_t getLength() const override { return _file->size(); } /** * Get the natural size for reads. * @return the number of bytes that should be read at once */ uint64_t getNaturalReadSize() const override { return 128 * 1024; } /** * Read length bytes from the file starting at offset into * the buffer starting at buf. * @param buf the starting position of a buffer. * @param length the number of bytes to read. * @param offset the position in the stream to read from. */ void read(void* buf, uint64_t length, uint64_t offset) override { if (buf == nullptr) { throw orc::ParseError("Buffer is null"); } int64_t bytes_read = 0; int64_t reads = 0; while (bytes_read < length) { Status result = _file->readat(offset, length - bytes_read, &reads, buf); if (!result.ok()) { throw orc::ParseError("Bad read of " + _filename); } if (reads == 0) { break; } bytes_read += reads;// total read bytes offset += reads; buf = (char*) buf + reads; } if (length != bytes_read) { throw orc::ParseError("Short read of " + _filename + ". expected :" + std::to_string(length) + ", actual : " + std::to_string(bytes_read)); } } /** * Get the name of the stream for error messages. */ const std::string& getName() const override { return _filename; } private: FileReader* _file; std::string _filename; }; ORCScanner::ORCScanner(RuntimeState* state, RuntimeProfile* profile, const TBrokerScanRangeParams& params, const std::vector& ranges, const std::vector& broker_addresses, ScannerCounter* counter) : BaseScanner(state, profile, params, counter), _ranges(ranges), _broker_addresses(broker_addresses), // _splittable(params.splittable), _next_range(0), _cur_file_eof(true), _scanner_eof(false), _total_groups(0), _current_group(0), _rows_of_group(0), _current_line_of_group(0) {} ORCScanner::~ORCScanner() { close(); } Status ORCScanner::open() { RETURN_IF_ERROR(BaseScanner::open()); if (!_ranges.empty()) { std::list include_cols; TBrokerRangeDesc range = _ranges[0]; _num_of_columns_from_file = range.__isset.num_of_columns_from_file ? range.num_of_columns_from_file : _src_slot_descs.size(); for (int i = 0; i < _num_of_columns_from_file; i++) { auto slot_desc = _src_slot_descs.at(i); include_cols.push_back(slot_desc->col_name()); } _row_reader_options.include(include_cols); } return Status::OK(); } Status ORCScanner::get_next(Tuple* tuple, MemPool* tuple_pool, bool* eof) { try { SCOPED_TIMER(_read_timer); // Get one line while (!_scanner_eof) { if (_cur_file_eof) { RETURN_IF_ERROR(open_next_reader()); if (_scanner_eof) { *eof = true; return Status::OK(); } else { _cur_file_eof = false; } } if (_current_line_of_group >= _rows_of_group) { // read next stripe if (_current_group >= _total_groups) { _cur_file_eof = true; continue; } _rows_of_group = _reader->getStripe(_current_group)->getNumberOfRows(); _batch = _row_reader->createRowBatch(_rows_of_group); _row_reader->next(*_batch.get()); _current_line_of_group = 0; ++_current_group; } const std::vector &batch_vec = ((orc::StructVectorBatch*) _batch.get())->fields; for (int column_ipos = 0; column_ipos < _num_of_columns_from_file; ++column_ipos) { auto slot_desc = _src_slot_descs[column_ipos]; orc::ColumnVectorBatch *cvb = batch_vec[_position_in_orc_original[column_ipos]]; if (cvb->hasNulls && !cvb->notNull[_current_line_of_group]) { if (!slot_desc->is_nullable()) { std::stringstream str_error; str_error << "The field name(" << slot_desc->col_name() << ") is not nullable "; LOG(WARNING) << str_error.str(); return Status::InternalError(str_error.str()); } _src_tuple->set_null(slot_desc->null_indicator_offset()); } else { int32_t wbytes = 0; uint8_t tmp_buf[128] = {0}; if (slot_desc->is_nullable()) { _src_tuple->set_not_null(slot_desc->null_indicator_offset()); } void* slot = _src_tuple->get_slot(slot_desc->tuple_offset()); StringValue* str_slot = reinterpret_cast(slot); switch (_row_reader->getSelectedType().getSubtype(_position_in_orc_original[column_ipos])->getKind()) { case orc::BOOLEAN: { int64_t value = ((orc::LongVectorBatch*) cvb)->data[_current_line_of_group]; if (value == 0) { str_slot->ptr = reinterpret_cast(tuple_pool->allocate(5)); memcpy(str_slot->ptr, "false", 5); str_slot->len = 5; } else { str_slot->ptr = reinterpret_cast(tuple_pool->allocate(4)); memcpy(str_slot->ptr, "true", 4); str_slot->len = 4; } break; } case orc::INT: case orc::SHORT: case orc::LONG: case orc::DATE: { int64_t value = ((orc::LongVectorBatch*) cvb)->data[_current_line_of_group]; wbytes = sprintf((char*) tmp_buf, "%ld", value); str_slot->ptr = reinterpret_cast(tuple_pool->allocate(wbytes)); memcpy(str_slot->ptr, tmp_buf, wbytes); str_slot->len = wbytes; break; } case orc::FLOAT: case orc::DOUBLE: { double value = ((orc::DoubleVectorBatch*) cvb)->data[_current_line_of_group]; wbytes = sprintf((char*) tmp_buf, "%f", value); str_slot->ptr = reinterpret_cast(tuple_pool->allocate(wbytes)); memcpy(str_slot->ptr, tmp_buf, wbytes); str_slot->len = wbytes; break; } case orc::BINARY: case orc::CHAR: case orc::VARCHAR: case orc::STRING: { char *value = ((orc::StringVectorBatch*) cvb)->data[_current_line_of_group]; wbytes = ((orc::StringVectorBatch*) cvb)->length[_current_line_of_group]; str_slot->ptr = reinterpret_cast(tuple_pool->allocate(wbytes)); memcpy(str_slot->ptr, value, wbytes); str_slot->len = wbytes; break; } case orc::DECIMAL: { int precision = ((orc::Decimal64VectorBatch*) cvb)->precision; int scale = ((orc::Decimal64VectorBatch*) cvb)->scale; //Decimal64VectorBatch handles decimal columns with precision no greater than 18. //Decimal128VectorBatch handles the others. std::string decimal_str; if (precision <= 18) { decimal_str = std::to_string(((orc::Decimal64VectorBatch*) cvb)->values[_current_line_of_group]); } else { decimal_str = ((orc::Decimal128VectorBatch*) cvb)->values[_current_line_of_group].toString(); } //Orc api will fill in 0 at the end, so size must greater than scale std::string v = decimal_str.substr(0, decimal_str.size() - scale) + "." + decimal_str.substr(decimal_str.size() - scale); str_slot->ptr = reinterpret_cast(tuple_pool->allocate(v.size())); memcpy(str_slot->ptr, v.c_str(), v.size()); str_slot->len = v.size(); break; } case orc::TIMESTAMP: { int64_t timestamp = ((orc::TimestampVectorBatch*) cvb)->data[_current_line_of_group]; std::string timezone = _state->timezone(); DateTimeValue dtv; if (!dtv.from_unixtime(timestamp, timezone)) { std::stringstream str_error; str_error << "Parse timestamp (" + std::to_string(timestamp) + ") error"; LOG(WARNING) << str_error.str(); return Status::InternalError(str_error.str()); } char* buf_end = dtv.to_string((char*) tmp_buf); wbytes = buf_end - (char*) tmp_buf -1; str_slot->ptr = reinterpret_cast(tuple_pool->allocate(wbytes)); memcpy(str_slot->ptr, tmp_buf, wbytes); str_slot->len = wbytes; break; } default: { std::stringstream str_error; str_error << "The field name(" << slot_desc->col_name() << ") type not support. "; LOG(WARNING) << str_error.str(); return Status::InternalError(str_error.str()); } } } } ++_current_line_of_group; // range of current file const TBrokerRangeDesc& range = _ranges.at(_next_range - 1); if (range.__isset.num_of_columns_from_file) { fill_slots_of_columns_from_path(range.num_of_columns_from_file, range.columns_from_path); } COUNTER_UPDATE(_rows_read_counter, 1); SCOPED_TIMER(_materialize_timer); if (fill_dest_tuple(Slice(), tuple, tuple_pool)) { break; // get one line, break from while } // else skip this line and continue get_next to return } return Status::OK(); } catch (orc::ParseError& e) { std::stringstream str_error; str_error << "ParseError : " << e.what(); LOG(WARNING) << str_error.str(); return Status::InternalError(str_error.str()); } catch (orc::InvalidArgument& e) { std::stringstream str_error; str_error << "ParseError : " << e.what(); LOG(WARNING) << str_error.str(); return Status::InternalError(str_error.str()); } } Status ORCScanner::open_next_reader() { while (true) { if (_next_range >= _ranges.size()) { _scanner_eof = true; return Status::OK(); } const TBrokerRangeDesc& range = _ranges[_next_range++]; std::unique_ptr file_reader; switch (range.file_type) { case TFileType::FILE_LOCAL: { file_reader.reset(new LocalFileReader(range.path, range.start_offset)); break; } case TFileType::FILE_BROKER: { int64_t file_size = 0; // for compatibility if (range.__isset.file_size) { file_size = range.file_size; } file_reader.reset(new BrokerReader(_state->exec_env(), _broker_addresses, _params.properties, range.path, range.start_offset, file_size)); break; } default: { std::stringstream ss; ss << "Unknown file type, type=" << range.file_type; return Status::InternalError(ss.str()); } } RETURN_IF_ERROR(file_reader->open()); if (file_reader->size() == 0) { file_reader->close(); continue; } std::unique_ptr inStream = std::unique_ptr( new ORCFileStream(file_reader.release(), range.path)); _reader = orc::createReader(std::move(inStream), _options); _total_groups = _reader->getNumberOfStripes(); _current_group = 0; _rows_of_group = 0; _current_line_of_group = 0; _row_reader = _reader->createRowReader(_row_reader_options); //include_colus is in loader columns order, and batch is in the orc order _position_in_orc_original.clear(); _position_in_orc_original.resize(_num_of_columns_from_file); int orc_index = 0; auto include_cols = _row_reader_options.getIncludeNames(); for (int i = 0; i < _row_reader->getSelectedType().getSubtypeCount(); ++i) { //include columns must in reader field, otherwise createRowReader will throw exception auto pos = std::find(include_cols.begin(), include_cols.end(), _row_reader->getSelectedType().getFieldName(i)); _position_in_orc_original.at(std::distance(include_cols.begin(), pos)) = orc_index++; } return Status::OK(); } } void ORCScanner::close() { _batch = nullptr; _reader.reset(nullptr); _row_reader.reset(nullptr); } }