/src/duckdb/src/function/scalar/struct/struct_pack.cpp
Line | Count | Source |
1 | | #include "duckdb/common/vector/map_vector.hpp" |
2 | | #include "duckdb/common/vector/struct_vector.hpp" |
3 | | #include "duckdb/function/scalar/nested_functions.hpp" |
4 | | #include "duckdb/function/scalar/struct_functions.hpp" |
5 | | #include "duckdb/common/case_insensitive_map.hpp" |
6 | | #include "duckdb/common/string_util.hpp" |
7 | | #include "duckdb/parser/expression/bound_expression.hpp" |
8 | | #include "duckdb/planner/expression/bound_function_expression.hpp" |
9 | | #include "duckdb/planner/expression_binder.hpp" |
10 | | #include "duckdb/storage/statistics/struct_stats.hpp" |
11 | | |
12 | | namespace duckdb { |
13 | | |
14 | 0 | static void StructPackFunction(DataChunk &args, ExpressionState &state, Vector &result) { |
15 | | #ifdef DEBUG |
16 | | auto &func_expr = state.expr.Cast<BoundFunctionExpression>(); |
17 | | auto &info = func_expr.bind_info->Cast<VariableReturnBindData>(); |
18 | | // this should never happen if the binder below is sane |
19 | | D_ASSERT(args.ColumnCount() == StructType::GetChildTypes(info.stype).size()); |
20 | | #endif |
21 | 0 | bool all_const = true; |
22 | 0 | auto &child_entries = StructVector::GetEntries(result); |
23 | 0 | idx_t children_size = 0; |
24 | 0 | for (idx_t i = 0; i < args.ColumnCount(); i++) { |
25 | 0 | if (args.data[i].GetVectorType() != VectorType::CONSTANT_VECTOR) { |
26 | 0 | all_const = false; |
27 | 0 | } |
28 | | // same holds for this |
29 | 0 | child_entries[i].Reference(args.data[i]); |
30 | 0 | children_size = MaxValue<idx_t>(children_size, child_entries[i].size()); |
31 | 0 | } |
32 | | // set only the struct buffer's type/size - do not propagate to children |
33 | | // since children reference external vectors (args) that may have incompatible buffer types. |
34 | | // match the parent size to the (already-set) child vector size, not to the chunk cardinality - those can |
35 | | // differ when the caller is collapsing all-constant inputs to a single argument row. |
36 | 0 | result.BufferMutable().SetVectorTypeOnly(all_const ? VectorType::CONSTANT_VECTOR : VectorType::FLAT_VECTOR); |
37 | 0 | result.BufferMutable().SetVectorSizeOnly(children_size); |
38 | 0 | result.Verify(); |
39 | 0 | } |
40 | | |
41 | | template <bool IS_STRUCT_PACK> |
42 | 0 | static unique_ptr<FunctionData> StructPackBind(BindScalarFunctionInput &input) { |
43 | 0 | auto &bound_function = input.GetBoundFunction(); |
44 | 0 | auto &arguments = input.GetArguments(); |
45 | 0 | case_insensitive_set_t name_collision_set; |
46 | | |
47 | | // collect names and deconflict, construct return type |
48 | 0 | if (arguments.empty()) { |
49 | 0 | throw InvalidInputException("Can't pack nothing into a struct"); |
50 | 0 | } |
51 | 0 | child_list_t<LogicalType> struct_children; |
52 | 0 | for (idx_t i = 0; i < arguments.size(); i++) { |
53 | 0 | auto &child = arguments[i]; |
54 | 0 | string alias; |
55 | 0 | if (IS_STRUCT_PACK) { |
56 | 0 | if (child->GetAlias().empty()) { |
57 | 0 | throw BinderException("Need named argument for struct pack, e.g. STRUCT_PACK(a := b)"); |
58 | 0 | } |
59 | 0 | alias = child->GetAlias(); |
60 | 0 | if (name_collision_set.find(alias) != name_collision_set.end()) { |
61 | 0 | throw BinderException("Duplicate struct entry name \"%s\"", alias); |
62 | 0 | } |
63 | 0 | name_collision_set.insert(alias); |
64 | 0 | } |
65 | 0 | struct_children.push_back(make_pair(alias, arguments[i]->GetReturnType())); |
66 | 0 | } |
67 | | |
68 | | // this is more for completeness reasons |
69 | 0 | bound_function.SetReturnType(LogicalType::STRUCT(struct_children)); |
70 | 0 | return make_uniq<VariableReturnBindData>(bound_function.GetReturnType()); |
71 | 0 | } Unexecuted instantiation: ub_duckdb_func_struct_main.cpp:duckdb::unique_ptr<duckdb::FunctionData, std::__1::default_delete<duckdb::FunctionData>, true> duckdb::StructPackBind<true>(duckdb::BindScalarFunctionInput&) Unexecuted instantiation: ub_duckdb_func_struct_main.cpp:duckdb::unique_ptr<duckdb::FunctionData, std::__1::default_delete<duckdb::FunctionData>, true> duckdb::StructPackBind<false>(duckdb::BindScalarFunctionInput&) |
72 | | |
73 | 0 | static unique_ptr<BaseStatistics> StructPackStats(ClientContext &context, FunctionStatisticsInput &input) { |
74 | 0 | auto &child_stats = input.child_stats; |
75 | 0 | auto &expr = input.expr; |
76 | 0 | auto struct_stats = StructStats::CreateUnknown(expr.GetReturnType()); |
77 | 0 | for (idx_t i = 0; i < child_stats.size(); i++) { |
78 | 0 | StructStats::SetChildStats(struct_stats, i, child_stats[i]); |
79 | 0 | } |
80 | 0 | return struct_stats.ToUnique(); |
81 | 0 | } |
82 | | |
83 | | template <bool IS_STRUCT_PACK> |
84 | 1.27k | static ScalarFunction GetStructPackFunction() { |
85 | 1.27k | ScalarFunction fun(IS_STRUCT_PACK ? "struct_pack" : "row", {}, LogicalTypeId::STRUCT, StructPackFunction, |
86 | 1.27k | StructPackBind<IS_STRUCT_PACK>, StructPackStats); |
87 | 1.27k | fun.SetVarArgs(LogicalType::ANY); |
88 | 1.27k | fun.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING); |
89 | 1.27k | fun.SetSerializeCallback(VariableReturnBindData::Serialize); |
90 | 1.27k | fun.SetDeserializeCallback(VariableReturnBindData::Deserialize); |
91 | 1.27k | return fun; |
92 | 1.27k | } ub_duckdb_func_struct_main.cpp:duckdb::ScalarFunction duckdb::GetStructPackFunction<true>() Line | Count | Source | 84 | 636 | static ScalarFunction GetStructPackFunction() { | 85 | 636 | ScalarFunction fun(IS_STRUCT_PACK ? "struct_pack" : "row", {}, LogicalTypeId::STRUCT, StructPackFunction, | 86 | 636 | StructPackBind<IS_STRUCT_PACK>, StructPackStats); | 87 | 636 | fun.SetVarArgs(LogicalType::ANY); | 88 | 636 | fun.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING); | 89 | 636 | fun.SetSerializeCallback(VariableReturnBindData::Serialize); | 90 | 636 | fun.SetDeserializeCallback(VariableReturnBindData::Deserialize); | 91 | 636 | return fun; | 92 | 636 | } |
ub_duckdb_func_struct_main.cpp:duckdb::ScalarFunction duckdb::GetStructPackFunction<false>() Line | Count | Source | 84 | 636 | static ScalarFunction GetStructPackFunction() { | 85 | 636 | ScalarFunction fun(IS_STRUCT_PACK ? "struct_pack" : "row", {}, LogicalTypeId::STRUCT, StructPackFunction, | 86 | 636 | StructPackBind<IS_STRUCT_PACK>, StructPackStats); | 87 | 636 | fun.SetVarArgs(LogicalType::ANY); | 88 | 636 | fun.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING); | 89 | 636 | fun.SetSerializeCallback(VariableReturnBindData::Serialize); | 90 | 636 | fun.SetDeserializeCallback(VariableReturnBindData::Deserialize); | 91 | 636 | return fun; | 92 | 636 | } |
|
93 | | |
94 | 636 | ScalarFunction StructPackFun::GetFunction() { |
95 | 636 | return GetStructPackFunction<true>(); |
96 | 636 | } |
97 | | |
98 | 636 | ScalarFunction RowFun::GetFunction() { |
99 | 636 | return GetStructPackFunction<false>(); |
100 | 636 | } |
101 | | |
102 | | } // namespace duckdb |