Skip to content

feat: Add oracle view support#27320

Open
imsayari404 wants to merge 3 commits intoprestodb:masterfrom
imsayari404:oracle_view
Open

feat: Add oracle view support#27320
imsayari404 wants to merge 3 commits intoprestodb:masterfrom
imsayari404:oracle_view

Conversation

@imsayari404
Copy link
Copy Markdown
Contributor

@imsayari404 imsayari404 commented Mar 12, 2026

Description

added view support for oracle

Motivation and Context

Impact

Test Plan

presto> SELECT * FROM oracle.TM_LAKEHOUSE_ENGINE.test_view;
      id      | name  |    dept_id    |  salary  
--------------+-------+---------------+----------
 1.0000000000 | Alice | 10.0000000000 | 75000.00 
 2.0000000000 | Bob   | 20.0000000000 | 60000.00 
 3.0000000000 | Carol | 10.0000000000 | 80000.00 
 4.0000000000 | David | 10.0000000000 | 90000.00 
 5.0000000000 | Eve   | 20.0000000000 | 55000.00 
(5 rows)

Query 20260312_073826_00000_yr979, FINISHED, 1 node
Splits: 17 total, 17 done (100.00%)
[Latency: client-side: 0:32, server-side: 0:32] [5 rows, 0B] [0 rows/s, 0B/s]

presto> SELECT * FROM oracle.TM_LAKEHOUSE_ENGINE.employees_view;
      id      | name  |  salary  
--------------+-------+----------
 1.0000000000 | Alice | 75000.00 
 2.0000000000 | Bob   | 60000.00 
 3.0000000000 | Carol | 80000.00 
 4.0000000000 | David | 90000.00 
 5.0000000000 | Eve   | 55000.00 
(5 rows)

Query 20260312_074044_00001_yr979, FINISHED, 1 node
Splits: 17 total, 17 done (100.00%)
[Latency: client-side: 0:32, server-side: 0:32] [5 rows, 0B] [0 rows/s, 0B/s]

presto> SELECT * FROM oracle.TM_LAKEHOUSE_ENGINE.employee_dept_view;
      id      | name  |  salary  |  dept_name  | location 
--------------+-------+----------+-------------+----------
 1.0000000000 | Alice | 75000.00 | Engineering | New York 
 2.0000000000 | Bob   | 60000.00 | Marketing   | Chicago  
 3.0000000000 | Carol | 80000.00 | Engineering | New York 
 4.0000000000 | David | 90000.00 | Engineering | New York 
 5.0000000000 | Eve   | 55000.00 | Marketing   | Chicago  
(5 rows)

Query 20260312_074126_00002_yr979, FINISHED, 1 node
Splits: 50 total, 50 done (100.00%)
[Latency: client-side: 1:32, server-side: 1:32] [7 rows, 0B] [0 rows/s, 0B/s]

presto> CREATE VIEW oracle.TM_LAKEHOUSE_ENGINE.test_view1 AS SELECT * FROM oracle.TM_LAKEHOUSE_ENGINE.employees;
CREATE VIEW

Query 20260312_074313_00003_yr979, FINISHED, 0 nodes
Splits: 0 total, 0 done (0.00%)
[Latency: client-side: 0:20, server-side: 0:20] [0 rows, 0B] [0 rows/s, 0B/s]

presto> SHOW CREATE VIEW oracle.TM_LAKEHOUSE_ENGINE.test_view1;
                              Create View                              
-----------------------------------------------------------------------
 CREATE VIEW oracle.TM_LAKEHOUSE_ENGINE.test_view1 SECURITY DEFINER AS 
 SELECT                                                                
   "ID"                                                                
 , "NAME"                                                              
 , "DEPT_ID"                                                           
 , "SALARY"                                                            
 FROM                                                                  
   TM_LAKEHOUSE_ENGINE.employees                                       
(1 row)

Query 20260312_074400_00004_yr979, FINISHED, 1 node
Splits: 1 total, 1 done (100.00%)
[Latency: client-side: 0:06, server-side: 0:06] [0 rows, 0B] [0 rows/s, 0B/s]

presto> drop table oracle.TM_LAKEHOUSE_ENGINE.test_view1;

