@@ -275,6 +275,20 @@ class NativeParquetStreamSource : public csp::adapters::parquet::RecordBatchStre
275275 }
276276
277277private:
278+ // Count the number of leaf (primitive) columns an Arrow field contributes to parquet.
279+ static int countLeafColumns ( const std::shared_ptr<::arrow::Field> & field )
280+ {
281+ auto type = field -> type ();
282+ if ( type -> id () == ::arrow::Type::STRUCT )
283+ {
284+ int count = 0 ;
285+ for ( int i = 0 ; i < type -> num_fields (); ++i )
286+ count += countLeafColumns ( type -> field ( i ) );
287+ return count;
288+ }
289+ return 1 ; // scalar or list types are one leaf in parquet
290+ }
291+
278292 // Open a single parquet file, projecting only needed columns.
279293 bool openSingleFile ( const std::string & path ) {
280294 auto fileReader = makeFileReader ( path );
@@ -288,19 +302,31 @@ class NativeParquetStreamSource : public csp::adapters::parquet::RecordBatchStre
288302 auto status = fileReader -> GetSchema ( &arrowSchema );
289303 if ( status.ok () && arrowSchema )
290304 {
305+ // Map from top-level Arrow schema fields to parquet leaf column indices.
306+ // Parquet stores nested struct fields as separate leaf columns.
307+ int leafIdx = 0 ;
291308 for ( int i = 0 ; i < arrowSchema -> num_fields (); ++i )
292309 {
293- auto fieldName = arrowSchema -> field ( i ) -> name ();
294- if ( m_neededColumns.count ( fieldName ) )
310+ auto field = arrowSchema -> field ( i );
311+ auto fieldName = field -> name ();
312+ int numLeaves = countLeafColumns ( field );
313+
314+ bool include = m_neededColumns.count ( fieldName ) > 0 ;
315+ if ( !include )
295316 {
296- colIndices.push_back ( i );
297- continue ;
317+ // Include parent fields of needed nested columns (e.g. "struct.i" → "struct")
318+ std::string prefix = fieldName + " ." ;
319+ auto lb = m_neededColumns.lower_bound ( prefix );
320+ include = lb != m_neededColumns.end () && lb -> compare ( 0 , prefix.size (), prefix ) == 0 ;
298321 }
299- // Include parent fields of needed nested columns (e.g. "struct.i" → "struct")
300- std::string prefix = fieldName + " ." ;
301- auto lb = m_neededColumns.lower_bound ( prefix );
302- if ( lb != m_neededColumns.end () && lb -> compare ( 0 , prefix.size (), prefix ) == 0 )
303- colIndices.push_back ( i );
322+
323+ if ( include )
324+ {
325+ for ( int leaf = 0 ; leaf < numLeaves; ++leaf )
326+ colIndices.push_back ( leafIdx + leaf );
327+ }
328+
329+ leafIdx += numLeaves;
304330 }
305331 }
306332 }
0 commit comments