Skip to content

fix(plugins): parameterize query execution for Redshift, Snowflake and Databricks#41967

Draft
wyattwalter wants to merge 3 commits into
releasefrom
fm/sqli-noprep-p2
Draft

fix(plugins): parameterize query execution for Redshift, Snowflake and Databricks#41967
wyattwalter wants to merge 3 commits into
releasefrom
fm/sqli-noprep-p2

Conversation

@wyattwalter

@wyattwalter wyattwalter commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Linear: APP-15378

Summary

The Redshift, Snowflake and Databricks plugins previously executed queries by substituting dynamic bindings directly into the SQL text. This PR adds prepared-statement support to all three so query execution is parameterized, bringing them in line with the other SQL plugins (Postgres, MySQL, MSSQL).

Changes

  • Parameterized execution — dynamic values ({{...}}) are bound as PreparedStatement parameters instead of being substituted into the SQL string.
  • "Use prepared statement" toggle — added to the plugin editor/settings for each plugin, enabled by default, with an opt-out that matches the Postgres/MySQL/MSSQL behavior. When the setting is absent or unrecognized, execution defaults to prepared; only an explicit opt-out selects the non-prepared path (which still supports binding identifiers/fragments a prepared statement cannot parameterize).
  • dependency.json — added for each plugin so the editor links the query body to the prepared-statement toggle (matching the existing SQL plugins).
  • Array-typed parameters are rejected with a clear error rather than being bound incorrectly, and prepared statements are closed on binding failure.

Tests

Adds unit tests for all three plugins covering:

  • the prepared path (prepareStatement used, values bound, createStatement never called),
  • default-on behavior when the setting is absent or malformed,
  • the explicit opt-out selecting the non-prepared path, and
  • resource cleanup (statements closed on binding failure).

Focused module suites are green: redshiftPlugin 19, snowflakePlugin 16, databricksPlugin 8 — 0 failures. spotless:check passes for all three modules.

Summary by CodeRabbit

  • New Features

    • Added “Use prepared statements” execution mode for Databricks, Redshift, and Snowflake with dynamic binding support.
    • Updated editors to show separate prepared vs non-prepared query inputs, controlled by the prepared-statement toggle.
    • Added run behavior, run-confirmation, and query-timeout settings for these plugins.
  • Bug Fixes

    • Improved prepared execution by binding dynamic values as JDBC parameters (with plugin-specific SQL handling) and reliably closing JDBC resources.
    • Added clearer errors for query-preparation failures and unsupported array parameters.
    • Improved write-style/no-result handling and safer catalog/schema usage.
  • Tests

    • Added regression tests covering prepared vs non-prepared routing, defaults, array rejection, error surfacing, and dependency wiring.

Warning

Tests have not run on the HEAD 2da5573 yet


Wed, 08 Jul 2026 21:35:06 UTC

…d Databricks

Adds prepared-statement support to the Redshift, Snowflake and Databricks
plugins so query execution is parameterized, bringing them in line with the
other SQL plugins (Postgres, MySQL, MSSQL).

- Bind dynamic values as prepared-statement parameters instead of
  interpolating them into the raw SQL string.
- Add a "Use prepared statement" toggle in the plugin editor/settings, with
  prepared statements enabled by default and an opt-out matching the
  Postgres/MySQL/MSSQL behavior. When the setting is absent or not a
  recognized value, execution defaults to prepared; only an explicit
  opt-out selects raw execution.
- Reject array-typed parameters with a clear error rather than binding them
  incorrectly, and ensure prepared statements are closed on binding failure.
- Add the plugins' dependency.json so the editor links the query body to the
  prepared-statement toggle.

Adds unit tests covering the prepared path, the default-on behavior for
absent/malformed settings, the explicit opt-out, and resource cleanup for all
three plugins.
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Databricks, Redshift, and Snowflake plugins add prepared-statement execution paths, typed parameter binding, UI toggles, dependency wiring, execution metadata, and regression tests.

Changes

Databricks Prepared Statement Support

