Move Connection#describe to SchemaStatements helpers#2545
Merged
Conversation
c13cc7b to
b17e082
Compare
3 tasks
7dfd27e to
4dd9c01
Compare
73363fd to
855f3ad
Compare
3 tasks
Contributor
There was a problem hiding this comment.
Pull request overview
This PR moves Oracle object “describe”/resolution logic off the low-level OracleEnhanced::Connection wrapper and into private SchemaStatements helpers, aligning Oracle Enhanced’s schema introspection structure with Rails’ bundled adapters and routing the catalog lookup through the adapter’s normal select_one path (logging/instrumentation/query cache).
Changes:
- Add private
resolve_data_source_nameandextract_schema_qualified_namehelpers toOracleEnhanced::SchemaStatementsand use them in place of_connection.describe(...). - Remove
describe(and related raw-cursor helpers) fromOracleEnhanced::Connection, and drop thedescribeforwarding shims fromOCIConnectionandJDBCConnection. - Update connection specs to cover the new helper behavior, including db-link rejection regression coverage.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb | Replaces describe expectations with coverage for resolve_data_source_name / extract_schema_qualified_name, including db-link rejection tests. |
| lib/active_record/connection_adapters/oracle_enhanced_adapter.rb | Switches adapter call sites from _connection.describe to resolve_data_source_name. |
| lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb | Introduces the new private helpers and updates SchemaStatements call sites to use them. |
| lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb | Removes the describe shim that previously exposed the base private method. |
| lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb | Removes the describe shim that previously exposed the base private method. |
| lib/active_record/connection_adapters/oracle_enhanced/connection.rb | Removes describe and raw cursor select helpers; exposes owner via attr_reader for default schema resolution. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
b5420c7 to
479f4a5
Compare
yahonda
added a commit
to yahonda/oracle-enhanced
that referenced
this pull request
Apr 20, 2026
…data_source_name Two follow-up specs surfaced in review of rsim#2545: - Assert that `resolve_data_source_name` emits a `SCHEMA` `sql.active_record` event. The previous `Connection#describe` path drove a raw cursor and emitted no event; this locks in the switch to the adapter's `select_one` path so a future refactor cannot silently regress it. - Extend synonym-cycle coverage beyond the A<->B case to a three-hop A->B->C->A chain, proving the `[owner, identifier]` visited Set catches cycles of arbitrary length, not only pairs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
78ce74c to
b8b0e6a
Compare
Replace the private `describe(name)` method on `OracleEnhanced::Connection` with a private `resolve_data_source_name(name)` helper on the adapter's `SchemaStatements` module. Rails' bundled adapters (mysql2, trilogy, postgresql) place introspection on the adapter itself rather than on a connection wrapper -- this aligns oracle-enhanced with that pattern. The new helper runs its catalog query through the adapter's `select_one` path, so it participates in logging, instrumentation, and the query cache. The previous implementation bypassed all of that via a raw cursor in `_select_one`. A regression spec subscribes to `sql.active_record` and asserts that a `SCHEMA` event fires, locking the instrumentation path in. Synonym resolution runs as an iterative loop that tracks visited `[owner, identifier]` pairs in a Set, so a circular synonym -- whether two-hop (`A <-> B`) or multi-hop (`A -> B -> C -> A`) -- raises OracleEnhanced::ConnectionException with "looping chain of synonyms" (Oracle's own phrasing for ORA-01775) instead of recursing until the Ruby stack overflows. Regression specs cover both shapes. `def describe(name); super; end` shims on OCIConnection/JDBCConnection and the `_select_one` / `_select_value` helpers that existed only to support `describe` are removed. `_oracle_downcase` stays on the base Connection class since OCI/JDBC still use it for column metadata. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
b8b0e6a to
f37ca48
Compare
This was referenced Apr 20, 2026
yahonda
added a commit
that referenced
this pull request
Apr 24, 2026
Move Connection#describe to SchemaStatements helpers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Alternative to #2498.
Instead of splitting
OracleEnhanced::Connectioninto a dispatcher plus aDatabaseDescriptionmodule, this PR aligns with how Rails' bundled adapters (mysql2, trilogy, postgresql) handle schema introspection: the logic lives as private helpers onSchemaStatements, not on the connection wrapper.OracleEnhanced::SchemaStatements:extract_schema_qualified_name(string)— pure string parsing. Mirrors the helpers of the same name in Rails' PostgreSQL and MySQL adapters. Returns[schema, identifier]; a non-qualified name returns[nil, identifier]. Oracle-specific bits (rejecting db links, upcasing valid identifiers so catalog lookups match the stored upper-case names) live here and nowhere else.resolve_data_source_name(name)— calls the extract helper, defaults the schema to_connection.ownerwhen unqualified, runs the catalog query, and iteratively follows synonyms. ASetof visited[owner, identifier]pairs guards against looping synonym chains. RaisesOracleEnhanced::ConnectionExceptionwhen the object does not exist, or with "looping chain of synonyms" (Oracle's own ORA-01775 phrasing) if a cycle is detected. The inline doc comment explicitly contrasts_connection.owner(the adapter's configured default schema, fromconfig[:schema]orconfig[:username]) againstSYS_CONTEXT('USERENV', 'CURRENT_SCHEMA'), which can diverge afterALTER SESSION SET CURRENT_SCHEMA.select_onepath, so it participates in logging, instrumentation, and the query cache. The previousdescribebypassed all of that by driving a raw cursor through_select_one/prepare/fetch._connection.describe(name)call sites inschema_statements.rbandoracle_enhanced_adapter.rbwithresolve_data_source_name(name).describe,_select_one, and_select_valuefromOracleEnhanced::Connection. Exposeattr_reader :ownerso the helper can read the default schema.def describe(name); super; endshims fromOCIConnectionandJDBCConnection.if name.include?("@")branch on master has hadraise ArgumentError "db link is not supported"(missing comma) since 2018, so it silently never raised. The new helper uses the correctraise ArgumentError, "..."form, and a regression spec locks it in.Why this shape
describewas effectively internal plumbing that every caller immediately destructured into[owner, table_name]. It did not need to be a public method on the connection wrapper, and putting it there made it awkward to route through the adapter's normal query path. Moving it toSchemaStatementsmatches the convention used byextract_schema_qualified_name/quoted_scopein other Rails adapters.Splitting
extract_schema_qualified_nameout ofresolve_data_source_namekeeps the parse step pure: no database access, no session state. Whichever follow-up path we take on synonym resolution —all_objects(#2521) orDBMS_UTILITY.NAME_RESOLVE(#2531) — the catalog-lookup body is the only thing that needs to change.Related
#2546 is a separate, independent cleanup that de-duplicates
_oracle_downcaseagainstQuoting#oracle_downcase. It can be merged before or after this PR.Test plan
bundle exec rspec spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb(MRI / OCI)bundle exec rspecresolve_data_source_namespecs cover: existing table, non-existing table (raisesConnectionException), cross-schema table, cross-schema with mixed case, view, cross-schema view, materialized view, private synonym, public synonym, two-hop looping synonym chain (A↔B), three-hop looping synonym chain (A→B→C→A), and db-link rejectionextract_schema_qualified_namespecs cover unqualified / already upcase / lowercase qualified / mixed-case qualified / Symbol input / db-link rejection / non-valid-identifier passthroughbundle exec rubocopresolve_data_source_nameemits aSCHEMAsql.active_recordevent via AR'sselect_one, proving the refactor exercises the adapter's query machinery (the previous raw-cursor path did not)🤖 Generated with Claude Code