You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Support cursor.rowcount for DML on the Thrift backend (#784) (#847)
* Support cursor.rowcount for DML on the Thrift backend (#784)
cursor.rowcount was hardcoded to -1 and never updated for the Thrift
backend (the default). For DML (INSERT/UPDATE/DELETE/MERGE) the
Databricks Thrift server reports the affected-row count in
TGetOperationStatusResp.numModifiedRows, but the connector discarded it —
_wait_until_command_done kept only operationState.
Thread numModifiedRows through: _wait_until_command_done now returns the
terminal status response, _handle_execute_response reads numModifiedRows
from it, ExecuteResponse and ResultSet carry a num_modified_rows field,
and Cursor.execute sets self.rowcount from it. rowcount resets to -1
before each statement so a DML count never leaks into a later SELECT.
SELECT (and statements the server does not report a count for) leave
rowcount at its -1 default. This brings the Thrift path in line with the
kernel backend, which already surfaces num_modified_rows.
Closes#784
Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
* test(e2e): verify DML cursor.rowcount against a live warehouse (#784)
End-to-end test in TestPySQLCoreSuite exercising INSERT/UPDATE/DELETE on
a real Thrift warehouse and asserting cursor.rowcount reports the exact
affected-row count (3/2/1), then that a following SELECT resets it to -1.
Verified live on dogfood; fails with the fix reverted (rowcount stays -1).
Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
* Aggregate executemany rowcount across parameter sets (#784)
Address PR review: executemany looped execute() per parameter set and,
since each execute() resets rowcount, left rowcount equal to only the
final set's affected-row count. Per PEP 249, rowcount after executemany
should reflect the total across all operations. Accumulate the reported
per-statement counts; if no statement reports a count (all SELECT / the
server reports none), rowcount stays at its -1 default.
Adds unit tests for the sum, mixed reported/unreported, and all-unreported
cases, and extends the live e2e test to assert executemany aggregation.
Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
---------
Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
Copy file name to clipboardExpand all lines: CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,6 +2,7 @@
2
2
3
3
# Unreleased
4
4
- Fix: `REMOVE` staging operations no longer require `staging_allowed_local_path` to be set, since removing a remote file does not touch the local filesystem (databricks/databricks-sql-python#726)
5
+
- Report `cursor.rowcount` for DML on the Thrift backend: INSERT/UPDATE/DELETE/MERGE now set `rowcount` to the server's affected-row count instead of the hardcoded `-1`; SELECT (and statements the server does not report a count for) still return `-1`. `executemany` aggregates the count across all parameter sets per PEP 249 ([#784](https://github.com/databricks/databricks-sql-python/issues/784))
5
6
6
7
# 4.3.0 (2026-06-12)
7
8
-**New: optional Rust kernel backend (`use_kernel=True`).** Adds an alternative connection path backed by the native [`databricks-sql-kernel`](https://pypi.org/project/databricks-sql-kernel/) client (a Rust core exposed via PyO3), installable with the new `databricks-sql-connector[kernel]` extra. The kernel talks to Databricks over the **SEA (Statement Execution API) HTTP transport** — not Thrift — with CloudFetch and inline-Arrow result fetching, so `use_kernel=True` gives you a modern SEA-native client through the same DB-API surface. Supports PAT, OAuth M2M, and OAuth U2M auth. Requires Python >= 3.10 (the kernel wheel is `cp310-abi3`); on older interpreters the extra is a no-op and `use_kernel=True` raises a clear `ImportError`. The default backend remains Thrift — opt in per connection.
0 commit comments