Layer / File(s) Summary
Prepared statement execution and binding logic
app/server/appsmith-plugins/databricksPlugin/src/main/java/com/external/plugins/DatabricksPlugin.java, app/server/appsmith-plugins/databricksPlugin/src/main/java/com/external/plugins/exceptions/DatabricksErrorMessages.java
Adds executeParameterized, dual Statement/PreparedStatement execution, request packaging, typed binding helpers, identifier quoting, and two new error messages.
Editor and settings configuration
app/server/appsmith-plugins/databricksPlugin/src/main/resources/dependency.json, app/server/appsmith-plugins/databricksPlugin/src/main/resources/editor/root.json, app/server/appsmith-plugins/databricksPlugin/src/main/resources/setting.json
Adds dependency wiring, prepared and non-prepared query controls, and prepared-statement toggle settings.
Unit tests for prepared statement behavior
app/server/appsmith-plugins/databricksPlugin/src/test/java/com/external/plugins/DatabricksPluginTest.java
Adds tests for prepared and raw path selection, defaults, array rejection, and dependency.json wiring.

Redshift Prepared Statement Support

Layer / File(s) Summary
Prepared statement execution and binding logic
app/server/appsmith-plugins/redshiftPlugin/src/main/java/com/external/plugins/RedshiftPlugin.java, app/server/appsmith-plugins/redshiftPlugin/src/main/java/com/external/plugins/exceptions/RedshiftErrorMessages.java
Adds SmartSubstitutionInterface, executeParameterized, dual-path execution, request properties, prepared-statement cleanup, typed binding, and new error messages.
Editor and settings configuration
app/server/appsmith-plugins/redshiftPlugin/src/main/resources/dependency.json, app/server/appsmith-plugins/redshiftPlugin/src/main/resources/editor.json, app/server/appsmith-plugins/redshiftPlugin/src/main/resources/setting.json
Adds dependency wiring, prepared and non-prepared query controls, and prepared-statement toggle settings.
Unit tests for prepared statement behavior
app/server/appsmith-plugins/redshiftPlugin/src/test/java/com/external/plugins/RedshiftPluginTest.java
Adds helpers and tests covering binding, defaults, raw and prepared selection, array and null handling, bind-failure cleanup, and dependency wiring.

Snowflake Prepared Statement Support

Layer / File(s) Summary
Prepared statement execution and binding logic
app/server/appsmith-plugins/snowflakePlugin/src/main/java/com/external/plugins/SnowflakePlugin.java, app/server/appsmith-plugins/snowflakePlugin/src/main/java/com/external/plugins/exceptions/SnowflakeErrorMessages.java, app/server/appsmith-plugins/snowflakePlugin/src/main/java/com/external/utils/ExecutionUtils.java
Adds executeParameterized, prepared-statement request metadata, typed binding, schema escaping, prepared-row extraction helpers, and two new error messages.
Editor and settings configuration
app/server/appsmith-plugins/snowflakePlugin/src/main/resources/dependency.json, app/server/appsmith-plugins/snowflakePlugin/src/main/resources/editor.json, app/server/appsmith-plugins/snowflakePlugin/src/main/resources/setting.json
Adds dependency wiring, prepared and non-prepared query controls, and prepared-statement toggle settings.
Unit tests for prepared statement behavior
app/server/appsmith-plugins/snowflakePlugin/src/test/java/com/external/plugins/SnowflakePluginTest.java
Adds helpers and tests covering path selection, defaults, bind-failure cleanup, array rejection, and dependency wiring.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant DatabricksPluginExecutor
  participant PreparedStatement
  Client->>DatabricksPluginExecutor: executeParameterized(...)
  DatabricksPluginExecutor->>DatabricksPluginExecutor: read prepared-statement toggle
  DatabricksPluginExecutor->>DatabricksPluginExecutor: rewrite mustache bindings to ?
  DatabricksPluginExecutor->>PreparedStatement: prepareStatement(rewrittenSQL)
  DatabricksPluginExecutor->>PreparedStatement: bind values and execute
  PreparedStatement-->>DatabricksPluginExecutor: rows or update count
  DatabricksPluginExecutor-->>Client: ActionExecutionResult
Loading
sequenceDiagram
  participant Client
  participant RedshiftPluginExecutor
  participant PreparedStatement
  Client->>RedshiftPluginExecutor: executeParameterized(...)
  RedshiftPluginExecutor->>RedshiftPluginExecutor: read prepared-statement toggle
  RedshiftPluginExecutor->>RedshiftPluginExecutor: rewrite mustache bindings to ?
  RedshiftPluginExecutor->>PreparedStatement: prepareStatement(transformedSQL)
  RedshiftPluginExecutor->>PreparedStatement: bind values and execute
  PreparedStatement-->>RedshiftPluginExecutor: rows or update count
  RedshiftPluginExecutor-->>Client: ActionExecutionResult
