Repository navigation
Conversation
There was a problem hiding this comment.
@lucasfang, I left two comments for this introduction. PTAL.
| PAIMON_ASSIGN_OR_RAISE(bool is_format_table, | ||
| TableTypeDefine::IsFormatTable(data_schema->Options())); | ||
| if (is_format_table) { | ||
| return FormatTable::Create(fs_, table_path, identifier, data_schema, |
There was a problem hiding this comment.
Bind format tables to the table-specific filesystem before returning them. When DATA_TOKEN_ENABLED is true and no filesystem was explicitly supplied, fs_ is the catalog-wide filesystem; only GetTableFileSystem(identifier) creates the RestTokenFileSystem that fetches and refreshes this table's credentials. This new format-table branch returns before that call. FormatTable::ForContext() preserves the bound filesystem, and its scan/read/write implementations access storage through it, so even supplying WithCatalog() on an operation context cannot recover the table token. On deployments where storage access requires the table-scoped credentials, GetTable() succeeds but subsequent file operations fail. Resolve the filesystem as the managed and system-table branches do, and add a format-table regression with data tokens enabled that verifies the token endpoint is used on storage access.
| PAIMON_ASSIGN_OR_RAISE(named_branch, impl_->identifier_->GetBranchName()); | ||
| } | ||
| if (named_branch || options.count(Options::BRANCH) != 0) { | ||
| options[Options::BRANCH] = branch; |
There was a problem hiding this comment.
Canonicalize identifier aliases of the main branch before adding the branch option. For Identifier("db", "tbl$branch_MAIN"), the catalog and Identifier::GetBranchNameOrDefault() resolve the table to main, but ResolveBranch() reads GetBranchName() and only normalizes blank strings, so this code inserts branch=MAIN. A context built with ScanContextBuilder(path).WithCatalog(catalog, identifier) then makes TableScan::Create() look for a schema under branch/branch-MAIN instead of the existing main schema; passing it to the catalog-loaded table's NewScan() instead fails with a branch contradiction. Before this change the scan builder did not inject that option and the same main-table scan worked. Canonicalize the identifier's main alias while preserving the case-sensitive semantics of explicitly named branch options, and cover both static and loaded-table scan entrypoints with $branch_MAIN.
Purpose
Linked issue: close #526
The current
Table::NewScan/NewRead/NewWrite/NewCommitmethods route back through context-based factories, so calling an operator on a loaded table does not bind it to that table's schema and storage identity. Table-kind dispatch is also concentrated intable.cpp, with format tables exposed through a separate handle.Introduce a common table hierarchy so
Catalog::GetTable()returns the appropriate managed, format or system table, and operator creation dispatches through that implementation.FileStoreTablewith append-only and primary-key implementations, reusing the FileStore factories from refactor(table): extract file store factories #516 as merged into main. FileStore continues to derive its branch from options.FormatTableandSystemTableimplement the common Table interface. System tables expose their own schemas and reject writes and commits.TableFactoryand the virtual operator methods. Preserve main's precise file-index evaluation behavior through both entrypoints.This is the hierarchy step of #459, following #516. Execution-context separation and general Table Copy/time-travel APIs remain separate follow-ups.
Tests
Full build and all 36 CTest targets passed on commit
0d2ddf52:git diff apache/main HEAD --checkpassed.Regression coverage includes catalog type dispatch, loaded schema/path/filesystem binding, explicit branch conflicts and aliases, builder retries after failed validation, deferred catalog lifetime, URI-map merging for main/fallback reads, changelog sequence numbers, system-table snapshot selection, and precise-index entrypoint parity.
API and Format
Tablebecomes abstract, with a virtual destructor and virtual operator creation methods. Callers that directly constructed Table should load it through the catalog.Table::LatestSchema()andFormatTable::LatestSchema()toGetSchema(), without compatibility aliases. The accessor returns the bound schema without metadata I/O; reload through the catalog to refresh it.CurrentBranch()from the common Table interface; managed-table branch handling belongs to FileStoreTable.FormatTablederives from Table.Catalog::GetFormatTable()remains available for typed callers.Create()signatures remain unchanged. Catalogs must be owned bystd::shared_ptrwhen loading global system tables, which retain the catalog for deferred reads.Documentation
Update the catalog and format-table guides to describe common catalog dispatch, bound-table operator semantics, schema access, branch validation and global-system-table ownership.
Generative AI tooling
Generated-by: OpenAI Codex (GPT-6)