blob: d0cd4ae27a16b588ac703091f64a84e53e6c597f [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 "jni_data_bridge.h"
#include <glog/logging.h>
#include <sstream>
#include <variant>
#include "core/block/block.h"
#include "core/column/column_array.h"
#include "core/column/column_map.h"
#include "core/column/column_nullable.h"
#include "core/column/column_string.h"
#include "core/column/column_struct.h"
#include "core/column/column_varbinary.h"
#include "core/data_type/data_type_array.h"
#include "core/data_type/data_type_map.h"
#include "core/data_type/data_type_nullable.h"
#include "core/data_type/data_type_struct.h"
#include "core/data_type/data_type_varbinary.h"
#include "core/data_type/define_primitive_type.h"
#include "core/data_type/primitive_type.h"
#include "core/types.h"
#include "core/value/decimalv2_value.h"
namespace doris {
#include "common/compile_check_begin.h"
#define FOR_FIXED_LENGTH_TYPES(M) \
M(PrimitiveType::TYPE_TINYINT, ColumnInt8, Int8) \
M(PrimitiveType::TYPE_BOOLEAN, ColumnUInt8, UInt8) \
M(PrimitiveType::TYPE_SMALLINT, ColumnInt16, Int16) \
M(PrimitiveType::TYPE_INT, ColumnInt32, Int32) \
M(PrimitiveType::TYPE_BIGINT, ColumnInt64, Int64) \
M(PrimitiveType::TYPE_LARGEINT, ColumnInt128, Int128) \
M(PrimitiveType::TYPE_FLOAT, ColumnFloat32, Float32) \
M(PrimitiveType::TYPE_DOUBLE, ColumnFloat64, Float64) \
M(PrimitiveType::TYPE_DECIMALV2, ColumnDecimal128V2, Int128) \
M(PrimitiveType::TYPE_DECIMAL128I, ColumnDecimal128V3, Int128) \
M(PrimitiveType::TYPE_DECIMAL32, ColumnDecimal32, Int32) \
M(PrimitiveType::TYPE_DECIMAL64, ColumnDecimal64, Int64) \
M(PrimitiveType::TYPE_DATE, ColumnDate, Int64) \
M(PrimitiveType::TYPE_DATEV2, ColumnDateV2, UInt32) \
M(PrimitiveType::TYPE_DATETIME, ColumnDateTime, Int64) \
M(PrimitiveType::TYPE_DATETIMEV2, ColumnDateTimeV2, UInt64) \
M(PrimitiveType::TYPE_TIMESTAMPTZ, ColumnTimeStampTz, UInt64) \
M(PrimitiveType::TYPE_IPV4, ColumnIPv4, IPv4) \
M(PrimitiveType::TYPE_IPV6, ColumnIPv6, IPv6)
Status JniDataBridge::fill_block(Block* block, const ColumnNumbers& arguments, long table_address) {
if (table_address == 0) {
return Status::InternalError("table_address is 0");
}
TableMetaAddress table_meta(table_address);
long num_rows = table_meta.next_meta_as_long();
for (size_t i : arguments) {
if (block->get_by_position(i).column.get() == nullptr) {
auto return_type = block->get_data_type(i);
bool result_nullable = return_type->is_nullable();
ColumnUInt8::MutablePtr null_col = nullptr;
if (result_nullable) {
return_type = remove_nullable(return_type);
null_col = ColumnUInt8::create();
}
auto res_col = return_type->create_column();
if (result_nullable) {
block->replace_by_position(
i, ColumnNullable::create(std::move(res_col), std::move(null_col)));
} else {
block->replace_by_position(i, std::move(res_col));
}
} else if (is_column_const(*(block->get_by_position(i).column))) {
auto doris_column = block->get_by_position(i).column->convert_to_full_column_if_const();
bool is_nullable = block->get_by_position(i).type->is_nullable();
block->replace_by_position(i, is_nullable ? make_nullable(doris_column) : doris_column);
}
auto& column_with_type_and_name = block->get_by_position(i);
auto& column_ptr = column_with_type_and_name.column;
auto& column_type = column_with_type_and_name.type;
RETURN_IF_ERROR(fill_column(table_meta, column_ptr, column_type, num_rows));
}
return Status::OK();
}
Status JniDataBridge::fill_column(TableMetaAddress& address, ColumnPtr& doris_column,
const DataTypePtr& data_type, size_t num_rows) {
auto logical_type = data_type->get_primitive_type();
void* null_map_ptr = address.next_meta_as_ptr();
if (null_map_ptr == nullptr) {
// org.apache.doris.common.jni.vec.ColumnType.Type#UNSUPPORTED will set column address as 0
return Status::InternalError("Unsupported type {} in java side", data_type->get_name());
}
MutableColumnPtr data_column;
if (doris_column->is_nullable()) {
auto* nullable_column =
reinterpret_cast<ColumnNullable*>(doris_column->assume_mutable().get());
data_column = nullable_column->get_nested_column_ptr();
NullMap& null_map = nullable_column->get_null_map_data();
size_t origin_size = null_map.size();
null_map.resize(origin_size + num_rows);
memcpy(null_map.data() + origin_size, static_cast<bool*>(null_map_ptr), num_rows);
} else {
data_column = doris_column->assume_mutable();
}
// Date and DateTime are deprecated and not supported.
switch (logical_type) {
#define DISPATCH(TYPE_INDEX, COLUMN_TYPE, CPP_TYPE) \
case TYPE_INDEX: \
return _fill_fixed_length_column<COLUMN_TYPE, CPP_TYPE>( \
data_column, reinterpret_cast<CPP_TYPE*>(address.next_meta_as_ptr()), num_rows);
FOR_FIXED_LENGTH_TYPES(DISPATCH)
#undef DISPATCH
case PrimitiveType::TYPE_STRING:
[[fallthrough]];
case PrimitiveType::TYPE_CHAR:
[[fallthrough]];
case PrimitiveType::TYPE_VARCHAR:
return _fill_string_column(address, data_column, num_rows);
case PrimitiveType::TYPE_ARRAY:
return _fill_array_column(address, data_column, data_type, num_rows);
case PrimitiveType::TYPE_MAP:
return _fill_map_column(address, data_column, data_type, num_rows);
case PrimitiveType::TYPE_STRUCT:
return _fill_struct_column(address, data_column, data_type, num_rows);
case PrimitiveType::TYPE_VARBINARY:
return _fill_varbinary_column(address, data_column, num_rows);
default:
return Status::InvalidArgument("Unsupported type {} in jni scanner", data_type->get_name());
}
return Status::OK();
}
Status JniDataBridge::_fill_varbinary_column(TableMetaAddress& address,
MutableColumnPtr& doris_column, size_t num_rows) {
auto* meta_base = reinterpret_cast<char*>(address.next_meta_as_ptr());
auto& varbinary_col = assert_cast<ColumnVarbinary&>(*doris_column);
// Java side writes per-row metadata as 16 bytes: [len: long][addr: long]
for (size_t i = 0; i < num_rows; ++i) {
// Read length (first 8 bytes)
int64_t len = 0;
memcpy(&len, meta_base + 16 * i, sizeof(len));
if (len <= 0) {
varbinary_col.insert_default();
} else {
// Read address (next 8 bytes)
uint64_t addr_u = 0;
memcpy(&addr_u, meta_base + 16 * i + 8, sizeof(addr_u));
const char* src = reinterpret_cast<const char*>(addr_u);
varbinary_col.insert_data(src, static_cast<size_t>(len));
}
}
return Status::OK();
}
Status JniDataBridge::_fill_string_column(TableMetaAddress& address, MutableColumnPtr& doris_column,
size_t num_rows) {
auto& string_col = static_cast<ColumnString&>(*doris_column);
ColumnString::Chars& string_chars = string_col.get_chars();
ColumnString::Offsets& string_offsets = string_col.get_offsets();
int* offsets = reinterpret_cast<int*>(address.next_meta_as_ptr());
char* chars = reinterpret_cast<char*>(address.next_meta_as_ptr());
// This judgment is necessary, otherwise the following statement `offsets[num_rows - 1]` out of bounds
// What's more, This judgment must be placed after `address.next_meta_as_ptr()`
// because `address.next_meta_as_ptr` will make `address._meta_index` plus 1
if (num_rows == 0) {
return Status::OK();
}
size_t origin_chars_size = string_chars.size();
string_chars.resize(origin_chars_size + offsets[num_rows - 1]);
memcpy(string_chars.data() + origin_chars_size, chars, offsets[num_rows - 1]);
size_t origin_offsets_size = string_offsets.size();
size_t start_offset = string_offsets[origin_offsets_size - 1];
string_offsets.resize(origin_offsets_size + num_rows);
for (size_t i = 0; i < num_rows; ++i) {
string_offsets[origin_offsets_size + i] =
static_cast<unsigned int>(offsets[i] + start_offset);
}
return Status::OK();
}
Status JniDataBridge::_fill_array_column(TableMetaAddress& address, MutableColumnPtr& doris_column,
const DataTypePtr& data_type, size_t num_rows) {
ColumnPtr& element_column = static_cast<ColumnArray&>(*doris_column).get_data_ptr();
const DataTypePtr& element_type =
(assert_cast<const DataTypeArray*>(remove_nullable(data_type).get()))
->get_nested_type();
ColumnArray::Offsets64& offsets_data = static_cast<ColumnArray&>(*doris_column).get_offsets();
int64_t* offsets = reinterpret_cast<int64_t*>(address.next_meta_as_ptr());
size_t origin_size = offsets_data.size();
offsets_data.resize(origin_size + num_rows);
size_t start_offset = offsets_data[origin_size - 1];
for (size_t i = 0; i < num_rows; ++i) {
offsets_data[origin_size + i] = offsets[i] + start_offset;
}
return fill_column(address, element_column, element_type,
offsets_data[origin_size + num_rows - 1] - start_offset);
}
Status JniDataBridge::_fill_map_column(TableMetaAddress& address, MutableColumnPtr& doris_column,
const DataTypePtr& data_type, size_t num_rows) {
auto& map = static_cast<ColumnMap&>(*doris_column);
const DataTypePtr& key_type =
reinterpret_cast<const DataTypeMap*>(remove_nullable(data_type).get())->get_key_type();
const DataTypePtr& value_type =
reinterpret_cast<const DataTypeMap*>(remove_nullable(data_type).get())
->get_value_type();
ColumnPtr& key_column = map.get_keys_ptr();
ColumnPtr& value_column = map.get_values_ptr();
ColumnArray::Offsets64& map_offsets = map.get_offsets();
int64_t* offsets = reinterpret_cast<int64_t*>(address.next_meta_as_ptr());
size_t origin_size = map_offsets.size();
map_offsets.resize(origin_size + num_rows);
size_t start_offset = map_offsets[origin_size - 1];
for (size_t i = 0; i < num_rows; ++i) {
map_offsets[origin_size + i] = offsets[i] + start_offset;
}
RETURN_IF_ERROR(fill_column(address, key_column, key_type,
map_offsets[origin_size + num_rows - 1] - start_offset));
RETURN_IF_ERROR(fill_column(address, value_column, value_type,
map_offsets[origin_size + num_rows - 1] - start_offset));
return Status::OK();
}
Status JniDataBridge::_fill_struct_column(TableMetaAddress& address, MutableColumnPtr& doris_column,
const DataTypePtr& data_type, size_t num_rows) {
auto& doris_struct = static_cast<ColumnStruct&>(*doris_column);
const DataTypeStruct* doris_struct_type =
reinterpret_cast<const DataTypeStruct*>(remove_nullable(data_type).get());
for (int i = 0; i < doris_struct.tuple_size(); ++i) {
ColumnPtr& struct_field = doris_struct.get_column_ptr(i);
const DataTypePtr& field_type = doris_struct_type->get_element(i);
RETURN_IF_ERROR(fill_column(address, struct_field, field_type, num_rows));
}
return Status::OK();
}
std::string JniDataBridge::get_jni_type(const DataTypePtr& data_type) {
DataTypePtr type = remove_nullable(data_type);
std::ostringstream buffer;
switch (type->get_primitive_type()) {
case TYPE_BOOLEAN:
return "boolean";
case TYPE_TINYINT:
return "tinyint";
case TYPE_SMALLINT:
return "smallint";
case TYPE_INT:
return "int";
case TYPE_BIGINT:
return "bigint";
case TYPE_LARGEINT:
return "largeint";
case TYPE_FLOAT:
return "float";
case TYPE_DOUBLE:
return "double";
case TYPE_IPV4:
return "ipv4";
case TYPE_IPV6:
return "ipv6";
case TYPE_VARCHAR:
[[fallthrough]];
case TYPE_CHAR:
[[fallthrough]];
case TYPE_STRING:
return "string";
case TYPE_DATE:
return "datev1";
case TYPE_DATEV2:
return "datev2";
case TYPE_DATETIME:
return "datetimev1";
case TYPE_DATETIMEV2:
[[fallthrough]];
case TYPE_TIMEV2: {
buffer << "datetimev2(" << type->get_scale() << ")";
return buffer.str();
}
case TYPE_TIMESTAMPTZ: {
buffer << "timestamptz(" << type->get_scale() << ")";
return buffer.str();
}
case TYPE_BINARY:
return "binary";
case TYPE_DECIMALV2: {
buffer << "decimalv2(" << DecimalV2Value::PRECISION << "," << DecimalV2Value::SCALE << ")";
return buffer.str();
}
case TYPE_DECIMAL32: {
buffer << "decimal32(" << type->get_precision() << "," << type->get_scale() << ")";
return buffer.str();
}
case TYPE_DECIMAL64: {
buffer << "decimal64(" << type->get_precision() << "," << type->get_scale() << ")";
return buffer.str();
}
case TYPE_DECIMAL128I: {
buffer << "decimal128(" << type->get_precision() << "," << type->get_scale() << ")";
return buffer.str();
}
case TYPE_STRUCT: {
const DataTypeStruct* struct_type = reinterpret_cast<const DataTypeStruct*>(type.get());
buffer << "struct<";
for (int i = 0; i < struct_type->get_elements().size(); ++i) {
if (i != 0) {
buffer << ",";
}
buffer << struct_type->get_element_names()[i] << ":"
<< get_jni_type(struct_type->get_element(i));
}
buffer << ">";
return buffer.str();
}
case TYPE_ARRAY: {
const DataTypeArray* array_type = reinterpret_cast<const DataTypeArray*>(type.get());
buffer << "array<" << get_jni_type(array_type->get_nested_type()) << ">";
return buffer.str();
}
case TYPE_MAP: {
const DataTypeMap* map_type = reinterpret_cast<const DataTypeMap*>(type.get());
buffer << "map<" << get_jni_type(map_type->get_key_type()) << ","
<< get_jni_type(map_type->get_value_type()) << ">";
return buffer.str();
}
case TYPE_VARBINARY:
return "varbinary";
// bitmap, hll, quantile_state, jsonb are transferred as strings via JNI
case TYPE_BITMAP:
[[fallthrough]];
case TYPE_HLL:
[[fallthrough]];
case TYPE_QUANTILE_STATE:
[[fallthrough]];
case TYPE_JSONB:
return "string";
default:
return "unsupported";
}
}
std::string JniDataBridge::get_jni_type_with_different_string(const DataTypePtr& data_type) {
DataTypePtr type = remove_nullable(data_type);
std::ostringstream buffer;
switch (data_type->get_primitive_type()) {
case TYPE_BOOLEAN:
return "boolean";
case TYPE_TINYINT:
return "tinyint";
case TYPE_SMALLINT:
return "smallint";
case TYPE_INT:
return "int";
case TYPE_BIGINT:
return "bigint";
case TYPE_LARGEINT:
return "largeint";
case TYPE_FLOAT:
return "float";
case TYPE_DOUBLE:
return "double";
case TYPE_IPV4:
return "ipv4";
case TYPE_IPV6:
return "ipv6";
case TYPE_VARCHAR: {
buffer << "varchar("
<< assert_cast<const DataTypeString*>(remove_nullable(data_type).get())->len()
<< ")";
return buffer.str();
}
case TYPE_DATE:
return "datev1";
case TYPE_DATEV2:
return "datev2";
case TYPE_DATETIME:
return "datetimev1";
case TYPE_DATETIMEV2:
[[fallthrough]];
case TYPE_TIMEV2: {
buffer << "datetimev2(" << data_type->get_scale() << ")";
return buffer.str();
}
case TYPE_TIMESTAMPTZ: {
buffer << "timestamptz(" << data_type->get_scale() << ")";
return buffer.str();
}
case TYPE_BINARY:
return "binary";
case TYPE_CHAR: {
buffer << "char("
<< assert_cast<const DataTypeString*>(remove_nullable(data_type).get())->len()
<< ")";
return buffer.str();
}
case TYPE_STRING:
return "string";
case TYPE_VARBINARY:
buffer << "varbinary("
<< assert_cast<const DataTypeVarbinary*>(remove_nullable(data_type).get())->len()
<< ")";
return buffer.str();
case TYPE_DECIMALV2: {
buffer << "decimalv2(" << DecimalV2Value::PRECISION << "," << DecimalV2Value::SCALE << ")";
return buffer.str();
}
case TYPE_DECIMAL32: {
buffer << "decimal32(" << data_type->get_precision() << "," << data_type->get_scale()
<< ")";
return buffer.str();
}
case TYPE_DECIMAL64: {
buffer << "decimal64(" << data_type->get_precision() << "," << data_type->get_scale()
<< ")";
return buffer.str();
}
case TYPE_DECIMAL128I: {
buffer << "decimal128(" << data_type->get_precision() << "," << data_type->get_scale()
<< ")";
return buffer.str();
}
case TYPE_STRUCT: {
const auto* type_struct =
assert_cast<const DataTypeStruct*>(remove_nullable(data_type).get());
buffer << "struct<";
for (int i = 0; i < type_struct->get_elements().size(); ++i) {
if (i != 0) {
buffer << ",";
}
buffer << type_struct->get_element_name(i) << ":"
<< get_jni_type_with_different_string(type_struct->get_element(i));
}
buffer << ">";
return buffer.str();
}
case TYPE_ARRAY: {
const auto* type_arr = assert_cast<const DataTypeArray*>(remove_nullable(data_type).get());
buffer << "array<" << get_jni_type_with_different_string(type_arr->get_nested_type())
<< ">";
return buffer.str();
}
case TYPE_MAP: {
const auto* type_map = assert_cast<const DataTypeMap*>(remove_nullable(data_type).get());
buffer << "map<" << get_jni_type_with_different_string(type_map->get_key_type()) << ","
<< get_jni_type_with_different_string(type_map->get_value_type()) << ">";
return buffer.str();
}
// bitmap, hll, quantile_state, jsonb are transferred as strings via JNI
case TYPE_BITMAP:
[[fallthrough]];
case TYPE_HLL:
[[fallthrough]];
case TYPE_QUANTILE_STATE:
[[fallthrough]];
case TYPE_JSONB:
return "string";
default:
return "unsupported";
}
}
Status JniDataBridge::_fill_column_meta(const ColumnPtr& doris_column, const DataTypePtr& data_type,
std::vector<long>& meta_data) {
auto logical_type = data_type->get_primitive_type();
const IColumn* column = nullptr;
// insert const flag
if (is_column_const(*doris_column)) {
meta_data.emplace_back((long)1);
const auto& const_column = assert_cast<const ColumnConst&>(*doris_column);
column = &(const_column.get_data_column());
} else {
meta_data.emplace_back((long)0);
column = &(*doris_column);
}
// insert null map address
const IColumn* data_column = nullptr;
if (column->is_nullable()) {
const auto& nullable_column = assert_cast<const ColumnNullable&>(*column);
data_column = &(nullable_column.get_nested_column());
const auto& null_map = nullable_column.get_null_map_data();
meta_data.emplace_back((long)null_map.data());
} else {
meta_data.emplace_back(0);
data_column = column;
}
switch (logical_type) {
#define DISPATCH(TYPE_INDEX, COLUMN_TYPE, CPP_TYPE) \
case TYPE_INDEX: { \
meta_data.emplace_back(_get_fixed_length_column_address<COLUMN_TYPE>(*data_column)); \
break; \
}
FOR_FIXED_LENGTH_TYPES(DISPATCH)
#undef DISPATCH
case PrimitiveType::TYPE_STRING:
[[fallthrough]];
case PrimitiveType::TYPE_CHAR:
[[fallthrough]];
case PrimitiveType::TYPE_VARCHAR: {
const auto& string_column = assert_cast<const ColumnString&>(*data_column);
// insert offsets
meta_data.emplace_back((long)string_column.get_offsets().data());
meta_data.emplace_back((long)string_column.get_chars().data());
break;
}
case PrimitiveType::TYPE_ARRAY: {
const auto& element_column = assert_cast<const ColumnArray&>(*data_column).get_data_ptr();
meta_data.emplace_back(
(long)assert_cast<const ColumnArray&>(*data_column).get_offsets().data());
const auto& element_type = assert_cast<const DataTypePtr&>(
(assert_cast<const DataTypeArray*>(remove_nullable(data_type).get()))
->get_nested_type());
RETURN_IF_ERROR(_fill_column_meta(element_column, element_type, meta_data));
break;
}
case PrimitiveType::TYPE_STRUCT: {
const auto& doris_struct = assert_cast<const ColumnStruct&>(*data_column);
const auto* doris_struct_type =
assert_cast<const DataTypeStruct*>(remove_nullable(data_type).get());
for (int i = 0; i < doris_struct.tuple_size(); ++i) {
const auto& struct_field = doris_struct.get_column_ptr(i);
const auto& field_type =
assert_cast<const DataTypePtr&>(doris_struct_type->get_element(i));
RETURN_IF_ERROR(_fill_column_meta(struct_field, field_type, meta_data));
}
break;
}
case PrimitiveType::TYPE_MAP: {
const auto& map = assert_cast<const ColumnMap&>(*data_column);
const auto& key_type = assert_cast<const DataTypePtr&>(
assert_cast<const DataTypeMap*>(remove_nullable(data_type).get())->get_key_type());
const auto& value_type = assert_cast<const DataTypePtr&>(
assert_cast<const DataTypeMap*>(remove_nullable(data_type).get())
->get_value_type());
const auto& key_column = map.get_keys_ptr();
const auto& value_column = map.get_values_ptr();
meta_data.emplace_back((long)map.get_offsets().data());
RETURN_IF_ERROR(_fill_column_meta(key_column, key_type, meta_data));
RETURN_IF_ERROR(_fill_column_meta(value_column, value_type, meta_data));
break;
}
case PrimitiveType::TYPE_VARBINARY: {
const auto& varbinary_col = assert_cast<const ColumnVarbinary&>(*data_column);
meta_data.emplace_back(
(long)assert_cast<const ColumnVarbinary&>(varbinary_col).get_data().data());
break;
}
default:
return Status::InternalError("Unsupported type: {}", data_type->get_name());
}
return Status::OK();
}
Status JniDataBridge::to_java_table(Block* block, std::unique_ptr<long[]>& meta) {
ColumnNumbers arguments;
for (size_t i = 0; i < block->columns(); ++i) {
arguments.emplace_back(i);
}
return to_java_table(block, block->rows(), arguments, meta);
}
Status JniDataBridge::to_java_table(Block* block, size_t num_rows, const ColumnNumbers& arguments,
std::unique_ptr<long[]>& meta) {
std::vector<long> meta_data;
// insert number of rows
meta_data.emplace_back(num_rows);
for (size_t i : arguments) {
auto& column_with_type_and_name = block->get_by_position(i);
RETURN_IF_ERROR(_fill_column_meta(column_with_type_and_name.column,
column_with_type_and_name.type, meta_data));
}
meta.reset(new long[meta_data.size()]);
memcpy(meta.get(), &meta_data[0], meta_data.size() * 8);
return Status::OK();
}
std::pair<std::string, std::string> JniDataBridge::parse_table_schema(
Block* block, const ColumnNumbers& arguments, bool ignore_column_name) {
// prepare table schema
std::ostringstream required_fields;
std::ostringstream columns_types;
for (int i = 0; i < arguments.size(); ++i) {
std::string type = JniDataBridge::get_jni_type(block->get_by_position(arguments[i]).type);
if (i == 0) {
if (ignore_column_name) {
required_fields << "_col_" << arguments[i];
} else {
required_fields << block->get_by_position(arguments[i]).name;
}
columns_types << type;
} else {
if (ignore_column_name) {
required_fields << ","
<< "_col_" << arguments[i];
} else {
required_fields << "," << block->get_by_position(arguments[i]).name;
}
columns_types << "#" << type;
}
}
return std::make_pair(required_fields.str(), columns_types.str());
}
std::pair<std::string, std::string> JniDataBridge::parse_table_schema(Block* block) {
ColumnNumbers arguments;
for (size_t i = 0; i < block->columns(); ++i) {
arguments.emplace_back(i);
}
return parse_table_schema(block, arguments, true);
}
#include "common/compile_check_end.h"
} // namespace doris