Skip to content

feat(rust): add prepared statement and parameter binding support#378

Open
vikrantpuppala wants to merge 8 commits intomainfrom
feat/rust-prepared-statement-design
Open

feat(rust): add prepared statement and parameter binding support#378
vikrantpuppala wants to merge 8 commits intomainfrom
feat/rust-prepared-statement-design

Conversation

@vikrantpuppala
Copy link
Copy Markdown
Collaborator

@vikrantpuppala vikrantpuppala commented Mar 31, 2026

Summary

  • Add prepared statement and parameter binding support to the Rust ADBC driver via the SEA API's positional parameters
  • Implement prepare(), bind(), bind_stream(), get_parameter_schema(), and fix execute_schema() to use DESCRIBE QUERY instead of full execution
  • Add SQL ? marker parsing (ignoring string literals/comments), Arrow-to-Databricks type conversion, and value serialization
  • bind_stream() executes one SEA API call per row (no batch INSERT optimization)
  • Fix missing databricks.auth.type in integration and FFI test setup

Files changed

File Change
src/types/sea.rs StatementParameter struct, parameters field on ExecuteStatementRequest and ExecuteParams
src/statement/mod.rs New fields, prepare/bind/bind_stream/get_parameter_schema impl, execute_schema fix, updated execute
src/statement/params.rs (new) SQL parser, Arrow→SEA conversion, DESCRIBE QUERY parsing, type mappings (30 unit tests)
src/client/sea.rs Wire parameters from ExecuteParams to ExecuteStatementRequest
src/reader/mod.rs VecBatchReader + ResultReaderAdapter::from_batches() for stream result collection
tests/prepared_statement_e2e.rs (new) 10 E2E tests: parameterized SELECT, multiple params, NULL, boolean, bigint, bind_stream, execute_schema, rebind
tests/integration.rs, tests/ffi_round_trip.rs Add missing databricks.auth.type option

Test plan

  • 30 unit tests for SQL parsing, Arrow→SEA conversion, type mapping, DESCRIBE QUERY parsing
  • 10 E2E tests passing against dogfood (parameterized queries, bind_stream, execute_schema via DESCRIBE QUERY, rebind/re-execute)
  • All 286 existing unit tests pass
  • cargo fmt, cargo clippy clean

This pull request was AI-assisted by Isaac.

@vikrantpuppala vikrantpuppala changed the title docs(rust): add prepared statement & parameter binding design feat(rust): add prepared statement and parameter binding support Mar 31, 2026
} else if bytes[i] == b'\'' {
state = SqlParserState::InSingleQuote;
i += 1;
} else if i + 1 < len && bytes[i] == b'-' && bytes[i + 1] == b'-' {
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.

shall we also include double quotes and backticks?

.to_adbc()
})?;

// Execute once per row in this batch
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.

looks inefficient, but okay since server side batch support would be coming soon

return sql.to_string();
}

// Build result string, replacing each `?` at marker positions with `'?'`
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.

this is a gap, will change the datatype, but may need to live with this

DataType::Date32 => {
let arr = array.as_primitive::<Date32Type>();
let days = arr.value(index);
let date = chrono::NaiveDate::from_num_days_from_ce_opt(days + 719_163)
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.

arrow_array provides Date32Array::value_as_date(index), can we use that?

Design for adding parameterized query support to the Rust ADBC driver
via the SEA API's positional parameters. Covers SQL marker parsing,
Arrow-to-SEA type conversion, bind/bind_stream lifecycle, and testing
strategy.

Co-authored-by: Isaac
execute_schema() currently does a full execute, violating the ADBC spec
("get schema without executing") and causing side effects for DML. Add
DESCRIBE QUERY approach with parameter marker substitution to the
prepared statement design doc.

Co-authored-by: Isaac
Implement parameterized query support via the SEA API's positional
parameters. Includes SQL marker parsing, Arrow-to-SEA type conversion,
bind/bind_stream lifecycle, and execute_schema via DESCRIBE QUERY.

Changes:
- Add StatementParameter type and wire through ExecuteParams/SeaClient
- Convert statement.rs to statement/ module with new params submodule
- Implement prepare(), bind(), bind_stream(), get_parameter_schema()
- Fix execute_schema() to use DESCRIBE QUERY (no side effects)
- Add VecBatchReader and ResultReaderAdapter::from_batches() for
  bind_stream result collection
- Add E2E tests for parameterized queries, bind_stream, execute_schema
- Fix missing auth.type in integration and FFI test setup

Co-authored-by: Isaac
Both execute() paths now collect into (schema, Vec<RecordBatch>) and
return a RecordBatchIterator, eliminating the need for VecBatchReader
and ResultReaderAdapter::from_batches().

Co-authored-by: Isaac
- Remove unnecessary `unsafe impl Send for Statement`
- Fix execute() to stream results lazily for non-bind_stream path
  instead of buffering all batches in memory
- Close server-side statements after draining in execute_with_stream
  to prevent statement ID leaks
- Fix format_decimal128 sign loss for negative values where |raw| < divisor
- Fix timestamp nanosecond conversion for negative (pre-epoch) values
  using div_euclid/rem_euclid
- Add UInt8/16/32/64 support to Arrow-to-Databricks type mapping
- Add missing test cases for negative decimal edge cases

Co-authored-by: Isaac
Move arrow_type_to_databricks() to metadata/type_mapping.rs alongside
databricks_type_to_arrow() so both directions live in one file. Remove
duplicate databricks_type_to_arrow_type() and parse_decimal_params()
from statement/params.rs. Add module-level comment that both mapping
functions must be updated together.

Co-authored-by: Isaac
- Add double quote and backtick quote handling to SQL parser so `?`
  inside quoted identifiers is not treated as a parameter marker
- Use arrow-array's built-in value_as_date/value_as_datetime helpers
  for Date32, Date64, and Timestamp conversions instead of manual
  epoch arithmetic
- Add tests for double-quoted and backtick-quoted identifier parsing

Co-authored-by: Isaac
@vikrantpuppala vikrantpuppala force-pushed the feat/rust-prepared-statement-design branch from 402cad0 to c2f1ad6 Compare April 9, 2026 10:25
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