Skip to content

All: Remove deprecated methods for 1.12.0 - #16449

Open
dramaticlly wants to merge 18 commits into
apache:mainfrom
dramaticlly:1.12deprecation
Open

All: Remove deprecated methods for 1.12.0#16449
dramaticlly wants to merge 18 commits into
apache:mainfrom
dramaticlly:1.12deprecation

Conversation

@dramaticlly

@dramaticlly dramaticlly commented May 20, 2026

Copy link
Copy Markdown
Contributor

Remove all methods, classes, and fields marked with "@deprecated will be removed in 1.12.0" across all modules, since 1.11.0 has been released.

Deleted Classes

  • SystemProperties → use SystemConfigs
  • PartitionStats → use PartitionStatistics interface / BasePartitionStatistics
  • DataReader → use PlannedDataReader
  • GenericAppenderFactory → use GenericFileWriterFactory
  • BaseFileWriterFactory → use RegistryBasedFileWriterFactory
  • S3SignRequest, S3SignResponse, S3SignRequestParser, S3SignResponseParser, S3ObjectMapper → use RemoteSign* equivalents

Notable Non-Mechanical Changes

Beyond deleting deprecated code, the following adjustments were needed. Items marked ⚠️ reviewer attention depart from a strict deprecation removal and warrant a closer look:

  1. ⚠️ PositionDelete.set(path, pos, row) and row() — Kept without @Deprecated. The public deprecation notice said position deletes with row data are no longer supported, but internal code (BaseTaskWriter, BasePositionDeltaWriter, RewriteTablePathUtil, Avro) still relies on these methods. Reviewer: confirm the methods are safe to retain as package-internal helpers, or whether a follow-up should narrow visibility / push removal to 1.13.0.

  2. ⚠️ HadoopFileIO.serializeConfWith() — Kept without @Deprecated because the HadoopConfigurable interface still declares the method. Also inlined the constructor logic since the removed constructor was the delegation target. Reviewer: the cleaner path is to deprecate the interface method (and the ResolvingFileIO / SerializableFileIOWithSize × 3 implementations) for 1.13.0 removal, then drop the SerializationUtil instanceof HadoopConfigurable branch and the iceberg.mr.config.serialization.disabled opt-in — those are the only remaining consumers after Core: Move Hadoop conf serialization into SerializableConfiguration #15583 made SerializableConfiguration itself SerializableSupplier-compatible. Happy to land this as a follow-up.

  3. BaseParquetReaders.createStructReader(List, StructType, Integer) — Changed from a concrete method (that delegated to the removed 2-param version) to abstract. Both existing subclasses (InternalReader, GenericParquetReaders) already override it.

  4. ⚠️ S3V4RestSignerClient — Removed deprecated property fallback logic from baseSignerUri(), endpoint(), and check(). The legacy properties (s3.signer.uri, s3.signer.endpoint) are no longer supported, and endpoint() now requires RESTCatalogProperties.SIGNER_ENDPOINT (previously defaulted to "v1/aws/s3/sign"). Reviewer: this is a stricter behavior change than a pure removal — please confirm downstream catalog adapters / integration tests are aware they must now supply RESTCatalogProperties.SIGNER_ENDPOINT explicitly.

AI Disclosure

Model: Claude Opus 4.7 (1M context)
Platform/Tool: Opus
Human Oversight: reviewed
Prompt Summary: provide class and method deprecation scheduled for upcoming 1.12.0 release