Loading
sequenceDiagram
  participant Client
  participant SnowflakePluginExecutor
  participant ExecutionUtils
  participant PreparedStatement
  Client->>SnowflakePluginExecutor: executeParameterized(...)
  SnowflakePluginExecutor->>SnowflakePluginExecutor: read prepared-statement toggle
  SnowflakePluginExecutor->>SnowflakePluginExecutor: rewrite mustache bindings to ?
  SnowflakePluginExecutor->>PreparedStatement: prepareStatement(preparedSQL)
  SnowflakePluginExecutor->>PreparedStatement: bind values and execute
  SnowflakePluginExecutor->>ExecutionUtils: getRowsFromPreparedStatement(...)
  ExecutionUtils-->>SnowflakePluginExecutor: rows list
  SnowflakePluginExecutor-->>Client: ActionExecutionResult
Loading

Poem

Three plugins learned a careful dance,
With placeholders set and SQL in trance.
Curly braces left, question marks grew,
Each statement closed when work was through.
Tests stood guard with steady light,
And bindings marched in ordered flight.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description covers summary, changes, and tests, but it misses required template sections like Fixes issue, Automation, and Communication. Add the Fixes issue line, /ok-to-test tags section, Cypress test results block, and Communication checkbox to match the repository template.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title is concise and accurately summarizes the main change: parameterized query execution across the three plugins.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fm/sqli-noprep-p2

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 2

🧹 Nitpick comments (2)
app/server/appsmith-plugins/snowflakePlugin/src/main/java/com/external/plugins/SnowflakePlugin.java (2)

307-313: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Prefer StandardCharsets.UTF_8 over the string variant.

value.getBytes("UTF-8") throws a checked UnsupportedEncodingException that can never fire. Using StandardCharsets.UTF_8 is the idiomatic Java 17 approach and eliminates the dead IOException catch path.

♻️ Proposed fix
                     case BYTES: {
-                        preparedStatement.setBytes(index, value.getBytes("UTF-8"));
+                        preparedStatement.setBytes(index, value.getBytes(StandardCharsets.UTF_8));
                         break;
                     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@app/server/appsmith-plugins/snowflakePlugin/src/main/java/com/external/plugins/SnowflakePlugin.java`
around lines 307 - 313, In SnowflakePlugin’s prepared-statement value handling,
the BYTES branch is using the string-based UTF-8 lookup, which adds an
unnecessary checked-exception path. Update the BYTES case in the switch that
calls preparedStatement.setBytes to use StandardCharsets.UTF_8 instead of the
string literal, and remove any now-dead IOException/UnsupportedEncodingException
handling around this conversion if it becomes unused.

357-358: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

default case silently skips parameter binding.

An unrecognized DataType will leave the ? placeholder unbound while insertedParams still records the entry, producing a confusing JDBC "parameter not set" error at execution time. Add a log warning or throw to fail fast.

♻️ Proposed fix
                     case ARRAY:
                     case NULL_ARRAY:
                         throw new AppsmithPluginException(
                                 AppsmithPluginError.PLUGIN_EXECUTE_ARGUMENT_ERROR,
                                 String.format(SnowflakeErrorMessages.ARRAY_PARAMETER_NOT_SUPPORTED_ERROR_MSG, binding));
                     default:
-                        break;
+                        log.warn("Unrecognized data type {} for binding {}, skipping parameter binding", valueType, binding);
+                        break;
                 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@app/server/appsmith-plugins/snowflakePlugin/src/main/java/com/external/plugins/SnowflakePlugin.java`
around lines 357 - 358, The default branch in SnowflakePlugin’s parameter
binding switch is silently ignoring unknown DataType values, which leaves
placeholders unbound while insertedParams still tracks them. Update the binding
logic in the relevant parameter-processing method to fail fast on unsupported
types, either by logging a clear warning and stopping or by throwing an explicit
exception, so the issue is caught before JDBC execution.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@app/server/appsmith-plugins/databricksPlugin/src/main/java/com/external/plugins/DatabricksPlugin.java`:
- Around line 411-412: The catch block in DatabricksPlugin should guard against
a null exception message before calling contains on e.getMessage(). Update the
SQLException branch in the exception handler to safely check for a non-null
message before matching "The column index is out of range:", so the logic still
routes through the intended AppsmithPluginException path instead of throwing an
NPE.

In
`@app/server/appsmith-plugins/redshiftPlugin/src/main/java/com/external/plugins/RedshiftPlugin.java`:
- Around line 577-578: The SQLException message check in RedshiftPlugin’s
exception handling is not null-safe because e.getMessage() may be null before
calling contains(). Update the catch block in RedshiftPlugin to guard the
message lookup before checking for "The column index is out of range:", keeping
the existing SQLException/IllegalArgumentException/java.io.IOException flow
intact while avoiding an NPE.

---

Nitpick comments:
In
`@app/server/appsmith-plugins/snowflakePlugin/src/main/java/com/external/plugins/SnowflakePlugin.java`:
- Around line 307-313: In SnowflakePlugin’s prepared-statement value handling,
the BYTES branch is using the string-based UTF-8 lookup, which adds an
unnecessary checked-exception path. Update the BYTES case in the switch that
calls preparedStatement.setBytes to use StandardCharsets.UTF_8 instead of the
string literal, and remove any now-dead IOException/UnsupportedEncodingException
handling around this conversion if it becomes unused.
- Around line 357-358: The default branch in SnowflakePlugin’s parameter binding
switch is silently ignoring unknown DataType values, which leaves placeholders
unbound while insertedParams still tracks them. Update the binding logic in the
relevant parameter-processing method to fail fast on unsupported types, either
by logging a clear warning and stopping or by throwing an explicit exception, so
the issue is caught before JDBC execution.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 215dcebe-0403-499a-83f9-a443d16e56e9

📥 Commits

Reviewing files that changed from the base of the PR and between 48ac053 and 599b08f.

📒 Files selected for processing (19)
  • app/server/appsmith-plugins/databricksPlugin/src/main/java/com/external/plugins/DatabricksPlugin.java
  • app/server/appsmith-plugins/databricksPlugin/src/main/java/com/external/plugins/exceptions/DatabricksErrorMessages.java
  • app/server/appsmith-plugins/databricksPlugin/src/main/resources/dependency.json
  • app/server/appsmith-plugins/databricksPlugin/src/main/resources/editor/root.json
  • app/server/appsmith-plugins/databricksPlugin/src/main/resources/setting.json
  • app/server/appsmith-plugins/databricksPlugin/src/test/java/com/external/plugins/DatabricksPluginTest.java
  • app/server/appsmith-plugins/redshiftPlugin/src/main/java/com/external/plugins/RedshiftPlugin.java
  • app/server/appsmith-plugins/redshiftPlugin/src/main/java/com/external/plugins/exceptions/RedshiftErrorMessages.java
  • app/server/appsmith-plugins/redshiftPlugin/src/main/resources/dependency.json
  • app/server/appsmith-plugins/redshiftPlugin/src/main/resources/editor.json
  • app/server/appsmith-plugins/redshiftPlugin/src/main/resources/setting.json
  • app/server/appsmith-plugins/redshiftPlugin/src/test/java/com/external/plugins/RedshiftPluginTest.java
  • app/server/appsmith-plugins/snowflakePlugin/src/main/java/com/external/plugins/SnowflakePlugin.java
  • app/server/appsmith-plugins/snowflakePlugin/src/main/java/com/external/plugins/exceptions/SnowflakeErrorMessages.java
  • app/server/appsmith-plugins/snowflakePlugin/src/main/java/com/external/utils/ExecutionUtils.java
  • app/server/appsmith-plugins/snowflakePlugin/src/main/resources/dependency.json
  • app/server/appsmith-plugins/snowflakePlugin/src/main/resources/editor.json
  • app/server/appsmith-plugins/snowflakePlugin/src/main/resources/setting.json
  • app/server/appsmith-plugins/snowflakePlugin/src/test/java/com/external/plugins/SnowflakePluginTest.java

wyattwalter and others added 2 commits July 8, 2026 15:48
…nowflake and Databricks

- Guard against a null exception message when classifying JDBC binding
  errors so a null message no longer triggers a NullPointerException.
- Log a warning when an unrecognized data type is encountered during
  parameter binding, instead of silently leaving the placeholder unbound
  and surfacing a confusing driver error later.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@wyattwalter

Copy link
Copy Markdown
Contributor Author

/build-deploy-preview

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown

Deploying Your Preview: https://github.com/appsmithorg/appsmith/actions/runs/28978657747.
Workflow: On demand build Docker image and deploy preview.
skip-tests: . env: .
PR: 41967.
recreate: .
base-image-tag: .

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown

Deploy-Preview-URL: https://ce-41967.dp.appsmith.com

@subrata71 subrata71 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

There's a good chance of regressions. It needs manual verification since there are not enough automated test coverage for these areas. The changes look good by the way.

@wyattwalter
wyattwalter marked this pull request as draft July 16, 2026 14:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants