Skip to content

fix(schema): enforce executable type evolution - #681

Open
QuakeWang wants to merge 2 commits into
apache:mainfrom
QuakeWang:alter-type-verify
Open

fix(schema): enforce executable type evolution#681
QuakeWang wants to merge 2 commits into
apache:mainfrom
QuakeWang:alter-type-verify

Conversation

@QuakeWang

Copy link
Copy Markdown
Member

Purpose

ALTER COLUMN TYPE previously accepted Arrow-castable type pairs without guaranteeing Paimon-compatible conversion of historical files. Predicates, statistics, and global indexes could therefore use incompatible physical-type semantics.

Brief change log

  • Add explicit Paimon-compatible type-evolution executors and historical-schema preflight validation.
  • Cast old files to the current logical schema and fail open for unsafe predicate or statistics pruning.
  • Normalize bounded character and binary writes after type evolution.
  • Record global-index build schema IDs and ignore schema-incompatible index entries.
  • Apply the validation consistently to filesystem, REST catalog, and DataFusion paths.

Tests

  • Workspace format, build, and clippy checks
  • Paimon and REST server all-target tests
  • DataFusion integration tests with Spark fixtures
  • Vortex end-to-end test

API and Format

Adds an optional build_schema_id to global-index metadata. Legacy index entries remain readable.

Documentation

Documents the supported type-evolution matrix and safety restrictions.

ALTER TYPE admitted Arrow-castable pairs without guaranteeing Paimon-compatible reads of historical files. Predicate pruning and global indexes could also retain stale physical-type semantics.

Add explicit evolution executors and history preflight checks, apply safe residual filtering and writer normalization, and fence schema-incompatible global index entries across catalog and DataFusion paths.

Signed-off-by: QuakeWang <wangfuzheng0814@foxmail.com>
{"name": "_INDEX_META", "type": ["null", "bytes"], "default": null},
{"name": "_SOURCE_META", "type": ["null", "bytes"], "default": null}
{"name": "_SOURCE_META", "type": ["null", "bytes"], "default": null},
{"name": "_BUILD_SCHEMA_ID", "type": ["null", "long"], "default": null}

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.

What is it?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It records the table schema ID used to build a global-index entry. It closes a race with ALTER COLUMN TYPE: schema evolution does not advance the data snapshot, so an index built with the old field type may still pass the latest-snapshot commit guard. Readers compare the indexed field types from this schema with the current schema and ignore incompatible entries. Legacy and Java entries leave it null and are handled conservatively through schema history.

@JingsongLi JingsongLi 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.

The addition of _BUILD_SCHEMA_ID breaks compatibility with older Rust readers. Testing has confirmed that the new writer produces two Index Manifests, causing the current main reader to report unknown FileKind: 7.

@QuakeWang

QuakeWang commented Aug 17, 2026

Copy link
Copy Markdown
Member Author

@JingsongLi Thanks, confirmed. The nested _BUILD_SCHEMA_ID extension is not backward compatible with the current Rust fast decoder. I see two safe options:
(1) remove build-schema provenance from this PR and use the conservative schema-history fallback, which preserves the current Java format but cannot distinguish indexes rebuilt after a type change from legacy indexes; or (2) store it as a trailing nullable top-level IndexManifestEntry field, which the current main reader already skips while retaining the ALTER/index-commit race guard. Would you prefer removing the field from this PR, or is the top-level optional extension acceptable?

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants