2323
2424#include < arrow/array.h>
2525#include < arrow/array/builder_binary.h>
26+ #include < arrow/array/builder_nested.h>
2627#include < arrow/array/builder_primitive.h>
28+ #include < arrow/io/memory.h>
29+ #include < arrow/ipc/writer.h>
2730#include < arrow/record_batch.h>
2831#include < arrow/type.h>
2932
@@ -76,6 +79,75 @@ std::optional<std::tuple<int64_t, int64_t, int64_t>> decode_indexed_range(
7679 return std::tuple{ordinal_begin->first , ordinal_begin->second , end_unused->second };
7780}
7881
82+ std::string encode_batch (const std::shared_ptr<arrow::RecordBatch>& batch) {
83+ auto sink = arrow::io::BufferOutputStream::Create ().ValueOrDie ();
84+ auto writer = arrow::ipc::MakeStreamWriter (sink, batch->schema ()).ValueOrDie ();
85+ (void )writer->WriteRecordBatch (*batch);
86+ (void )writer->Close ();
87+ return sink->Finish ().ValueOrDie ()->ToString ();
88+ }
89+
90+ std::shared_ptr<arrow::Array> one_string_list (const std::vector<std::string>& values) {
91+ arrow::ListBuilder builder (arrow::default_memory_pool (),
92+ std::make_unique<arrow::StringBuilder>());
93+ (void )builder.Append ();
94+ auto & items = static_cast <arrow::StringBuilder&>(*builder.value_builder ());
95+ for (const auto & value : values) (void )items.Append (value);
96+ return builder.Finish ().ValueOrDie ();
97+ }
98+
99+ std::shared_ptr<arrow::Array> one_binary_list (const std::vector<std::string>& values) {
100+ arrow::ListBuilder builder (arrow::default_memory_pool (),
101+ std::make_unique<arrow::BinaryBuilder>());
102+ (void )builder.Append ();
103+ auto & items = static_cast <arrow::BinaryBuilder&>(*builder.value_builder ());
104+ for (const auto & value : values) (void )items.Append (value);
105+ return builder.Finish ().ValueOrDie ();
106+ }
107+
108+ std::string identity_key_grouping (const std::string& column) {
109+ const auto path = encode_batch (arrow::RecordBatch::Make (
110+ arrow::schema ({arrow::field (" components" , arrow::list (arrow::utf8 ()), false )}), 1 ,
111+ {one_string_list ({column})}));
112+
113+ arrow::StringBuilder id_builder;
114+ (void )id_builder.Append (" vgi.identity/1" );
115+ arrow::BinaryBuilder parameters_builder;
116+ (void )parameters_builder.AppendNull ();
117+ const auto transform = encode_batch (arrow::RecordBatch::Make (
118+ arrow::schema ({arrow::field (" id" , arrow::utf8 (), false ),
119+ arrow::field (" inputs" , arrow::list (arrow::binary ()), false ),
120+ arrow::field (" parameters" , arrow::binary (), true )}),
121+ 1 ,
122+ {id_builder.Finish ().ValueOrDie (), one_binary_list ({path}),
123+ parameters_builder.Finish ().ValueOrDie ()}));
124+
125+ return encode_batch (arrow::RecordBatch::Make (
126+ arrow::schema ({arrow::field (" keys" , arrow::list (arrow::binary ()), false )}), 1 ,
127+ {one_binary_list ({transform})}));
128+ }
129+
130+ std::optional<std::string> partition_key_value (const std::string& country,
131+ const std::string& mode) {
132+ if (mode == " missing" ) return std::nullopt ;
133+ if (mode == " wrong_type" ) {
134+ arrow::Int64Builder values;
135+ (void )values.Append (1 );
136+ return encode_batch (
137+ arrow::RecordBatch::Make (arrow::schema ({arrow::field (" country" , arrow::int64 (), true )}),
138+ 1 , {values.Finish ().ValueOrDie ()}));
139+ }
140+ if (mode != " valid" && mode != " two_rows" ) {
141+ throw std::invalid_argument (" unknown split_partitioned key_mode: " + mode);
142+ }
143+ arrow::StringBuilder values;
144+ (void )values.Append (country);
145+ if (mode == " two_rows" ) (void )values.Append (country);
146+ auto array = values.Finish ().ValueOrDie ();
147+ return encode_batch (arrow::RecordBatch::Make (
148+ arrow::schema ({arrow::field (" country" , arrow::utf8 (), true )}), array->length (), {array}));
149+ }
150+
79151std::shared_ptr<arrow::Schema> n_schema () {
80152 return arrow::schema ({arrow::field (" n" , arrow::int64 (), /* nullable=*/ false )});
81153}
@@ -481,7 +553,10 @@ class SplitPartitioned : public vgi::TableFunction {
481553 }
482554
483555 std::vector<vgi::ArgSpec> argument_specs () const override {
484- return {vgi::ArgSpec::named (" rows_per_country" , " int64" , " Rows per country" )};
556+ return {vgi::ArgSpec::named (" rows_per_country" , " int64" , " Rows per country" ),
557+ vgi::ArgSpec::named (
558+ " key_mode" , " varchar" ,
559+ " Test-only Protocol 3.1 key shape: valid, missing, two_rows, or wrong_type" )};
485560 }
486561
487562 std::shared_ptr<arrow::Schema> bind (const vgi::BindParams&) const override {
@@ -494,14 +569,17 @@ class SplitPartitioned : public vgi::TableFunction {
494569 vgi::PlanResult plan (const vgi::BindParams& params, const vgi::PlanParams&) const override {
495570 const int64_t rows =
496571 std::max<int64_t >(0 , params.arguments .named_int64 (" rows_per_country" ).value_or (0 ));
572+ const auto key_mode = params.arguments .named_string (" key_mode" ).value_or (" valid" );
497573 vgi::PlanResult result;
498574 result.estimated_total_splits = static_cast <int64_t >(kCountries .size ());
499575 result.estimated_total_rows = rows * static_cast <int64_t >(kCountries .size ());
576+ result.key_grouping = identity_key_grouping (" country" );
500577 for (int64_t i = 0 ; i < static_cast <int64_t >(kCountries .size ()); ++i) {
501578 vgi::ScanSplit split;
502579 split.payload = encode_range (i, rows);
503580 split.estimated_rows = rows;
504581 split.rows_exact = true ;
582+ split.key_value = partition_key_value (kCountries [static_cast <size_t >(i)], key_mode);
505583 result.splits .push_back (std::move (split));
506584 }
507585 return result;
0 commit comments