| 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 | #include "duckdb/common/types/chunk_collection.hpp" |
| 6 | #include "duckdb/common/types/data_chunk.hpp" |
| 7 | |
| 8 | using namespace std; |
| 9 | |
| 10 | namespace duckdb { |
| 11 | |
| 12 | static void list_value_fun(DataChunk &args, ExpressionState &state, Vector &result) { |
| 13 | // auto &func_expr = (BoundFunctionExpression &)state.expr; |
| 14 | // auto &info = (VariableReturnBindData &)*func_expr.bind_info; |
| 15 | |
| 16 | assert(result.type == TypeId::LIST); |
| 17 | auto list_child = make_unique<ChunkCollection>(); |
| 18 | ListVector::SetEntry(result, move(list_child)); |
| 19 | |
| 20 | auto &cc = ListVector::GetEntry(result); |
| 21 | DataChunk append_vals; |
| 22 | vector<TypeId> types; |
| 23 | if (args.column_count() > 0) { |
| 24 | types.push_back(args.GetTypes()[0]); |
| 25 | append_vals.Initialize(types); |
| 26 | append_vals.SetCardinality(1); |
| 27 | } |
| 28 | result.vector_type = VectorType::CONSTANT_VECTOR; |
| 29 | for (idx_t i = 0; i < args.column_count(); i++) { |
| 30 | if (args.data[i].vector_type != VectorType::CONSTANT_VECTOR) { |
| 31 | result.vector_type = VectorType::FLAT_VECTOR; |
| 32 | } |
| 33 | } |
| 34 | |
| 35 | auto result_data = FlatVector::GetData<list_entry_t>(result); |
| 36 | for (idx_t i = 0; i < args.size(); i++) { |
| 37 | result_data[i].offset = cc.count; |
| 38 | for (idx_t col_idx = 0; col_idx < args.column_count(); col_idx++) { |
| 39 | append_vals.SetValue(0, 0, args.GetValue(col_idx, i).CastAs(types[0])); // FIXME evil pattern |
| 40 | cc.Append(append_vals); |
| 41 | } |
| 42 | result_data[i].length = args.column_count(); |
| 43 | } |
| 44 | result.Verify(args.size()); |
| 45 | } |
| 46 | |
| 47 | static unique_ptr<FunctionData> list_value_bind(BoundFunctionExpression &expr, ClientContext &context) { |
| 48 | SQLType stype(SQLTypeId::LIST); |
| 49 | |
| 50 | // collect names and deconflict, construct return type |
| 51 | assert(expr.arguments.size() == expr.children.size()); |
| 52 | |
| 53 | if (expr.children.size() > 0) { |
| 54 | stype.child_type.push_back(make_pair("" , expr.arguments[0])); |
| 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 ListValueFun::RegisterFunction(BuiltinFunctions &set) { |
| 63 | // the arguments and return types are actually set in the binder function |
| 64 | ScalarFunction fun("list_value" , {}, SQLType::LIST, list_value_fun, false, list_value_bind); |
| 65 | fun.varargs = SQLType::ANY; |
| 66 | set.AddFunction(fun); |
| 67 | } |
| 68 | |
| 69 | } // namespace duckdb |
| 70 | |