@@ -161,11 +161,15 @@ Status AvroScanner::open() {
161161 }
162162 ++_counter->num_files_read ;
163163
164- for (const auto & desc : _src_slot_descriptors) {
164+ for (size_t i = 0 ; i < _src_slot_descriptors.size (); ++i) {
165+ const auto & desc = _src_slot_descriptors[i];
165166 if (desc == nullptr ) {
166167 continue ;
167168 }
168169 _slot_desc_dict.emplace (desc->col_name (), desc);
170+ // Remember the intermediate avro type per slot so the no-jsonpath path can dispatch
171+ // _construct_column on the source column's type rather than the destination type.
172+ _slot_id_to_avro_type.emplace (desc->id (), _avro_types[i]);
169173 }
170174 _init_data_idx_to_slot_once = false ;
171175 return Status::OK ();
@@ -217,8 +221,13 @@ Status AvroScanner::_construct_row(const avro_value_t& avro_value, Chunk* chunk)
217221 avro_value_t output_value;
218222 auto st = _extract_field (avro_value, _json_paths[i], &output_value);
219223 if (LIKELY (st.ok ())) {
220- RETURN_IF_ERROR (_construct_column (output_value, column, _src_slot_descriptors[i]->type (),
221- _src_slot_descriptors[i]->col_name ()));
224+ // Dispatch on the intermediate avro type (which matches the source column created in
225+ // _create_src_chunk), not the destination type. Otherwise a complex column whose
226+ // intermediate type differs from the destination (e.g. MAP<VARCHAR,VARCHAR> vs
227+ // MAP<VARCHAR,DATE>) would be written by a writer chosen for the destination and crash
228+ // on down_cast. The cast stage converts the intermediate column to the destination type.
229+ RETURN_IF_ERROR (
230+ _construct_column (output_value, column, _avro_types[i], _src_slot_descriptors[i]->col_name ()));
222231 } else if (st.is_not_found ()) {
223232 column->append_nulls (1 );
224233 } else {
@@ -355,7 +364,9 @@ Status AvroScanner::_construct_row_without_jsonpath(const avro_value_t& avro_val
355364 }
356365 auto slot_desc = itr->second ;
357366 slot_info.id = slot_desc->id ();
358- slot_info.type = slot_desc->type ();
367+ // Store the intermediate avro type (not the destination type) so _construct_column
368+ // dispatches on the type the source column was built with. See _construct_row.
369+ slot_info.type = _slot_id_to_avro_type[slot_desc->id ()];
359370 slot_info.key = key;
360371 int column_index = chunk->get_index_by_slot_id (slot_info.id );
361372 _found_columns[column_index] = true ;
@@ -460,87 +471,75 @@ Status AvroScanner::_construct_cast_exprs() {
460471 return Status::OK ();
461472}
462473
463- Status AvroScanner::_construct_avro_types () {
464- size_t slot_size = _src_slot_descriptors.size ();
465- _avro_types.resize (slot_size);
466- for (int column_pos = 0 ; column_pos < slot_size; ++column_pos) {
467- auto slot_desc = _src_slot_descriptors[column_pos];
468- if (slot_desc == nullptr ) {
469- continue ;
474+ // Build the intermediate avro load type for a destination slot type. Complex types (ARRAY / MAP /
475+ // STRUCT) recurse so they are loaded natively; directly-representable scalars are kept as-is and
476+ // everything else is loaded as VARCHAR(MAX), with the cast stage converting to the destination type
477+ // (the cast factory supports recursive ARRAY/MAP/STRUCT casts). This mirrors
478+ // JsonUtils::construct_json_type. Avro map keys are always strings, so a map's intermediate key
479+ // type is forced to a string type regardless of the destination key type.
480+ static TypeDescriptor construct_avro_type (const TypeDescriptor& slot_type) {
481+ switch (slot_type.type ) {
482+ case TYPE_ARRAY : {
483+ TypeDescriptor avro_type (TYPE_ARRAY );
484+ avro_type.children .emplace_back (construct_avro_type (slot_type.children [0 ]));
485+ return avro_type;
486+ }
487+ case TYPE_MAP : {
488+ TypeDescriptor avro_type (TYPE_MAP );
489+ const auto & key_type = slot_type.children [0 ];
490+ if (key_type.type == TYPE_CHAR ) {
491+ avro_type.children .emplace_back (TypeDescriptor::create_char_type (key_type.len ));
492+ } else if (key_type.type == TYPE_VARCHAR ) {
493+ avro_type.children .emplace_back (TypeDescriptor::create_varchar_type (key_type.len ));
494+ } else {
495+ avro_type.children .emplace_back (TypeDescriptor::create_varchar_type (TypeDescriptor::MAX_VARCHAR_LENGTH ));
470496 }
471-
472- switch (slot_desc->type ().type ) {
473- case TYPE_ARRAY : {
474- TypeDescriptor json_type (TYPE_ARRAY );
475- TypeDescriptor* child_type = &json_type;
476-
477- const TypeDescriptor* slot_type = &(slot_desc->type ().children [0 ]);
478- while (slot_type->type == TYPE_ARRAY ) {
479- slot_type = &(slot_type->children [0 ]);
480-
481- child_type->children .emplace_back (TYPE_ARRAY );
482- child_type = &(child_type->children [0 ]);
483- }
484-
485- // the json lib don't support get_int128_t(), so we load with BinaryColumn and then convert to LargeIntColumn
486- if (slot_type->type == TYPE_FLOAT || slot_type->type == TYPE_DOUBLE || slot_type->type == TYPE_BIGINT ||
487- slot_type->type == TYPE_INT || slot_type->type == TYPE_SMALLINT || slot_type->type == TYPE_TINYINT ) {
488- // Treat these types as what they are.
489- child_type->children .emplace_back (slot_type->type );
490- } else if (slot_type->type == TYPE_VARCHAR ) {
491- auto varchar_type = TypeDescriptor::create_varchar_type (slot_type->len );
492- child_type->children .emplace_back (varchar_type);
493- } else if (slot_type->type == TYPE_CHAR ) {
494- auto char_type = TypeDescriptor::create_char_type (slot_type->len );
495- child_type->children .emplace_back (char_type);
496- } else if (slot_type->type == TYPE_JSON ) {
497- child_type->children .emplace_back (TypeDescriptor::create_json_type ());
498- } else {
499- // Treat other types as VARCHAR.
500- auto varchar_type = TypeDescriptor::create_varchar_type (TypeDescriptor::MAX_VARCHAR_LENGTH );
501- child_type->children .emplace_back (varchar_type);
502- }
503-
504- _avro_types[column_pos] = std::move (json_type);
505- break ;
497+ avro_type.children .emplace_back (construct_avro_type (slot_type.children [1 ]));
498+ return avro_type;
499+ }
500+ case TYPE_STRUCT : {
501+ TypeDescriptor avro_type (TYPE_STRUCT );
502+ avro_type.field_names = slot_type.field_names ;
503+ for (const auto & child : slot_type.children ) {
504+ avro_type.children .emplace_back (construct_avro_type (child));
506505 }
506+ return avro_type;
507+ }
507508
508- // Treat these types as what they are.
509- case TYPE_FLOAT :
510- case TYPE_DOUBLE :
511- case TYPE_BIGINT :
512- case TYPE_INT :
513- case TYPE_BOOLEAN :
514- case TYPE_SMALLINT :
515- case TYPE_TINYINT : {
516- _avro_types[column_pos] = TypeDescriptor{slot_desc->type ().type };
517- break ;
518- }
509+ // Treat these types as what they are.
510+ case TYPE_FLOAT :
511+ case TYPE_DOUBLE :
512+ case TYPE_BIGINT :
513+ case TYPE_INT :
514+ case TYPE_BOOLEAN :
515+ case TYPE_SMALLINT :
516+ case TYPE_TINYINT :
517+ return TypeDescriptor{slot_type.type };
519518
520- case TYPE_CHAR : {
521- auto char_type = TypeDescriptor::create_char_type (slot_desc->type ().len );
522- _avro_types[column_pos] = std::move (char_type);
523- break ;
524- }
519+ case TYPE_CHAR :
520+ return TypeDescriptor::create_char_type (slot_type.len );
525521
526- case TYPE_VARCHAR : {
527- auto varchar_type = TypeDescriptor::create_varchar_type (slot_desc->type ().len );
528- _avro_types[column_pos] = std::move (varchar_type);
529- break ;
530- }
522+ case TYPE_VARCHAR :
523+ return TypeDescriptor::create_varchar_type (slot_type.len );
531524
532- case TYPE_JSON : {
533- _avro_types[column_pos] = TypeDescriptor::create_json_type ();
534- break ;
535- }
525+ case TYPE_JSON :
526+ return TypeDescriptor::create_json_type ();
536527
537- // Treat other types as VARCHAR.
538- default : {
539- auto varchar_type = TypeDescriptor::create_varchar_type (TypeDescriptor::MAX_VARCHAR_LENGTH );
540- _avro_types[column_pos] = std::move (varchar_type);
541- break ;
542- }
528+ // Treat other types as VARCHAR.
529+ default :
530+ return TypeDescriptor::create_varchar_type (TypeDescriptor::MAX_VARCHAR_LENGTH );
531+ }
532+ }
533+
534+ Status AvroScanner::_construct_avro_types () {
535+ size_t slot_size = _src_slot_descriptors.size ();
536+ _avro_types.resize (slot_size);
537+ for (int column_pos = 0 ; column_pos < slot_size; ++column_pos) {
538+ auto slot_desc = _src_slot_descriptors[column_pos];
539+ if (slot_desc == nullptr ) {
540+ continue ;
543541 }
542+ _avro_types[column_pos] = construct_avro_type (slot_desc->type ());
544543 }
545544 return Status::OK ();
546545}
0 commit comments