1 | #include "duckdb/function/table/range.hpp" |
2 | #include "duckdb/common/algorithm.hpp" |
3 | |
4 | namespace duckdb { |
5 | |
6 | struct RepeatRowFunctionData : public TableFunctionData { |
7 | RepeatRowFunctionData(vector<Value> values, idx_t target_count) |
8 | : values(std::move(values)), target_count(target_count) { |
9 | } |
10 | |
11 | const vector<Value> values; |
12 | idx_t target_count; |
13 | }; |
14 | |
15 | struct RepeatRowOperatorData : public GlobalTableFunctionState { |
16 | RepeatRowOperatorData() : current_count(0) { |
17 | } |
18 | idx_t current_count; |
19 | }; |
20 | |
21 | static unique_ptr<FunctionData> RepeatRowBind(ClientContext &context, TableFunctionBindInput &input, |
22 | vector<LogicalType> &return_types, vector<string> &names) { |
23 | auto &inputs = input.inputs; |
24 | for (idx_t input_idx = 0; input_idx < inputs.size(); input_idx++) { |
25 | return_types.push_back(x: inputs[input_idx].type()); |
26 | names.push_back(x: "column" + std::to_string(val: input_idx)); |
27 | } |
28 | auto entry = input.named_parameters.find(x: "num_rows" ); |
29 | if (entry == input.named_parameters.end()) { |
30 | throw BinderException("repeat_rows requires num_rows to be specified" ); |
31 | } |
32 | if (inputs.empty()) { |
33 | throw BinderException("repeat_rows requires at least one column to be specified" ); |
34 | } |
35 | return make_uniq<RepeatRowFunctionData>(args&: inputs, args: entry->second.GetValue<int64_t>()); |
36 | } |
37 | |
38 | static unique_ptr<GlobalTableFunctionState> RepeatRowInit(ClientContext &context, TableFunctionInitInput &input) { |
39 | return make_uniq<RepeatRowOperatorData>(); |
40 | } |
41 | |
42 | static void RepeatRowFunction(ClientContext &context, TableFunctionInput &data_p, DataChunk &output) { |
43 | auto &bind_data = data_p.bind_data->Cast<RepeatRowFunctionData>(); |
44 | auto &state = data_p.global_state->Cast<RepeatRowOperatorData>(); |
45 | |
46 | idx_t remaining = MinValue<idx_t>(a: bind_data.target_count - state.current_count, STANDARD_VECTOR_SIZE); |
47 | for (idx_t val_idx = 0; val_idx < bind_data.values.size(); val_idx++) { |
48 | output.data[val_idx].Reference(value: bind_data.values[val_idx]); |
49 | } |
50 | output.SetCardinality(remaining); |
51 | state.current_count += remaining; |
52 | } |
53 | |
54 | static unique_ptr<NodeStatistics> RepeatRowCardinality(ClientContext &context, const FunctionData *bind_data_p) { |
55 | auto &bind_data = bind_data_p->Cast<RepeatRowFunctionData>(); |
56 | return make_uniq<NodeStatistics>(args: bind_data.target_count, args: bind_data.target_count); |
57 | } |
58 | |
59 | void RepeatRowTableFunction::RegisterFunction(BuiltinFunctions &set) { |
60 | TableFunction repeat_row("repeat_row" , {}, RepeatRowFunction, RepeatRowBind, RepeatRowInit); |
61 | repeat_row.varargs = LogicalType::ANY; |
62 | repeat_row.named_parameters["num_rows" ] = LogicalType::BIGINT; |
63 | repeat_row.cardinality = RepeatRowCardinality; |
64 | set.AddFunction(function: repeat_row); |
65 | } |
66 | |
67 | } // namespace duckdb |
68 | |