1 | #include "duckdb/planner/expression/bound_function_expression.hpp" |
2 | #include "duckdb/common/string_util.hpp" |
3 | #include "duckdb/parser/expression/bound_expression.hpp" |
4 | #include "duckdb/function/scalar/nested_functions.hpp" |
5 | |
6 | #include <set> |
7 | |
8 | using namespace std; |
9 | |
10 | namespace duckdb { |
11 | |
12 | static void struct_pack_fun(DataChunk &args, ExpressionState &state, Vector &result) { |
13 | auto &func_expr = (BoundFunctionExpression &)state.expr; |
14 | auto &info = (VariableReturnBindData &)*func_expr.bind_info; |
15 | |
16 | // this should never happen if the binder below is sane |
17 | assert(args.column_count() == info.stype.child_type.size()); |
18 | |
19 | bool all_const = true; |
20 | for (size_t i = 0; i < args.column_count(); i++) { |
21 | if (args.data[i].vector_type != VectorType::CONSTANT_VECTOR) { |
22 | all_const = false; |
23 | } |
24 | // same holds for this |
25 | assert(args.data[i].type == GetInternalType(info.stype.child_type[i].second)); |
26 | auto new_child = make_unique<Vector>(); |
27 | new_child->Reference(args.data[i]); |
28 | StructVector::AddEntry(result, info.stype.child_type[i].first, move(new_child)); |
29 | } |
30 | result.vector_type = all_const ? VectorType::CONSTANT_VECTOR : VectorType::FLAT_VECTOR; |
31 | |
32 | result.Verify(args.size()); |
33 | } |
34 | |
35 | static unique_ptr<FunctionData> struct_pack_bind(BoundFunctionExpression &expr, ClientContext &context) { |
36 | SQLType stype(SQLTypeId::STRUCT); |
37 | set<string> name_collision_set; |
38 | |
39 | // collect names and deconflict, construct return type |
40 | assert(expr.arguments.size() == expr.children.size()); |
41 | |
42 | if (expr.arguments.size() == 0) { |
43 | throw Exception("Can't pack nothing into a struct" ); |
44 | } |
45 | for (idx_t i = 0; i < expr.children.size(); i++) { |
46 | auto &child = expr.children[i]; |
47 | if (child->alias.size() == 0) { |
48 | throw Exception("Need named argument for struct pack, e.g. STRUCT_PACK(a := b)" ); |
49 | } |
50 | if (name_collision_set.find(child->alias) != name_collision_set.end()) { |
51 | throw Exception("Duplicate struct entry name" ); |
52 | } |
53 | name_collision_set.insert(child->alias); |
54 | stype.child_type.push_back(make_pair(child->alias, expr.arguments[i])); |
55 | } |
56 | |
57 | // this is more for completeness reasons |
58 | expr.sql_return_type = stype; |
59 | return make_unique<VariableReturnBindData>(stype); |
60 | } |
61 | |
62 | void StructPackFun::RegisterFunction(BuiltinFunctions &set) { |
63 | // the arguments and return types are actually set in the binder function |
64 | ScalarFunction fun("struct_pack" , {}, SQLType::STRUCT, struct_pack_fun, false, struct_pack_bind); |
65 | fun.varargs = SQLType::ANY; |
66 | set.AddFunction(fun); |
67 | } |
68 | |
69 | } // namespace duckdb |
70 | |