Query 20260312_074417_00005_yr979, FAILED, 0 nodes
Splits: 0 total, 0 done (0.00%)
[Latency: client-side: 0:08, server-side: 0:08] [0 rows, 0B] [0 rows/s, 0B/s]

Query 20260312_074417_00005_yr979 failed: ORA-00942: table or view does not exist


presto> DROP VIEW oracle.TM_LAKEHOUSE_ENGINE.test_view1;
DROP VIEW

Query 20260312_074502_00006_yr979, FINISHED, 0 nodes
Splits: 0 total, 0 done (0.00%)
[Latency: client-side: 0:09, server-side: 0:09] [0 rows, 0B] [0 rows/s, 0B/s]

presto> exit

Contributor checklist

  • Please make sure your submission complies with our contributing guide, in particular code style and commit standards.
  • PR description addresses the issue accurately and concisely. If the change is non-trivial, a GitHub Issue is referenced.
  • Documented new properties (with its default value), SQL syntax, functions, or other functionality.
  • If release notes are required, they follow the release notes guidelines.
  • Adequate tests were added if applicable.
  • CI passed.
  • If adding new dependencies, verified they have an OpenSSF Scorecard score of 5.0 or higher (or obtained explicit TSC approval for lower scores).

Release Notes

Please follow release notes guidelines and fill in the release notes below.

== RELEASE NOTES ==

Oracle Connector Changes
* Add view querying capabilities in the Oracle connector.

Summary by Sourcery

Add Oracle-specific metadata and client support to enable full view lifecycle operations in the Oracle connector.

New Features:

  • Allow querying existing Oracle views as Presto views via Oracle-specific metadata and view definition retrieval.
  • Support listing Oracle views and discovering schemas containing views through the Oracle connector.
  • Enable creating and dropping views in Oracle from Presto, mapping Presto view definitions to Oracle views.

Enhancements:

  • Extend the JDBC metadata factory to construct an Oracle-specific metadata implementation while preserving the default path for other connectors.

@prestodb-ci prestodb-ci added the from:IBM PR from IBM label Mar 12, 2026
@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai bot commented Mar 12, 2026

Reviewer's Guide

Implements Oracle connector view support by adding Oracle-specific view metadata operations, delegating view CRUD to OracleClient, and wiring OracleMetadata into the generic JDBC metadata factory while slightly generalizing metadata factory fields.

Sequence diagram for Oracle view creation and querying via OracleMetadata and OracleClient

sequenceDiagram
    actor User
    participant PrestoCoordinator
    participant JdbcMetadataFactory
    participant OracleMetadata
    participant OracleClient
    participant OracleDB

    User->>PrestoCoordinator: CREATE VIEW oracle.schema.view AS SELECT ...
    PrestoCoordinator->>JdbcMetadataFactory: create()
    JdbcMetadataFactory->>JdbcMetadataFactory: detect OracleClient and instantiate OracleMetadata
    JdbcMetadataFactory-->>PrestoCoordinator: OracleMetadata
    PrestoCoordinator->>OracleMetadata: createView(session, viewMetadata, viewData, replace)
    OracleMetadata->>OracleClient: createView(session, identity, viewName, viewData, replace)
    OracleClient->>OracleClient: extractOriginalSql(viewData)
    OracleClient->>OracleClient: removeCatalogPrefix(sql)
    OracleClient->>OracleDB: CREATE VIEW schema.view AS originalSql
    OracleDB-->>OracleClient: success
    OracleClient-->>OracleMetadata: return
    OracleMetadata-->>PrestoCoordinator: return

    User->>PrestoCoordinator: SELECT * FROM oracle.schema.view
    PrestoCoordinator->>OracleMetadata: getViews(session, prefix)
    OracleMetadata->>OracleClient: listViews(session, identity, Optional(schema))
    OracleClient->>OracleDB: JDBC metadata getTables
    OracleDB-->>OracleClient: view rows
    OracleClient-->>OracleMetadata: List SchemaTableName
    OracleMetadata->>OracleClient: getViews(session, identity, viewNames)
    OracleClient->>OracleDB: SELECT OWNER, VIEW_NAME, TEXT FROM ALL_VIEWS ...
    OracleDB-->>OracleClient: view definition
    OracleClient->>OracleDB: JDBC metadata getColumns
    OracleDB-->>OracleClient: column metadata
    OracleClient-->>OracleMetadata: Map SchemaTableName ConnectorViewDefinition
    OracleMetadata-->>PrestoCoordinator: view definitions
    PrestoCoordinator-->>User: query results
Loading

Class diagram for Oracle view support in OracleClient, OracleMetadata, and JdbcMetadataFactory

classDiagram
    class JdbcClient
    class JdbcMetadataCache
    class TableLocationProvider
    class ConnectorSession
    class SchemaTableName
    class SchemaTablePrefix
    class ConnectorViewDefinition
    class ConnectorTableMetadata
    class JdbcIdentity
    class TypeManager

    class OracleClient {
        - boolean synonymsEnabled
        - int numberDefaultScale
        - TypeManager typeManager
        + OracleClient(JdbcConnectorId connectorId, BaseJdbcConfig config, OracleConfig oracleConfig, ConnectionFactory connectionFactory, TypeManager typeManager)
        - String[] getTableTypes()
        + String normalizeIdentifier(ConnectorSession session, String identifier)
        + Map~SchemaTableName,ConnectorViewDefinition~ getViews(ConnectorSession session, JdbcIdentity identity, List~SchemaTableName~ tableNames)
        + List~SchemaTableName~ listViews(ConnectorSession session, JdbcIdentity identity, Optional~String~ schema)
        + List~SchemaTableName~ listSchemasForViews(ConnectorSession session, JdbcIdentity identity)
        + void createView(ConnectorSession session, JdbcIdentity identity, SchemaTableName viewName, String viewData, boolean replace)
        - String removeCatalogPrefix(String sql)
        - String extractOriginalSql(String viewData)
        + void dropView(ConnectorSession session, JdbcIdentity identity, SchemaTableName viewName)
    }

    class JdbcMetadata {
        + JdbcMetadata(JdbcMetadataCache jdbcMetadataCache, JdbcClient jdbcClient, boolean allowDropTable, TableLocationProvider tableLocationProvider)
        + Map~SchemaTableName,ConnectorViewDefinition~ getViews(ConnectorSession session, SchemaTablePrefix prefix)
        + List~SchemaTableName~ listViews(ConnectorSession session, Optional~String~ schemaName)
        + void createView(ConnectorSession session, ConnectorTableMetadata viewMetadata, String viewData, boolean replace)
        + void dropView(ConnectorSession session, SchemaTableName viewName)
    }

    class OracleMetadata {
        - OracleClient oracleClient
        + OracleMetadata(JdbcMetadataCache jdbcMetadataCache, OracleClient oracleClient, boolean allowDropTable, TableLocationProvider tableLocationProvider)
        + Map~SchemaTableName,ConnectorViewDefinition~ getViews(ConnectorSession session, SchemaTablePrefix prefix)
        + List~SchemaTableName~ listViews(ConnectorSession session, Optional~String~ schemaName)
        + void createView(ConnectorSession session, ConnectorTableMetadata viewMetadata, String viewData, boolean replace)
        + void dropView(ConnectorSession session, SchemaTableName viewName)
    }

    class JdbcMetadataFactory {
        protected JdbcMetadataCache jdbcMetadataCache
        protected JdbcClient jdbcClient
        protected boolean allowDropTable
        protected TableLocationProvider tableLocationProvider
        + JdbcMetadataFactory(JdbcMetadataCache jdbcMetadataCache, JdbcClient jdbcClient, JdbcMetadataConfig config, TableLocationProvider tableLocationProvider)
        + JdbcMetadata create()
        protected JdbcMetadata createMetadata()
    }

    JdbcClient <|-- OracleClient
    JdbcMetadata <|-- OracleMetadata

    JdbcMetadataFactory --> JdbcClient : uses
    JdbcMetadataFactory --> JdbcMetadata : creates
    JdbcMetadataFactory --> OracleMetadata : creates via reflection

    OracleMetadata --> OracleClient : delegates view operations
    JdbcMetadata --> JdbcClient : delegates
Loading

File-Level Changes

Change Details Files
Extend OracleClient to handle Oracle views and view DDL directly against ALL_VIEWS and JDBC metadata.
  • Inject and store TypeManager in OracleClient constructor for type resolution when mapping view columns.
  • Treat Oracle views as regular tables via getTableTypes so they’re discoverable without Presto-side view validation.
  • Implement getViews to query ALL_VIEWS, derive column metadata via DatabaseMetaData.getColumns, map JDBC types to Presto types, and build ConnectorViewDefinition JSON payloads.
  • Implement listViews and listSchemasForViews to enumerate Oracle views from JDBC metadata, normalizing identifiers per Oracle rules.
  • Add createView, dropView, removeCatalogPrefix, and extractOriginalSql helpers so view DDL is executed on Oracle and SQL is extracted from stored view JSON.
presto-oracle/src/main/java/com/facebook/presto/plugin/oracle/OracleClient.java
Introduce Oracle-specific JdbcMetadata implementation that delegates view operations to OracleClient.
  • Create OracleMetadata extending JdbcMetadata to override getViews, listViews, createView, and dropView with Oracle-specific logic.
  • Use JdbcIdentity derived from ConnectorSession to drive all OracleClient calls.
  • Implement schema/table prefix handling so getViews can fetch a specific view, all views in a schema, or all views across schemas.
presto-oracle/src/main/java/com/facebook/presto/plugin/oracle/OracleMetadata.java
Wire OracleMetadata into the JDBC metadata factory while keeping the default behavior for other connectors.
  • Relax visibility of JdbcMetadataFactory fields to protected to allow subclassing/extension.
  • Update create() to detect OracleClient by class name and, via reflection, construct OracleMetadata with the existing JdbcMetadataCache, JdbcClient, allowDropTable flag, and TableLocationProvider.
  • Factor original JdbcMetadata creation logic into protected createMetadata() used as a fallback when Oracle-specific wiring is not applicable or reflection fails.
presto-base-jdbc/src/main/java/com/facebook/presto/plugin/jdbc/JdbcMetadataFactory.java

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@imsayari404 imsayari404 changed the title oracle view support feat: Add oracle view support Mar 12, 2026
@imsayari404 imsayari404 marked this pull request as ready for review March 13, 2026 06:50
@imsayari404 imsayari404 requested a review from a team as a code owner March 13, 2026 06:50
@prestodb-ci prestodb-ci requested review from a team, ShahimSharafudeen and namya28 and removed request for a team March 13, 2026 06:50
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 4 issues, and left some high level feedback:

  • The Oracle-specific wiring in JdbcMetadataFactory relies on a reflective clientClassName.contains("OracleClient") check, which is brittle; consider introducing an explicit SPI hook or overridable factory method in the Oracle connector instead of using reflection and string matching on class names.
  • OracleClient.getViews/createView manually build and parse the view JSON payload (including extractOriginalSql), duplicating Presto’s view-serialization format and making it fragile to changes; it would be safer to reuse the existing view JSON codec / ConnectorViewDefinition APIs rather than hand-rolled string manipulation.
  • The removeCatalogPrefix implementation uses a simple regex on \b\w+\.(\w+\.\w+)\b, which won’t handle quoted identifiers or more complex SQL correctly and may accidentally rewrite unrelated patterns; consider a more robust approach (e.g., parsing the statement or limiting rewrite to known catalog names) or leaving the SQL unchanged if that’s acceptable for Oracle.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The Oracle-specific wiring in JdbcMetadataFactory relies on a reflective `clientClassName.contains("OracleClient")` check, which is brittle; consider introducing an explicit SPI hook or overridable factory method in the Oracle connector instead of using reflection and string matching on class names.
- OracleClient.getViews/createView manually build and parse the view JSON payload (including `extractOriginalSql`), duplicating Presto’s view-serialization format and making it fragile to changes; it would be safer to reuse the existing view JSON codec / ConnectorViewDefinition APIs rather than hand-rolled string manipulation.
- The `removeCatalogPrefix` implementation uses a simple regex on `\b\w+\.(\w+\.\w+)\b`, which won’t handle quoted identifiers or more complex SQL correctly and may accidentally rewrite unrelated patterns; consider a more robust approach (e.g., parsing the statement or limiting rewrite to known catalog names) or leaving the SQL unchanged if that’s acceptable for Oracle.

## Individual Comments

### Comment 1
<location path="presto-oracle/src/main/java/com/facebook/presto/plugin/oracle/OracleClient.java" line_range="329-337" />
<code_context>
+            Map<SchemaTableName, ConnectorViewDefinition> views = new HashMap<>();
+
+            // Build the query to fetch view definitions from ALL_VIEWS
+            StringBuilder sql = new StringBuilder(
+                    "SELECT OWNER, VIEW_NAME, TEXT FROM ALL_VIEWS WHERE (OWNER, VIEW_NAME) IN (");
+
+            List<String> placeholders = new ArrayList<>();
+            for (int i = 0; i < tableNames.size(); i++) {
+                placeholders.add("(?, ?)");
+            }
+            sql.append(String.join(", ", placeholders));
+            sql.append(")");
+
+            try (PreparedStatement statement = connection.prepareStatement(sql.toString())) {
</code_context>
<issue_to_address>
**suggestion (performance):** Large IN-clause construction may hit Oracle limits and scale poorly.

For workloads with many views this query may fail or degrade significantly. Please either: (a) split the requested views into batches (e.g., 500–1000 pairs per query) and merge the results, or (b) switch to a temp table / join-based approach to avoid very large `IN` lists entirely.
</issue_to_address>

### Comment 2
<location path="presto-oracle/src/main/java/com/facebook/presto/plugin/oracle/OracleClient.java" line_range="407-416" />
<code_context>
+
+                        String columnsJson = String.join(",", columnJsonList);
+
+                        String prestoViewData = String.format(
+                                "{\"originalSql\":\"%s\",\"catalog\":\"%s\",\"schema\":\"%s\",\"columns\":[%s],\"owner\":\"%s\",\"runAsInvoker\":false}",
+                                escapedSql,
+                                connectorId,  // Use connector ID as catalog
+                                schemaName,
+                                columnsJson,
+                                owner);
+
+                        views.put(viewName, new ConnectorViewDefinition(
+                                viewName,
+                                Optional.of(owner),
+                                prestoViewData));
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Manual JSON construction/parsing for view data is brittle; consider using a JSON library or existing helpers.

This JSON is built via string formatting and ad-hoc escaping, then later parsed via string scanning (`extractOriginalSql`). That approach is brittle for cases like unusual escaping, unicode, or changes to the JSON shape. Prefer constructing and parsing the view JSON with a JSON library or existing Presto `ViewDefinition` helpers instead of manual `replace`/index-based logic.

Suggested implementation:

```java
                        // Build a structured ConnectorViewDefinition instead of manual JSON
                        ConnectorViewDefinition viewDefinition = new ConnectorViewDefinition(
                                oracleViewSql,
                                Optional.of(connectorId),  // Use connector ID as catalog
                                Optional.of(schemaName),
                                viewColumns,
                                Optional.of(owner),
                                Optional.of(false));

                        views.put(viewName, viewDefinition);

```

1. Ensure you have a `List<ConnectorViewDefinition.ViewColumn> viewColumns` (or similarly named) built alongside `columnJsonList`. For each column, populate `new ConnectorViewDefinition.ViewColumn(columnName, Optional.of(prestoType.toString()), Optional.empty())` (or the appropriate constructor used elsewhere in the codebase).
2. Remove any now-unused `columnJsonList` construction logic in this method, since the JSON string is no longer needed.
3. Add or verify imports for `com.facebook.presto.spi.ConnectorViewDefinition` and `com.facebook.presto.spi.ConnectorViewDefinition.ViewColumn` as needed.
4. If the actual `ConnectorViewDefinition` constructor signature in your Presto version differs (e.g., different `Optional` parameters or `runAsInvoker` handling), adjust the arguments accordingly to match the existing usage patterns in other connectors (e.g., MySQL, PostgreSQL) in your codebase.
</issue_to_address>

### Comment 3
<location path="presto-oracle/src/main/java/com/facebook/presto/plugin/oracle/OracleClient.java" line_range="514-518" />
<code_context>
+    /**
+     * Remove catalog prefix from table references in SQL.
+     */
+    private String removeCatalogPrefix(String sql)
+    {
+        // Pattern to match: word.word.word (catalog.schema.table)
+        // Replace with: word.word (schema.table)
+        return sql.replaceAll("\\b\\w+\\.(\\w+\\.\\w+)\\b", "$1");
+    }
+
</code_context>
<issue_to_address>
**issue:** Regex-based catalog stripping can accidentally modify literals or quoted identifiers.

This pattern will also match three-part identifiers inside string literals or quoted identifiers (e.g., `'a.b.c'`, "A.B.C"), potentially corrupting valid SQL. If catalog stripping is required, consider using an SQL parser to operate on the AST, or at least implement a simple tokenizer so quoted content is skipped before applying the replacement.
</issue_to_address>

### Comment 4
<location path="presto-base-jdbc/src/main/java/com/facebook/presto/plugin/jdbc/JdbcMetadataFactory.java" line_range="40-49" />
<code_context>
+        String clientClassName = jdbcClient.getClass().getName();
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Oracle-specific metadata selection via class-name substring and silent reflection failure is brittle.

The current approach relies on `clientClassName.contains(

Suggested implementation:

```java
        // Check if this is an Oracle client and create appropriate metadata
        String jdbcClientClassName = jdbcClient.getClass().getName();
        if ("com.facebook.presto.plugin.oracle.OracleClient".equals(jdbcClientClassName)) {

```

To fully address the brittleness around reflection, you may also want to:
1. Wrap the reflective `Class.forName(...)` and constructor calls in a `catch (ReflectiveOperationException e)` and rethrow as an `IllegalStateException` with a clear message indicating Oracle support is misconfigured, instead of silently falling back to generic `JdbcMetadata`.
2. Optionally log the failure via the existing logging mechanism in this module so operators can diagnose missing Oracle classes at runtime.
These changes would need to be applied around the rest of the `try` block that is not shown in the snippet.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +329 to +337
StringBuilder sql = new StringBuilder(
"SELECT OWNER, VIEW_NAME, TEXT FROM ALL_VIEWS WHERE (OWNER, VIEW_NAME) IN (");

List<String> placeholders = new ArrayList<>();
for (int i = 0; i < tableNames.size(); i++) {
placeholders.add("(?, ?)");
}
sql.append(String.join(", ", placeholders));
sql.append(")");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (performance): Large IN-clause construction may hit Oracle limits and scale poorly.

For workloads with many views this query may fail or degrade significantly. Please either: (a) split the requested views into batches (e.g., 500–1000 pairs per query) and merge the results, or (b) switch to a temp table / join-based approach to avoid very large IN lists entirely.

Comment on lines +407 to +416
String prestoViewData = String.format(
"{\"originalSql\":\"%s\",\"catalog\":\"%s\",\"schema\":\"%s\",\"columns\":[%s],\"owner\":\"%s\",\"runAsInvoker\":false}",
escapedSql,
connectorId, // Use connector ID as catalog
schemaName,
columnsJson,
owner);

views.put(viewName, new ConnectorViewDefinition(
viewName,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (bug_risk): Manual JSON construction/parsing for view data is brittle; consider using a JSON library or existing helpers.

This JSON is built via string formatting and ad-hoc escaping, then later parsed via string scanning (extractOriginalSql). That approach is brittle for cases like unusual escaping, unicode, or changes to the JSON shape. Prefer constructing and parsing the view JSON with a JSON library or existing Presto ViewDefinition helpers instead of manual replace/index-based logic.

Suggested implementation:

                        // Build a structured ConnectorViewDefinition instead of manual JSON
                        ConnectorViewDefinition viewDefinition = new ConnectorViewDefinition(
                                oracleViewSql,
                                Optional.of(connectorId),  // Use connector ID as catalog
                                Optional.of(schemaName),
                                viewColumns,
                                Optional.of(owner),
                                Optional.of(false));

                        views.put(viewName, viewDefinition);
  1. Ensure you have a List<ConnectorViewDefinition.ViewColumn> viewColumns (or similarly named) built alongside columnJsonList. For each column, populate new ConnectorViewDefinition.ViewColumn(columnName, Optional.of(prestoType.toString()), Optional.empty()) (or the appropriate constructor used elsewhere in the codebase).
  2. Remove any now-unused columnJsonList construction logic in this method, since the JSON string is no longer needed.
  3. Add or verify imports for com.facebook.presto.spi.ConnectorViewDefinition and com.facebook.presto.spi.ConnectorViewDefinition.ViewColumn as needed.
  4. If the actual ConnectorViewDefinition constructor signature in your Presto version differs (e.g., different Optional parameters or runAsInvoker handling), adjust the arguments accordingly to match the existing usage patterns in other connectors (e.g., MySQL, PostgreSQL) in your codebase.

Comment on lines +514 to +518
private String removeCatalogPrefix(String sql)
{
// Pattern to match: word.word.word (catalog.schema.table)
// Replace with: word.word (schema.table)
return sql.replaceAll("\\b\\w+\\.(\\w+\\.\\w+)\\b", "$1");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: Regex-based catalog stripping can accidentally modify literals or quoted identifiers.

This pattern will also match three-part identifiers inside string literals or quoted identifiers (e.g., 'a.b.c', "A.B.C"), potentially corrupting valid SQL. If catalog stripping is required, consider using an SQL parser to operate on the AST, or at least implement a simple tokenizer so quoted content is skipped before applying the replacement.

Comment on lines +40 to +49
String clientClassName = jdbcClient.getClass().getName();
if (clientClassName.contains("OracleClient")) {
try {
// Use reflection to create OracleMetadata
Class<?> oracleClientClass = Class.forName("com.facebook.presto.plugin.oracle.OracleClient");
Class<?> oracleMetadataClass = Class.forName("com.facebook.presto.plugin.oracle.OracleMetadata");
if (oracleClientClass.isInstance(jdbcClient)) {
return (JdbcMetadata) oracleMetadataClass
.getConstructor(
JdbcMetadataCache.class,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (bug_risk): Oracle-specific metadata selection via class-name substring and silent reflection failure is brittle.

The current approach relies on `clientClassName.contains(

Suggested implementation:

        // Check if this is an Oracle client and create appropriate metadata
        String jdbcClientClassName = jdbcClient.getClass().getName();
        if ("com.facebook.presto.plugin.oracle.OracleClient".equals(jdbcClientClassName)) {

To fully address the brittleness around reflection, you may also want to:

  1. Wrap the reflective Class.forName(...) and constructor calls in a catch (ReflectiveOperationException e) and rethrow as an IllegalStateException with a clear message indicating Oracle support is misconfigured, instead of silently falling back to generic JdbcMetadata.
  2. Optionally log the failure via the existing logging mechanism in this module so operators can diagnose missing Oracle classes at runtime.
    These changes would need to be applied around the rest of the try block that is not shown in the snippet.

Copy link
Copy Markdown
Contributor

@auden-woolfson auden-woolfson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please add tests?

@BryanCutler BryanCutler self-requested a review March 19, 2026 00:53
steveburnett
steveburnett previously approved these changes Mar 27, 2026
Copy link
Copy Markdown
Contributor

@steveburnett steveburnett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! (docs)

Pull branch, local doc build, looks good. Thank you for the documentation!

@imsayari404
Copy link
Copy Markdown
Contributor Author

LGTM! (docs)

Pull branch, local doc build, looks good. Thank you for the documentation!

Thank you, @steveburnett, for reviewing.

protected final JdbcMetadataCache jdbcMetadataCache;
protected final JdbcClient jdbcClient;
protected final boolean allowDropTable;
protected final TableLocationProvider tableLocationProvider;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these changes still necessary?

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.

I've made the changes


List<String> placeholders = new ArrayList<>();
for (int i = 0; i < tableNames.size(); i++) {
placeholders.add("(?, ?)");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we just add the table names directly instead of using placeholders?

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.

I have made the change

return createMetadata();
}

protected JdbcMetadata createMetadata()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please refer to this comment:

#27266 (comment)

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.

Sure

@imsayari404 imsayari404 force-pushed the oracle_view branch 2 times, most recently from ce9c5ca to 60f400b Compare April 8, 2026 06:21
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 8, 2026

Codenotify: Notifying subscribers in CODENOTIFY files for diff 40c1c4e...fcea93a.

No notifications.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

from:IBM PR from IBM

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants