-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Fixes #23387, #14238: Oracle View Definitions and Filtering #25189
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Code Review
|
| Auto-apply | Compact |
|
|
Was this helpful? React with 👍 / 👎 | This comment will update automatically (Docs)
| if schema: | ||
| self.get_all_view_definitions( | ||
| connection, ORACLE_VIEW_DEFINITIONS_BY_SCHEMA, schema | ||
| ) | ||
| else: | ||
| self.get_all_view_definitions(connection, ORACLE_ALL_VIEW_DEFINITIONS) | ||
|
|
||
| return self.all_view_definitions.get(key, "") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Details
The get_view_definition function calls get_all_view_definitions when a key is not found in the cache. However, if views from different schemas are queried in sequence, subsequent schema-filtered queries will only add views from that specific schema to the cache.
The problem is that when a view is not found in the cache with a schema filter, the code fetches views only for that schema. But the cache reset logic only resets when current_db changes, not when switching between schemas. This means:
- First call with schema="schema1" populates cache with schema1's views
- Second call with schema="schema2" adds schema2's views to existing cache (correct behavior)
- Third call with schema=None will call
ORACLE_ALL_VIEW_DEFINITIONS- which is fine
However, the real issue is that if get_view_definition is called with a schema that doesn't have the requested view, it will return an empty string without ever checking if the view exists in another schema. This may be intentional behavior but could lead to confusion.
Consider adding a comment to clarify this is expected behavior, or consider whether the function should fall back to checking other schemas if the view isn't found in the specified schema's cache.
| if schema: | ||
| result = connection.execute(sql.text(query), {"owner": schema}) | ||
| else: | ||
| result = connection.execute(query) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Details
In get_all_view_definitions, when schema is provided, the query is wrapped with sql.text() before execution:
result = connection.execute(sql.text(query), {"owner": schema})But when no schema is provided, the query is executed directly without wrapping:
result = connection.execute(query)This inconsistency could cause issues depending on SQLAlchemy version. Modern SQLAlchemy 2.0+ requires text() wrapping for raw SQL strings. If the code runs with SQLAlchemy 2.0+, the non-schema branch may fail or emit deprecation warnings.
Suggested fix: Consistently wrap both queries with sql.text():
if schema:
result = connection.execute(sql.text(query), {"owner": schema.upper()})
else:
result = connection.execute(sql.text(query))|
|
||
| ORACLE_VIEW_DEFINITIONS_BY_SCHEMA = textwrap.dedent( | ||
| """ | ||
| SELECT | ||
| LOWER(view_name) AS "view_name", | ||
| LOWER(owner) AS "schema", | ||
| DBMS_METADATA.GET_DDL('VIEW', view_name, owner) AS view_def | ||
| FROM DBA_VIEWS | ||
| WHERE owner = :owner | ||
| UNION ALL | ||
| SELECT | ||
| LOWER(mview_name) AS "view_name", | ||
| LOWER(owner) AS "schema", | ||
| DBMS_METADATA.GET_DDL('MATERIALIZED_VIEW', mview_name, owner) AS view_def | ||
| FROM DBA_MVIEWS | ||
| WHERE owner = :owner |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Details
There's a case sensitivity mismatch between the query and the code:
-
In
utils.py, the schema is converted to lowercase:schema = schema.lower() if schema else None
-
In
queries.py, theORACLE_VIEW_DEFINITIONS_BY_SCHEMAquery compares againstownerdirectly:WHERE owner = :owner
-
In Oracle's
DBA_VIEWSandDBA_MVIEWS, theOWNERcolumn typically stores values in UPPERCASE.
This means the query WHERE owner = :owner with a lowercase schema value will likely return no results, since Oracle stores owner names in uppercase by default.
Suggested fix: Either:
- Pass the schema in uppercase to the query:
result = connection.execute(sql.text(query), {"owner": schema.upper()})
- Or modify the query to use
UPPER():WHERE UPPER(owner) = UPPER(:owner)
The first option is more efficient as it allows Oracle to use indexes on the owner column.
Summary
This PR addresses two issues with the Oracle connector regarding view definitions:
TEXTcolumn (LONG type) withDBMS_METADATA.GET_DDLto correctly retrieve large or complex view definitions.DBA_VIEWSfor the entire database when only a specific schema is needed.Changes
queries.py:ORACLE_ALL_VIEW_DEFINITIONSto useDBMS_METADATA.GET_DDL.ORACLE_VIEW_DEFINITIONS_BY_SCHEMA.utils.py:get_all_view_definitionsto accept a query and schema parameter.get_view_definitionto use the schema-filtered query when a schema is provided.test_oracle_views.py: Added unit tests to verify the fix.