// TODO change to required in 1.12.0
if (!properties().containsKey(S3_SIGNER_ENDPOINT)
&& !properties().containsKey(RESTCatalogProperties.SIGNER_ENDPOINT)) {
LOG.warn(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this shouldn't be removed. Instead, this should go through a Preconditions.checkArgument check

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah I think RESTCatalogProperties.SIGNER_ENDPOINT is replaced with RESTCatalogProperties.SIGNER_URI and we can rely on LINE 206 to ensure its existence. Sorry it's a bit messy right now

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adutra can you help check the deprecation align with your original goal in #15451.

  • Removes S3_SIGNER_URI / S3_SIGNER_ENDPOINT / S3_SIGNER_DEFAULT_ENDPOINT
  • RESTCatalogProperties.SIGNER_ENDPOINT is now required

@github-actions github-actions Bot removed the ORC label May 23, 2026
@dramaticlly
dramaticlly force-pushed the 1.12deprecation branch 3 times, most recently from aa6430d to 0436357 Compare May 25, 2026 17:08
@dramaticlly
dramaticlly marked this pull request as ready for review May 26, 2026 06:35
@dramaticlly

dramaticlly commented May 26, 2026

Copy link
Copy Markdown
Contributor Author

@nastra do you want to take another look as now CI is green. I leave the PositionDelete.set(path, pos, row) and row() as is given there's nontrivial amount of caller still use the Deprecated method, plan to handle in a follow up PR

@nssalian nssalian added this to the Iceberg 1.12.0 milestone Jun 13, 2026
@manuzhang
manuzhang requested a review from nastra June 20, 2026 12:25
dramaticlly added a commit to dramaticlly/iceberg that referenced this pull request Jun 25, 2026
…NSAFE branch

The prior 1.11 logic in `Parquet.ReadBuilder` had three branches when picking
the name mapping for a vectorized read:

  1. caller-provided nameMapping → use it
  2. `NETFLIX_UNSAFE_PARQUET_ID_FALLBACK_ENABLED=true` → use null (unsafe
     fallback to position-based field resolution)
  3. default → use `NameMapping.empty()` (safe)

PR apache#16449 removed the deprecated NETFLIX_UNSAFE branch (case 2) but
collapsed the default to `null` rather than `NameMapping.empty()`, making
unsafe position-based resolution the new default. That contradicts the
PR description ("always use NameMapping.empty() (the safe default)") and
silently regresses readers that don't supply an explicit mapping.

Restore the safe default by using `NameMapping.empty()` when no mapping
is provided.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dramaticlly added a commit to dramaticlly/iceberg that referenced this pull request Jun 25, 2026
…NSAFE branch

The prior 1.11 logic in `Parquet.ReadBuilder` had three branches when picking
the name mapping for a vectorized read:

  1. caller-provided nameMapping → use it
  2. `NETFLIX_UNSAFE_PARQUET_ID_FALLBACK_ENABLED=true` → use null (unsafe
     fallback to position-based field resolution)
  3. default → use `NameMapping.empty()` (safe)

PR apache#16449 removed the deprecated NETFLIX_UNSAFE branch (case 2) but
collapsed the default to `null` rather than `NameMapping.empty()`, making
unsafe position-based resolution the new default. That contradicts the
PR description ("always use NameMapping.empty() (the safe default)") and
silently regresses readers that don't supply an explicit mapping.

Restore the safe default by using `NameMapping.empty()` when no mapping
is provided.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dramaticlly added a commit to dramaticlly/iceberg that referenced this pull request Jun 25, 2026
…NSAFE branch

The prior 1.11 logic in `Parquet.ReadBuilder` had three branches when picking
the name mapping for a vectorized read:

  1. caller-provided nameMapping → use it
  2. `NETFLIX_UNSAFE_PARQUET_ID_FALLBACK_ENABLED=true` → use null (unsafe
     fallback to position-based field resolution)
  3. default → use `NameMapping.empty()` (safe)

PR apache#16449 removed the deprecated NETFLIX_UNSAFE branch (case 2) but
collapsed the default to `null` rather than `NameMapping.empty()`, making
unsafe position-based resolution the new default. That contradicts the
PR description ("always use NameMapping.empty() (the safe default)") and
silently regresses readers that don't supply an explicit mapping.

Restore the safe default by using `NameMapping.empty()` when no mapping
is provided.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dramaticlly added a commit to dramaticlly/iceberg that referenced this pull request Jun 25, 2026
`build.gradle` line 145 sets `oldVersion = "1.11.0"` — revapi compares
the current code against the 1.11.0 released baseline. Section keys
in `.palantir/revapi.yml` correspond to that baseline, so new
breaks accepted during the 1.12.0 dev cycle belong under `"1.11.0"`,
not under a not-yet-released `"1.12.0"` section.

Evidence in-file: the `"1.10.0"` section already contains entries with
justifications like "Removing deprecated code for 1.11.0" — entries added
during the 1.11.0 dev cycle when `oldVersion` was `"1.10.0"`. Same shape
applies now.

This commit:
- Renames the section header `"1.12.0"` -> `"1.11.0"`, merging the new
  entries from PR apache#16449 into the existing 1.11.0 section that was
  already on upstream/main (the partition-stats entries from PR apache#14998).
- Restores the original justifications on the 17 partition-stats entries
  that were rewritten by an earlier fixup commit
  (`fb5ddae9b2 Core: Move partition stats revapi entries to 1.12.0`),
  back to "Removed deprecated functionality for partition stats".
- Drops a duplicate `class org.apache.iceberg.PartitionStats` entry
  that the earlier fixup commit had introduced.

Net effect: the cumulative PR diff against upstream/main is now
additive only (new entries appended to the existing 1.11.0 section,
no churn on existing entries).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@nastra
nastra requested review from pvary and singhpk234 June 25, 2026 09:24
@manuzhang

Copy link
Copy Markdown
Member

@dramaticlly are you still working on this?

dramaticlly added a commit to dramaticlly/iceberg that referenced this pull request Jul 22, 2026
…NSAFE branch

The prior 1.11 logic in `Parquet.ReadBuilder` had three branches when picking
the name mapping for a vectorized read:

  1. caller-provided nameMapping → use it
  2. `NETFLIX_UNSAFE_PARQUET_ID_FALLBACK_ENABLED=true` → use null (unsafe
     fallback to position-based field resolution)
  3. default → use `NameMapping.empty()` (safe)

PR apache#16449 removed the deprecated NETFLIX_UNSAFE branch (case 2) but
collapsed the default to `null` rather than `NameMapping.empty()`, making
unsafe position-based resolution the new default. That contradicts the
PR description ("always use NameMapping.empty() (the safe default)") and
silently regresses readers that don't supply an explicit mapping.

Restore the safe default by using `NameMapping.empty()` when no mapping
is provided.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dramaticlly added a commit to dramaticlly/iceberg that referenced this pull request Jul 22, 2026
`build.gradle` line 145 sets `oldVersion = "1.11.0"` — revapi compares
the current code against the 1.11.0 released baseline. Section keys
in `.palantir/revapi.yml` correspond to that baseline, so new
breaks accepted during the 1.12.0 dev cycle belong under `"1.11.0"`,
not under a not-yet-released `"1.12.0"` section.

Evidence in-file: the `"1.10.0"` section already contains entries with
justifications like "Removing deprecated code for 1.11.0" — entries added
during the 1.11.0 dev cycle when `oldVersion` was `"1.10.0"`. Same shape
applies now.

This commit:
- Renames the section header `"1.12.0"` -> `"1.11.0"`, merging the new
  entries from PR apache#16449 into the existing 1.11.0 section that was
  already on upstream/main (the partition-stats entries from PR apache#14998).
- Restores the original justifications on the 17 partition-stats entries
  that were rewritten by an earlier fixup commit
  (`fb5ddae9b2 Core: Move partition stats revapi entries to 1.12.0`),
  back to "Removed deprecated functionality for partition stats".
- Drops a duplicate `class org.apache.iceberg.PartitionStats` entry
  that the earlier fixup commit had introduced.

Net effect: the cumulative PR diff against upstream/main is now
additive only (new entries appended to the existing 1.11.0 section,
no churn on existing entries).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dramaticlly and others added 15 commits July 23, 2026 09:39
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…DeleteRowSchema

- TestS3FileIOProperties: Add required signer.endpoint property since the
  deprecated default was removed
- TestSparkWriterMetrics: Override checkRowStatistics and
  checkNotExistingRowStatistics to match behavior without
  positionDeleteRowSchema (consistent with Flink tests)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
BaseScan.io() and PositionDelete.set(path, pos, row)/row() still have
callers and cannot be removed yet. Restore their deprecation annotations
to preserve the original removal intent.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…io()

The method had only 4 internal callers (DataScan, BaseDistributedDataScan)
which are trivially replaced with table().io(). Also moves revapi entries
to the 1.12.0 section with unified justification.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ification

All deprecated API removals for this release should be under the "1.12.0"
version key with justification "Removing deprecated API scheduled for
removal in 1.12.0", sorted alphabetically by class/method name.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The `specsById` map carried on `BaseScanTaskResponse` and its builder is
parser context, not part of the REST spec for scan-planning response
models. It was deprecated in 1.11.0 (apache#14485) with a note that visibility
would be reduced in 1.12.0.

Demote `specsById()` getter and `withSpecsById()` setter (plus the
builder's `deleteFiles()` getter) from public to protected so the
parsers and subclasses can still use them while keeping the field out of
the public API.

To preserve cross-package construction paths used by `CatalogHandlers`,
`RESTServerCatalogAdapter`, and tests in `org.apache.iceberg.rest`:

- Add `builder(Map<Integer, PartitionSpec> specsById)` factory on each
  of `PlanTableScanResponse`, `FetchPlanningResultResponse`, and
  `FetchScanTasksResponse` for initial server-side construction.
- Add `toBuilder()` on each response for copy-with-modification patterns
  (used when adapters rebuild a response to inject credentials or
  rewrite status).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…NSAFE branch

The prior 1.11 logic in `Parquet.ReadBuilder` had three branches when picking
the name mapping for a vectorized read:

  1. caller-provided nameMapping → use it
  2. `NETFLIX_UNSAFE_PARQUET_ID_FALLBACK_ENABLED=true` → use null (unsafe
     fallback to position-based field resolution)
  3. default → use `NameMapping.empty()` (safe)

PR apache#16449 removed the deprecated NETFLIX_UNSAFE branch (case 2) but
collapsed the default to `null` rather than `NameMapping.empty()`, making
unsafe position-based resolution the new default. That contradicts the
PR description ("always use NameMapping.empty() (the safe default)") and
silently regresses readers that don't supply an explicit mapping.

Restore the safe default by using `NameMapping.empty()` when no mapping
is provided.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`build.gradle` line 145 sets `oldVersion = "1.11.0"` — revapi compares
the current code against the 1.11.0 released baseline. Section keys
in `.palantir/revapi.yml` correspond to that baseline, so new
breaks accepted during the 1.12.0 dev cycle belong under `"1.11.0"`,
not under a not-yet-released `"1.12.0"` section.

Evidence in-file: the `"1.10.0"` section already contains entries with
justifications like "Removing deprecated code for 1.11.0" — entries added
during the 1.11.0 dev cycle when `oldVersion` was `"1.10.0"`. Same shape
applies now.

This commit:
- Renames the section header `"1.12.0"` -> `"1.11.0"`, merging the new
  entries from PR apache#16449 into the existing 1.11.0 section that was
  already on upstream/main (the partition-stats entries from PR apache#14998).
- Restores the original justifications on the 17 partition-stats entries
  that were rewritten by an earlier fixup commit
  (`fb5ddae9b2 Core: Move partition stats revapi entries to 1.12.0`),
  back to "Removed deprecated functionality for partition stats".
- Drops a duplicate `class org.apache.iceberg.PartitionStats` entry
  that the earlier fixup commit had introduced.

Net effect: the cumulative PR diff against upstream/main is now
additive only (new entries appended to the existing 1.11.0 section,
no churn on existing entries).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
After restoring `NameMapping.empty()` as the default in `Parquet.ReadBuilder`
(commit 8881516), two data-module tests fail because they wrote parquet
files via raw `AvroParquetWriter` (no Iceberg field IDs in the file metadata)
and read them back without providing a `NameMapping`, implicitly relying on
the unsafe positional-fallback ID assignment that the
`NETFLIX_UNSAFE_PARQUET_ID_FALLBACK_ENABLED` config previously enabled by
default. The deprecation message on that config explicitly said
"Fallback ID assignment in Parquet is UNSAFE and will be removed in 1.12.0.
Use name mapping instead."

Honor that guidance:

- `TestGenericData.testTwoLevelList` and
  `TestParquetEncryptionWithWriteSupport.testTwoLevelList` now pass an
  explicit `withNameMapping(MappingUtil.create(schema))` to the reader.
- Add `TestGenericData.testReadWithoutFieldIdsOrNameMappingReturnsNullFields`
  to assert the new strict default behavior: when a parquet file has no
  field IDs and no `NameMapping` is supplied, projected fields read as null
  (rather than being bound by position as before).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…itional-fallback

Same root cause as the data-module migrations in ac9ee16: the test
writes a parquet file via raw AvroParquetWriter (no Iceberg field IDs)
and then reads it back without supplying a NameMapping. Pre-1.12 this
worked via the NETFLIX_UNSAFE_PARQUET_ID_FALLBACK_ENABLED positional
fallback (defaulted to true on upstream/main); after this PR's Parquet
ReadBuilder restores NameMapping.empty() as the default, projected
fields no longer bind by position and the assertion NPEs.

Migrate all three flink versions (v1.20, v2.0, v2.1) to supply
`withNameMapping(MappingUtil.create(schema))`, matching the strict
default and aligning with the deprecation message's guidance to
"Use name mapping instead".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
After restoring `NameMapping.empty()` as the safe default in `Parquet.ReadBuilder`
(commit 8881516), Spark tests that import external Parquet files via
`SparkTableUtil.importSparkTable` and then read them through Iceberg fail
field resolution: the imported files have no Iceberg field IDs and no
`schema.name-mapping.default` property is auto-set, so the strict empty
mapping returns null for every projected field.

Mirror the established pattern from `AddFilesProcedure.ensureNameMappingPresent`
and `BaseTableCreationSparkAction`: when the target Iceberg table does not
already have `schema.name-mapping.default` set, auto-derive a name mapping
from the target schema before importing. Subsequent reads via Iceberg pick
up the property automatically through `BaseReader`.

Applied identically to v3.5, v4.0, and v4.1.

This honors the deprecation guidance Russell Spitzer documented when
deprecating the NETFLIX_UNSAFE positional fallback ("Use name mapping
instead") and brings `importSparkTable` in line with `AddFilesProcedure`,
which has been doing this for some time.

Verified on Spark 4.1 via the full `org.apache.iceberg.spark.source.*`
test package (`-DtestParallelism=8`); previously-failing
`TestIcebergSourceHadoopTables.testTableWithInt96Timestamp` and
`TestIdentityPartitionData.testProjections` now pass with no
collateral failures elsewhere.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ate TestSparkParquetReader fixtures

After restoring `NameMapping.empty()` as the safe default in `Parquet.ReadBuilder`
(commit 8881516), `IcebergGenerics.read(table)` started failing field
resolution on tables whose data files lack Iceberg field IDs. Pre-1.12 the
unsafe positional-fallback path masked this; now the strict default refuses
to bind by position.

`GenericReader` (data module) never consulted `schema.name-mapping.default`
even though every Iceberg table that reads non-Iceberg-written files is
expected to carry it. Spark's `BaseReader` already reads the property
(`BaseReader.java:100`); bring `GenericReader` in line with that pattern so
`IcebergGenerics.read(table)` auto-applies the mapping when present.

Also migrate `TestSparkParquetReader.testInt96TimestampProducedBySparkIsReadCorrectly`
(v3.5 / v4.0 / v4.1) — the test creates a `HadoopTables` table directly
(bypassing `SparkTableUtil.importSparkTable`, so the auto-set in commit
9ebb273 doesn't reach it) and reads files written by raw Spark
`ParquetWriteSupport` without Iceberg field IDs:

- `rowsFromFile`: pass `.withNameMapping(MappingUtil.create(schema))` on
  the direct `Parquet.read(...)` call.
- `tableFromInputFile`: set `schema.name-mapping.default` at table creation
  time so the `GenericReader` change above picks it up automatically.

Verified:
- `:iceberg-data:test` clean
- Targeted `TestSparkParquetReader.testInt96TimestampProducedBySparkIsReadCorrectly`
  passes on v3.5, v4.0, v4.1
- `:iceberg-flink:iceberg-flink-2.1:test` full sweep clean (30m,
  `-DtestParallelism=8`)
- Spotless / checkstyle / revapi clean across all versions

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Migrate the vectorized dictionary-encoded parquet read test off
unsafe positional-fallback ID assignment by attaching a NameMapping
created from the schema to the Parquet read builder.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Upstream commit 773907d ("Core: Add id tracking to MetricsConfig")
removed checkNotExistingRowStatistics() from the abstract
TestWriterMetrics parent and removed MetricsConfig.forPositionDelete(Table).
After rebasing onto that commit, our branch had orphaned overrides and a
divergent revapi justification.

- Remove the now-orphaned @OverRide checkNotExistingRowStatistics from
  TestSparkWriterMetrics in spark v3.5/v4.0/v4.1 (the parent method no
  longer exists); the checkRowStatistics override remains valid.
- Align revapi.yml justifications with upstream: use "Deprecated for
  removal in 1.12.0" for MetricsConfig::forPositionDelete(Table) and the
  uniform partition-stats wording.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- AWS: Rename legacySignerProperties to signerUriResolution (no legacy
  properties remain) and add signerEndpointIsRequired coverage for the
  now-required signer.endpoint precondition.
- Core: Replace hardcoded "%1F"/"%2E" separator literals in TestRESTUtil
  and TestResourcePaths with the canonical NAMESPACE_SEPARATOR_URLENCODED_UTF_8
  constants so the tests stay coupled to source.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
// TODO change to required in 1.12.0
if (!properties().containsKey(S3_SIGNER_ENDPOINT)
&& !properties().containsKey(RESTCatalogProperties.SIGNER_ENDPOINT)) {
LOG.warn(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adutra can you help check the deprecation align with your original goal in #15451.

  • Removes S3_SIGNER_URI / S3_SIGNER_ENDPOINT / S3_SIGNER_DEFAULT_ENDPOINT
  • RESTCatalogProperties.SIGNER_ENDPOINT is now required

// Fallback to the signature without fieldId if not overridden
return createStructReader(fieldReaders, structType);
}
protected abstract ParquetValueReader<T> createStructReader(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RussellSpitzer I think with createStructReader(fieldReaders, structType) removed and all subclass override the method, this can now become abstract method, do you think this is safe to apply?

Comment on lines -150 to -151
public static ManifestReader<DataFile> read(ManifestFile manifest, FileIO io) {
return read(manifest, io, null);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RussellSpitzer I think the public static read method might be used a lot outside iceberg package, want to double check this is ok to remove with 1 release between deprecation and removal

* @deprecated will be removed in 1.12.0; use name mapping instead
*/
@Deprecated
public static final ConfigEntry<Boolean> NETFLIX_UNSAFE_PARQUET_ID_FALLBACK_ENABLED =

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rdblue I want to double check with you on this. More in #16449 (comment), I end up changing few spark and Flink test for using NameMapping.empty() instead of null (unsafe positional ID assignment).

* TableIdentifier, SnapshotMode)} instead.
*/
@Deprecated
public static LoadTableResponse loadTable(Catalog catalog, TableIdentifier ident) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gaborkaszab I think this 2 arguments public static method might be used a lot outside iceberg package, want to double check this is ok to remove with 1 release between deprecation and removal.

/**
* @deprecated since 1.11.0, will be removed in 1.12.0.
*/
@Deprecated

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nastra want to check with you that on not remove this for now, as the HadoopFileIO today still implement the required method defined in HadoopConfigurable interface. Can follow up with better removal cycle in 1.13 if needed.


@SuppressWarnings("deprecation")
public static Stream<Arguments> legacySignerProperties() {
public static Stream<Arguments> signerUriResolution() {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nastra I renamed method source and UT above as after this PR we no longer have legacySignerProperties

}

/**
* @deprecated since 1.11.0, will be removed in 1.12.0; use {@link BaseScan#fileIO()} instead.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For existing scan which use io to read manifests, I end up using table().io() instead of fileIO().get()` as it reads better

*/
@Deprecated
public B withSpecsById(Map<Integer, PartitionSpec> specs) {
protected B withSpecsById(Map<Integer, PartitionSpec> specs) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@singhpk234 can you help check the visibility change from public to protected align with your original goal, also end up providing sanctioned entry point of witSpecById in builder for BaseScanTaskResponse,FetchPlanningResultResponse,FetchScanTasksResponse,PlanTableScanResponse,

@u70b3 u70b3 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working through this broad cleanup. I am new to the Iceberg community, so please correct me if I have missed an intended calling constraint. I ran focused reproductions against the current PR head and found two cases that seem worth checking.

"Table %s does not exist", sourceTableIdentWithDB);
}

ensureNameMappingPresent(targetTable);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we also ensure the name mapping in the deepest retained importSparkPartitions overload (or otherwise ensure that every public overload reaches this initialization)? I may be missing an intended precondition, but I reproduced this on the current PR head by adapting the existing TestIdentityPartitionData setup to call public getPartitions + importSparkPartitions directly. Both Parquet parameterizations failed: the partition columns remained correct, but every id and message value was read as null. Adding ensureNameMappingPresent(targetTable) to the deepest overload made all 5 testFullProjection parameterizations pass. I ran: ./gradlew :iceberg-spark:iceberg-spark-4.1_2.13:test --tests "org.apache.iceberg.spark.source.TestIdentityPartitionData.testFullProjection".

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @u70b3 , I think after some deep dive we decided to keep NETFLIX_UNSAFE_PARQUET_ID_FALLBACK_ENABLED for a few more releases given the silent behavior change of imported parquet files in #17444

@@ -93,20 +89,7 @@ public B withFileScanTasks(List<FileScanTask> tasks) {
return self();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could withFileScanTasks(null) clear the builder's derived deleteFiles as well? I may be misunderstanding the builder contract, but I reproduced this by creating a completed response whose task has a delete file, then calling response.toBuilder().withPlanStatus(FAILED).withFileScanTasks(null).build(). It throws IllegalArgumentException: deleteFiles should only be returned with fileScanTasks that reference them because the copied delete files remain. Setting deleteFiles to null when tasks are cleared made the focused test pass. I ran: ./gradlew :iceberg-core:test --tests "org.apache.iceberg.rest.responses.TestPlanTableScanResponseParser.toBuilderClearsDeleteFilesWhenClearingFileScanTasks".

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a good callout, applied suggestion to remove deleteFiles in 7024529

Reverts the removal of SystemConfigs.NETFLIX_UNSAFE_PARQUET_ID_FALLBACK_ENABLED,
the Parquet.ReadBuilder change it guarded, and everything that followed from it:
the GenericReader name-mapping lookup, the SparkTableUtil deprecation removals
and name-mapping auto-set, and the migrated Parquet reader tests in data, flink
and spark.

That config defaulted to true, so removing it changes how every Iceberg
deployment reads Parquet files without field IDs, and the failure mode is silent
nulls rather than an error. It needs a dedicated review thread on the migration
path instead of riding along in a broad deprecation sweep.

SparkTableUtil moves with it in full, including its own "@deprecated since
1.11.0, will be removed in 1.12.0" members, so that exactly one PR owns the file
and the two do not conflict.

This PR keeps every other 1.12.0 removal.
BaseScanTaskResponse.Builder.withFileScanTasks derives deleteFiles from the
tasks, but only on the non-null branch, so clearing the tasks left the previously
derived delete files behind. Combined with the removal of withDeleteFiles in this
PR, there was no longer any way to clear them, and

  response.toBuilder().withPlanStatus(FAILED).withFileScanTasks(null).build()

failed validation with "deleteFiles should only be returned with fileScanTasks
that reference them".

Derives on both branches so clearing the tasks clears the derived delete files,
and reads the tasks parameter rather than the field, which is what the guard
always meant.

Reported-by: u70b3

@singhpk234 singhpk234 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @dramaticlly, just took a pass on rest changes in this cycles, added comments inline

Comment on lines +84 to +88
this.deleteFiles =
tasks == null
? null
: DeleteFileSet.of(
() -> tasks.stream().flatMap(task -> task.deletes().stream()).iterator());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this required ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the logic is revised slightly so that now we can clean this.deleteFiles when passing null tasks. This is needed as we are removing the seter of withDeleteFiles in the same PR, so need a way to reset the internal deleteFiles if they are not longer applicable. Before the change it will only set this.deleteFiles if we have a valid task but not be able to clear

Comment on lines +77 to +89
/**
* Returns a builder pre-populated with this response's fields, suitable for producing a copy with
* one or more fields modified.
*/
public Builder toBuilder() {
return new Builder()
.withPlanStatus(planStatus)
.withErrorResponse(errorResponse)
.withPlanTasks(planTasks())
.withFileScanTasks(fileScanTasks())
.withCredentials(credentials())
.withSpecsById(specsById());
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this required ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this to provide a way for class outside the package to create the builder correctly as now the specById is reduced to protected scope. Current user are org.apache.iceberg.rest.RESTServerCatalogAdapter and org.apache.iceberg.rest.TestRESTScanPlanning

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants