@@ -68,13 +68,24 @@ Field convertNodeToField(capnp::DynamicValue::Reader value)
68
68
auto listValue = value.as <capnp::DynamicList>();
69
69
Array res (listValue.size ());
70
70
for (auto i : kj::indices (listValue))
71
- res[i] = convertNodeToField (listValue[i]);
71
+ res[i] = convertNodeToField (listValue[i]);
72
+
72
73
return res;
73
74
}
74
75
case capnp::DynamicValue::ENUM:
75
76
return UInt64 (value.as <capnp::DynamicEnum>().getRaw ());
76
77
case capnp::DynamicValue::STRUCT:
77
- throw Exception (" STRUCT type not supported, read individual fields instead" );
78
+ {
79
+ auto structValue = value.as <capnp::DynamicStruct>();
80
+ const auto & fields = structValue.getSchema ().getFields ();
81
+
82
+ Field field = Tuple (TupleBackend (fields.size ()));
83
+ TupleBackend & tuple = get<Tuple &>(field).toUnderType ();
84
+ for (auto i : kj::indices (fields))
85
+ tuple[i] = convertNodeToField (structValue.get (fields[i]));
86
+
87
+ return field;
88
+ }
78
89
case capnp::DynamicValue::CAPABILITY:
79
90
throw Exception (" CAPABILITY type not supported" );
80
91
case capnp::DynamicValue::ANY_POINTER:
@@ -88,9 +99,8 @@ capnp::StructSchema::Field getFieldOrThrow(capnp::StructSchema node, const std::
88
99
KJ_IF_MAYBE (child, node.findFieldByName (field))
89
100
return *child;
90
101
else
91
- throw Exception (" Field " + field + " doesn't exist in schema. " );
102
+ throw Exception (" Field " + field + " doesn't exist in schema " + node. getShortDisplayName (). cStr () );
92
103
}
93
-
94
104
void CapnProtoRowInputStream::createActions (const NestedFieldList & sortedFields, capnp::StructSchema reader)
95
105
{
96
106
String last;
@@ -110,13 +120,28 @@ void CapnProtoRowInputStream::createActions(const NestedFieldList & sortedFields
110
120
// Descend to a nested structure
111
121
for (; level < field.tokens .size () - 1 ; ++level)
112
122
{
113
- last = field.tokens [level];
114
- parent = getFieldOrThrow (reader, last);
115
- reader = parent.getType ().asStruct ();
116
- actions.push_back ({Action::PUSH, parent});
123
+ auto node = getFieldOrThrow (reader, field.tokens [level]);
124
+ if (node.getType ().isStruct ()) {
125
+ // Descend to field structure
126
+ last = field.tokens [level];
127
+ parent = node;
128
+ reader = parent.getType ().asStruct ();
129
+ actions.push_back ({Action::PUSH, parent});
130
+ } else if (node.getType ().isList ()) {
131
+ break ; // Collect list
132
+ } else
133
+ throw Exception (" Field " + field.tokens [level] + " is neither Struct nor List" );
117
134
}
135
+
118
136
// Read field from the structure
119
- actions.push_back ({Action::READ, getFieldOrThrow (reader, field.tokens [level]), field.pos });
137
+ auto node = getFieldOrThrow (reader, field.tokens [level]);
138
+ if (node.getType ().isList () && actions.size () > 0 && actions.back ().field == node) {
139
+ // The field list here flattens Nested elements into multiple arrays
140
+ // In order to map Nested types in Cap'nProto back, they need to be collected
141
+ actions.back ().columns .push_back (field.pos );
142
+ } else {
143
+ actions.push_back ({Action::READ, node, {field.pos }});
144
+ }
120
145
}
121
146
}
122
147
@@ -176,7 +201,7 @@ bool CapnProtoRowInputStream::read(MutableColumns & columns)
176
201
array = heap_array.asPtr ();
177
202
}
178
203
179
- capnp::FlatArrayMessageReader msg (array);
204
+ capnp::UnalignedFlatArrayMessageReader msg (array);
180
205
std::vector<capnp::DynamicStruct::Reader> stack;
181
206
stack.push_back (msg.getRoot <capnp::DynamicStruct>(root));
182
207
@@ -186,9 +211,28 @@ bool CapnProtoRowInputStream::read(MutableColumns & columns)
186
211
{
187
212
case Action::READ:
188
213
{
189
- auto & col = columns[action.column ];
190
214
Field value = convertNodeToField (stack.back ().get (action.field ));
191
- col->insert (value);
215
+ if (action.columns .size () > 1 ) {
216
+ // Nested columns must be flattened into several arrays
217
+ // e.g. Array(Tuple(x ..., y ...)) -> Array(x ...), Array(y ...)
218
+ const Array & collected = DB::get<const Array &>(value);
219
+ size_t size = collected.size ();
220
+ // The flattened array contains an array of a part of the nested tuple
221
+ Array flattened (size);
222
+ for (size_t column_index = 0 ; column_index < action.columns .size (); ++column_index) {
223
+ // Populate array with a single tuple elements
224
+ for (size_t off = 0 ; off < size; ++off) {
225
+ const TupleBackend & tuple = DB::get<const Tuple &>(collected[off]).toUnderType ();
226
+ flattened[off] = tuple[column_index];
227
+ }
228
+ auto & col = columns[action.columns [column_index]];
229
+ col->insert (flattened);
230
+ }
231
+ } else {
232
+ auto & col = columns[action.columns [0 ]];
233
+ col->insert (value);
234
+ }
235
+
192
236
break ;
193
237
}
194
238
case Action::POP:
0 commit comments