Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions be/src/vec/columns/column_struct.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,6 @@

namespace doris::vectorized {

namespace ErrorCodes {
extern const int ILLEGAL_COLUMN;
extern const int NOT_IMPLEMENTED;
extern const int CANNOT_INSERT_VALUE_OF_DIFFERENT_SIZE_INTO_TUPLE;
extern const int LOGICAL_ERROR;
} // namespace ErrorCodes

std::string ColumnStruct::get_name() const {
std::stringstream res;
res << "Struct(";
Expand Down
1 change: 0 additions & 1 deletion be/src/vec/columns/column_struct.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ class ColumnStruct final : public COWHelper<IColumn, ColumnStruct> {
bool can_be_inside_nullable() const override { return true; }
MutableColumnPtr clone_empty() const override;
MutableColumnPtr clone_resized(size_t size) const override;

size_t size() const override { return columns.at(0)->size(); }

Field operator[](size_t n) const override;
Expand Down
8 changes: 8 additions & 0 deletions be/src/vec/data_types/data_type_factory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,14 @@ class DataTypeFactory {
return entity.second;
}
}
if (type_ptr->get_type_id() == TypeIndex::Struct) {
DataTypeFactory::instance().register_data_type(type_ptr->get_name(), type_ptr);
for (const auto& entity : _invert_data_type_map) {
if (entity.first->equals(*type_ptr)) {
return entity.second;
}
}
}
return _empty_string;
}

Expand Down
99 changes: 88 additions & 11 deletions be/src/vec/data_types/data_type_struct.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,6 @@

namespace doris::vectorized {

namespace ErrorCodes {
extern const int BAD_ARGUMENTS;
extern const int DUPLICATE_COLUMN;
extern const int EMPTY_DATA_PASSED;
extern const int NOT_FOUND_COLUMN_IN_BLOCK;
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
extern const int SIZES_OF_COLUMNS_IN_TUPLE_DOESNT_MATCH;
extern const int ILLEGAL_INDEX;
extern const int LOGICAL_ERROR;
} // namespace ErrorCodes

DataTypeStruct::DataTypeStruct(const DataTypes& elems_)
: elems(elems_), have_explicit_names(false) {
/// Automatically assigned names in form of '1', '2', ...
Expand Down Expand Up @@ -91,6 +80,94 @@ std::string DataTypeStruct::do_get_name() const {
return s.str();
}

Status DataTypeStruct::from_string(ReadBuffer& rb, IColumn* column) const {
DCHECK(!rb.eof());
auto* struct_column = assert_cast<ColumnStruct*>(column);

if (*rb.position() != '{') {
return Status::InvalidArgument("Struct does not start with '{' character, found '{}'",
*rb.position());
}
if (rb.count() < 2 || *(rb.end() - 1) != '}') {
return Status::InvalidArgument("Struct does not end with '}' character, found '{}'",
*(rb.end() - 1));
}

// here need handle the empty struct '{}'
if (rb.count() == 2) {
return Status::OK();
}

++rb.position();
std::vector<ReadBuffer> field_rbs;
field_rbs.reserve(elems.size());

// here get the value "jack" and 20 from {"name":"jack","age":20}
while (!rb.eof()) {
size_t field_len = 0;
auto start = rb.position();
while (!rb.eof() && *start != ',' && *start != '}') {
field_len++;
start++;
}
if (field_len >= rb.count()) {
return Status::InvalidArgument("Invalid Length");
}
ReadBuffer field_rb(rb.position(), field_len);
size_t len = 0;
auto start_rb = field_rb.position();
while (!field_rb.eof() && *start_rb != ':') {
len++;
start_rb++;
}
ReadBuffer field(field_rb.position() + len + 1, field_rb.count() - len - 1);

if (field.count() < 2 || *field.position() != '"' || *field.end() != '"') {
field_rbs.push_back(field);
} else {
ReadBuffer field_has_quote(field.position() + 1, field.count() - 2);
field_rbs.push_back(field_has_quote);
}

rb.position() += field_len + 1;
}

for (size_t idx = 0; idx < elems.size(); idx++) {
elems[idx]->from_string(field_rbs[idx], &struct_column->get_column(idx));
}

return Status::OK();
}

std::string DataTypeStruct::to_string(const IColumn& column, size_t row_num) const {
auto ptr = column.convert_to_full_column_if_const();
auto& struct_column = assert_cast<const ColumnStruct&>(*ptr.get());

std::stringstream ss;
ss << "<";
for (size_t idx = 0; idx < elems.size(); idx++) {
if (idx != 0) {
ss << ", ";
}
ss << elems[idx]->to_string(struct_column.get_column(idx), row_num);
}
ss << ">";
return ss.str();
}

void DataTypeStruct::to_string(const IColumn& column, size_t row_num, BufferWritable& ostr) const {
auto ptr = column.convert_to_full_column_if_const();
auto& struct_column = assert_cast<const ColumnStruct&>(*ptr.get());
ostr.write("<", 1);
for (size_t idx = 0; idx < elems.size(); idx++) {
if (idx != 0) {
ostr.write(", ", 2);
}
elems[idx]->to_string(struct_column.get_column(idx), row_num, ostr);
}
ostr.write(">", 1);
}

static inline IColumn& extract_element_column(IColumn& column, size_t idx) {
return assert_cast<ColumnStruct&>(column).get_column(idx);
}
Expand Down
3 changes: 3 additions & 0 deletions be/src/vec/data_types/data_type_struct.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ class DataTypeStruct final : public IDataType {
const char* deserialize(const char* buf, IColumn* column, int be_exec_version) const override;
void to_pb_column_meta(PColumnMeta* col_meta) const override;

Status from_string(ReadBuffer& rb, IColumn* column) const override;
std::string to_string(const IColumn& column, size_t row_num) const override;
void to_string(const IColumn& column, size_t row_num, BufferWritable& ostr) const override;
// bool is_parametric() const { return true; }
// SerializationPtr do_get_default_serialization() const override;
// SerializationPtr get_serialization(const SerializationInfo& info) const override;
Expand Down
13 changes: 12 additions & 1 deletion be/src/vec/functions/function_cast.h
Original file line number Diff line number Diff line change
Expand Up @@ -1512,6 +1512,16 @@ class FunctionCast final : public IFunctionBase {
return &ConvertImplGenericToJsonb::execute;
}
}
// check struct value type and get to_type value
// TODO: need handle another type to cast struct
WrapperType create_struct_wrapper(const DataTypePtr& from_type,
const DataTypeStruct& to_type) const {
switch (from_type->get_type_id()) {
case TypeIndex::String:
default:
return &ConvertImplGenericFromString<ColumnString>::execute;
}
}

WrapperType prepare_unpack_dictionaries(const DataTypePtr& from_type,
const DataTypePtr& to_type) const {
Expand Down Expand Up @@ -1680,6 +1690,8 @@ class FunctionCast final : public IFunctionBase {
return create_string_wrapper(from_type);
case TypeIndex::Array:
return create_array_wrapper(from_type, static_cast<const DataTypeArray&>(*to_type));
case TypeIndex::Struct:
return create_struct_wrapper(from_type, static_cast<const DataTypeStruct&>(*to_type));
default:
break;
}
Expand Down Expand Up @@ -1725,7 +1737,6 @@ class FunctionBuilderCast : public FunctionBuilderImpl {
// TODO(xy): support return struct type for factory
auto type = DataTypeFactory::instance().get(type_col->get_value<String>());
DCHECK(type != nullptr);

bool need_to_be_nullable = false;
// 1. from_type is nullable
need_to_be_nullable |= arguments[0].type->is_nullable();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,9 +318,17 @@ public void analyze() throws AnalysisException {
type, Function.NullableMode.ALWAYS_NULLABLE,
Lists.newArrayList(Type.VARCHAR), false,
"doris::CastFunctions::cast_to_array_val", null, null, true);
} else if (type.isStructType()) {
fn = ScalarFunction.createBuiltin(getFnName(Type.STRUCT),
type, Function.NullableMode.ALWAYS_NULLABLE,
Lists.newArrayList(Type.VARCHAR), false,
"doris::CastFunctions::cast_to_struct_val", null, null, true);
}

if (fn == null) {
if (type.isStructType() && childType.isStringType()) {
return;
}
if (childType.isNull() && Type.canCastTo(childType, type)) {
return;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ private void analyzeNestedType(Type parent, ScalarType child) throws AnalysisExc
// check whether the sub-type is supported
if (!parent.supportSubType(child)) {
throw new AnalysisException(
parent.getPrimitiveType() + "unsupported sub-type: " + child.toSql());
parent.getPrimitiveType() + " unsupported sub-type: " + child.toSql());
}

if (child.getPrimitiveType().isStringType() && !child.isLengthSet()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public class Column implements Writable, GsonPostProcessable {
public static final String DELETE_SIGN = "__DORIS_DELETE_SIGN__";
public static final String SEQUENCE_COL = "__DORIS_SEQUENCE_COL__";
private static final String COLUMN_ARRAY_CHILDREN = "item";
private static final String COLUMN_STRUCT_CHILDREN = "field";
public static final int COLUMN_UNIQUE_ID_INIT_VALUE = -1;

@SerializedName(value = "name")
Expand Down
14 changes: 13 additions & 1 deletion fe/fe-core/src/main/java/org/apache/doris/catalog/Type.java
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,20 @@ public abstract class Type {
arraySubTypes.add(STRING);

structSubTypes = Lists.newArrayList();
structSubTypes.add(INT);
structSubTypes.addAll(numericTypes);
structSubTypes.add(BOOLEAN);
structSubTypes.add(VARCHAR);
structSubTypes.add(STRING);
structSubTypes.add(CHAR);
structSubTypes.add(DATE);
structSubTypes.add(DATETIME);
structSubTypes.add(DATEV2);
structSubTypes.add(DATETIMEV2);
structSubTypes.add(TIME);
structSubTypes.add(TIMEV2);
structSubTypes.add(DECIMAL32);
structSubTypes.add(DECIMAL64);
structSubTypes.add(DECIMAL128);
}

public static ArrayList<ScalarType> getIntegerTypes() {
Expand Down