Skip to content

Commit 8b047ce

Browse files
committed
consolidate Avro default scalar into AvroExtraAttributes with checked_cast
1 parent 7de6e6e commit 8b047ce

3 files changed

Lines changed: 23 additions & 18 deletions

File tree

src/iceberg/avro/avro_data_util.cc

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -590,12 +590,11 @@ Status PrepareStructDefaultScalars(std::span<FieldProjection> projections,
590590
auto* field_builder = struct_builder->field_builder(static_cast<int>(i));
591591

592592
if (field_projection.kind == FieldProjection::Kind::kDefault) {
593-
if (dynamic_cast<const AvroDefaultAttributes*>(field_projection.attributes.get()) !=
594-
nullptr) {
593+
if (field_projection.attributes != nullptr) {
595594
continue;
596595
}
597-
auto attrs = std::make_shared<AvroDefaultAttributes>();
598-
ICEBERG_ASSIGN_OR_RAISE(attrs->scalar,
596+
auto attrs = std::make_shared<AvroExtraAttributes>();
597+
ICEBERG_ASSIGN_OR_RAISE(attrs->default_scalar,
599598
MakeDefaultScalar(std::get<Literal>(field_projection.from),
600599
field_builder->type()));
601600
field_projection.attributes = std::move(attrs);
@@ -624,11 +623,15 @@ Status AppendDefaultToBuilder(const Literal& literal, ::arrow::ArrayBuilder* bui
624623

625624
Status AppendDefaultToBuilder(const FieldProjection& projection,
626625
::arrow::ArrayBuilder* builder) {
627-
if (const auto* attrs =
628-
dynamic_cast<const AvroDefaultAttributes*>(projection.attributes.get());
629-
attrs != nullptr && attrs->scalar != nullptr) {
630-
ICEBERG_ARROW_RETURN_NOT_OK(builder->AppendScalar(*attrs->scalar));
631-
return {};
626+
// Avro projections carry a single attributes type, so once one is attached it is an
627+
// AvroExtraAttributes; use checked_cast instead of a per-row dynamic_cast.
628+
if (projection.attributes != nullptr) {
629+
const auto& attrs =
630+
internal::checked_cast<const AvroExtraAttributes&>(*projection.attributes);
631+
if (attrs.default_scalar != nullptr) {
632+
ICEBERG_ARROW_RETURN_NOT_OK(builder->AppendScalar(*attrs.default_scalar));
633+
return {};
634+
}
632635
}
633636
return AppendDefaultToBuilder(std::get<Literal>(projection.from), builder);
634637
}

src/iceberg/avro/avro_data_util_internal.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,22 @@
3131

3232
namespace iceberg::avro {
3333

34-
/// \brief Cached Arrow scalar for a `kDefault` field projection.
34+
/// \brief Avro-specific per-field projection attributes.
3535
///
36-
/// Materialized once (see `PrepareDefaultScalars`) so row-by-row Avro decode only
37-
/// needs `AppendScalar` instead of repeating `ToArrowScalar` / `CastTo` per row.
38-
struct AvroDefaultAttributes : FieldProjection::ExtraAttributes {
39-
std::shared_ptr<::arrow::Scalar> scalar;
36+
/// `FieldProjection` has a single attributes slot, so all Avro-side attributes live in
37+
/// one container (mirroring `ParquetExtraAttributes`) rather than separate subclasses
38+
/// that could not coexist. `default_scalar` is the Arrow scalar for a `kDefault` field,
39+
/// materialized once (see `PrepareDefaultScalars`) so row-by-row decode only needs
40+
/// `AppendScalar` instead of repeating `ToArrowScalar` / `CastTo` per row.
41+
struct AvroExtraAttributes : FieldProjection::ExtraAttributes {
42+
std::shared_ptr<::arrow::Scalar> default_scalar;
4043
};
4144

4245
/// \brief Precompute cast Arrow scalars for every `kDefault` field under `projection`.
4346
///
4447
/// Walks `root_builder` in lockstep with the projection so each default is cast to the
4548
/// builder's Arrow type once per scan. Safe to call repeatedly; existing
46-
/// `AvroDefaultAttributes` entries are left unchanged.
49+
/// `AvroExtraAttributes` entries are left unchanged.
4750
Status PrepareDefaultScalars(SchemaProjection& projection,
4851
::arrow::ArrayBuilder* root_builder);
4952

src/iceberg/test/avro_data_test.cc

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -801,7 +801,7 @@ TEST(AppendDefaultToBuilderTest, ReusesPreparedScalar) {
801801
SchemaProjection schema_projection;
802802
schema_projection.fields.push_back(projection);
803803
ASSERT_THAT(PrepareDefaultScalars(schema_projection, &struct_builder), IsOk());
804-
ASSERT_NE(dynamic_cast<const AvroDefaultAttributes*>(
804+
ASSERT_NE(dynamic_cast<const AvroExtraAttributes*>(
805805
schema_projection.fields[0].attributes.get()),
806806
nullptr);
807807

@@ -852,8 +852,7 @@ TEST(AppendDefaultToBuilderTest, PreparesScalarUnderNestedCollections) {
852852
ASSERT_THAT(PrepareDefaultScalars(schema_projection, &root_builder), IsOk());
853853

854854
const auto& prepared = schema_projection.fields[0].children[0].children[0].children[0];
855-
ASSERT_NE(dynamic_cast<const AvroDefaultAttributes*>(prepared.attributes.get()),
856-
nullptr);
855+
ASSERT_NE(dynamic_cast<const AvroExtraAttributes*>(prepared.attributes.get()), nullptr);
857856
}
858857

859858
TEST(AppendDatumToBuilderTest, NestedStructWithMissingOptionalFields) {

0 commit comments

Comments
 (0)