Skip to content

refactor(scan) refactor PlanContext to allow for different manifest sources - #3108

Open
xanderbailey wants to merge 2 commits into
apache:mainfrom
xanderbailey:xb/generalize_plan_context
Open

refactor(scan) refactor PlanContext to allow for different manifest sources#3108
xanderbailey wants to merge 2 commits into
apache:mainfrom
xanderbailey:xb/generalize_plan_context

Conversation

@xanderbailey

@xanderbailey xanderbailey commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

What changes are included in this PR?

Previously PlanContext only held a snapshot reference which makes it very hard to be extended for incremental append scans since they require multiple manifest lists so we introduce ManifestSource as a way to represent a source of ManifestFile.

This has the added benefit now having a non-optional PlanContext on the TableScan as a result of EmptySource. The reason this wasn't possible before was because metadata without any snapshots couldn't construct a PlanContext - this isn't true anymore. The result of this is that previously SELECT "not_a_column" FROM table would actually skip schema validation before if there wasn't a snapshot in the metadata.

This refactor has the benefit of creating a single pub (crate) method on the PlanContext. Before it was the case that the PlanContext had a load manifest_list method that it then passed into the other build_manifest_file_contexts method which seemed like a leaky abstraction to me.

We're also refactoring the actual planning in TableScan scan out into a reusable plan.rs such that we can directly use it in an append scan.

There are alternatives here for the reviewer to consider:

  1. build_manifest_file_contexts could take Vec but you'd still need to generalize the PlanContext to remove the get_manifest_list since this only makes sense for a single snapshot scan.
  2. PlanContext could store a list of manifest files but that involves resolving them when we build the table scan rather than we ask for the plan, this would make TableScanBuilder::build async and eagerly resolve the manifest files which I don't think is desirable.

Are these changes tested?

AI Disclosure

manifest_source: Arc::new(SnapshotSource::new(snapshot.clone())),
table_metadata: self.table.metadata_ref(),
snapshot_schema: schema,
plan_schema: schema,

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.

Renamed this to a more generic "plan_schema"


/// Returns the partition filter for a manifest. See [`PartitionFilterCache::get`] for the
/// always-true fallback when the manifest's spec cannot be resolved against the scan schema.
fn get_partition_filter(&self, manifest_file: &ManifestFile) -> Result<Arc<BoundPredicate>> {

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.

moved private method down to make pub (crate) more obvious

plan_context: Option<PlanContext>,
/// The snapshot being scanned, if this table has at least one snapshot.
/// When absent the scan yields no rows.
snapshot: Option<SnapshotRef>,

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.

needed because TableScan has a pub api to ask for it's snapshot and I didn't want to break that

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.

1 participant