Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces a typed, owned GetObjects metadata tree in sf_core and adds a new DatabaseDriverV1::connection_get_objects_typed API, while refactoring the existing connection_get_objects Arrow result-set path to reuse the same underlying metadata-fetching logic to avoid duplication and preserve existing ordering/null/empty semantics.
Changes:
- Adds typed metadata tree structs (
CatalogMetadata,DbSchemaMetadata,TableMetadata) and exposes them via thedatabase_driver_v1module exports. - Introduces
DatabaseDriverV1::connection_get_objects_typedand refactors the legacy Arrowconnection_get_objectsto build batches from the typed tree. - Adds unit tests validating ordering and null/empty behavior when converting typed metadata to Arrow batches.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
sf_core/src/apis/database_driver_v1/mod.rs |
Re-exports new typed metadata structs so they’re available to API consumers. |
sf_core/src/apis/database_driver_v1/get_objects.rs |
Implements typed metadata tree, new typed API entrypoint, refactors Arrow path to reuse typed tree, and adds tests for behavioral parity. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.
Suppressed comments (1)
sf_core/src/apis/database_driver_v1/get_objects.rs:240
- The doc comment here says “A
Nonechild collection means the requested depth stopped at its parent”, but onlyCatalogMetadata::db_schemasandDbSchemaMetadata::tablesare optional.TableMetadata::columnsis always aVec, so callers can’t interpretNone/Some(Vec::new())semantics for columns from this documentation as written. Please clarify that theNone/empty distinction applies to the optional child vectors only.
/// Unlike [`Self::connection_get_objects`], this API does not encode the
/// metadata into an Arrow result-set handle. A `None` child collection
/// means the requested depth stopped at its parent; `Some(Vec::new())`
/// means that level was requested but matched no objects.
| depth: i32, | ||
| ) -> Result<RecordBatch, ApiError> { | ||
| match depth { | ||
| DEPTH_CATALOGS => build_catalogs_batch( |
There was a problem hiding this comment.
why can't build_catalogs_batch and analogous methods work on constructed metadata tree instead of requiring to parse it to non-typed strings?
| #[derive(Debug, Clone, PartialEq, Eq)] | ||
| pub struct CatalogMetadata { | ||
| pub catalog_name: String, | ||
| pub db_schemas: Option<Vec<DbSchemaMetadata>>, |
There was a problem hiding this comment.
there doesn't seem to be any difference in handling None vs handling empty vector here - maybe we can equate the two and drop the option whatsoever
| #[derive(Debug, Clone, PartialEq, Eq)] | ||
| pub struct DbSchemaMetadata { | ||
| pub db_schema_name: String, | ||
| pub tables: Option<Vec<TableMetadata>>, |
There was a problem hiding this comment.
there doesn't seem to be any difference in handling None vs handling empty vector here - maybe we can equate the two and drop the option whatsoever
| /// `None` at column depth because `SHOW COLUMNS` does not return table type. | ||
| pub table_type: Option<String>, | ||
| /// Columns are empty when the requested depth stops at tables. | ||
| pub columns: Vec<ColumnDescriptor>, |
There was a problem hiding this comment.
there doesn't seem to be any difference in handling None vs handling empty vector here - maybe we can equate the two and drop the option whatsoever
| pub table_name: String, | ||
| /// `Some("TABLE")` or `Some("VIEW")` when table metadata was requested; | ||
| /// `None` at column depth because `SHOW COLUMNS` does not return table type. | ||
| pub table_type: Option<String>, |
There was a problem hiding this comment.
Add concrete enum to represent Table or View variants.
| /// metadata into an Arrow result-set handle. A `None` child collection | ||
| /// means the requested depth stopped at its parent; `Some(Vec::new())` | ||
| /// means that level was requested but matched no objects. | ||
| pub async fn connection_get_objects_typed( |
There was a problem hiding this comment.
new public api method has zero test coverage
## Stack SNOW-2912540 typed session parameters, merge order: 1. [#1339](https://github.com/snowflake-eng/drivers/pull/1339) proto + `sf_core` (merged) 2. [#1340](https://github.com/snowflake-eng/drivers/pull/1340) Python — typed `SessionParametersProxy` (base of #1341) 3. [#1341](https://github.com/snowflake-eng/drivers/pull/1341) JDBC — typed `ParametersRegistry` (**this PR's base**) 4. **This PR** — ODBC typed `ConfigSetting` reads 5. [#1629](https://github.com/snowflake-eng/drivers/pull/1629) drop the deprecated string wire fields (stacked on this branch) ## Summary - The independent session-parameter read sites (autocommit, decimal-as-int, big-number-as-string, max-varchar-size, array-bind threshold, metadata-context bool) plus the TZ-offset-format cache now read `ConnectionGetParameterResponse.typed_value` (`ConfigSetting`) instead of parsing a re-derived dispring. - Three shared helpers (`config_setting_bool` / `config_setting_u64` / `config_setting_string`) live in `api::utils` so those call sites do not each duplicate the oneof match. Native variants are preferred; `string_value` remains a fallback. Non-string variants still collapse to `None` for string-typed parameters such as `TIMESTAMP_TZ_OUTPUT_FORMAT`. - Not doing the full `ParametersRegistry`-style consolidation (dedup of the near-identical RPC-fetch helpers across `connection.rs` / `statement.rs` / `catalog.rs`). That is independent of the typing fix. Merge-resolution restores after catching up to #1341 (from [#1656](https://github.com/snowflake-eng/drivers/pull/1656)): - `select_binding_mode` again requires `threshold > 0` before CSV/stage binding, so `CLIENT_STAGE_ARRAY_BINDING_THRESHOLD=0` stays on inline JSON (same as Python). - `SQLGetTypeInfo` IRD schema again tags string columns as `SQL_WVARCHAR` and `INTERVAL_PRECISION` as `SQL_SMALLINT`, with the corresponding `type_info_tests` restored. ## Test plan - [x] `cargo test -p odbc --lib` — helpers plus restored `type_info_tests` (`string_columns_are_tagged_wvarchar`, `interval_precision_is_smallint_num_prec_radix_is_integer`) - [x] `cargo clippy -p odbc` / `cargo fmt -p odbc` on changed files - [ ] CI `odbc_tests` on this branch after the merge-fix (the three e2e cases that failed on the pre-fix run: all-NULL row with threshold 0; GetTypeInfo WVARCHAR / SMALLINT IRD) --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Filip Pawłowski <sfc-gh-fpawlowski@users.noreply.github.com> GitOrigin-RevId: 51ab345
Summary
sf_coreDatabaseDriverV1::connection_get_objects_typedalongside the existing Arrow result-set APIconnection_get_objectspath encode its Arrow batch from the same typed tree, avoiding duplicate metadata-fetch logicAPI
The tree is represented by:
CatalogMetadataDbSchemaMetadataTableMetadataColumnDescriptorOptional child vectors distinguish a depth cutoff (
None) from a requested level with no matches (Some(Vec::new())).Testing
cargo test -p sf_core --lib get_objects::tests— 41 passedcargo test -p sf_core --lib— 1697 passed, 1 ignoredcargo check -p sf_core --all-targetscargo clippy -p sf_core --libcargo doc -p sf_core --no-depscargo fmt --all -- --checkgit diff --check