Skip to content

Commit a82dba0

Browse files
fix(volume): reject stream markers and classify remote failures
Signed-off-by: Aakash Saravanan <aakash.saravanan@databricks.com>
1 parent 175efa3 commit a82dba0

5 files changed

Lines changed: 39 additions & 6 deletions

File tree

‎CONNECTION_PARAMETERS.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -206,12 +206,12 @@ installed kernel binding. `force_enable_telemetry` remains Python-driver-only.
206206
`enable_query_result_lz4_compression`.
207207
5. Arrow-native rendering for `_use_arrow_native_decimals` /
208208
`_use_arrow_native_timestamps` (complex types **are** forwarded).
209-
7. Retry fine-tuning beyond the four forwarded knobs: `_retry_delay_default`,
209+
6. Retry fine-tuning beyond the four forwarded knobs: `_retry_delay_default`,
210210
`_retry_dangerous_codes`, `_respect_server_retry_after_header`,
211211
`_retry_max_redirects`, `_enable_v3_retries`.
212-
8. `force_enable_telemetry`.
213-
9. `_port` and `_connection_uri`.
214-
10. `_pool_connections` and `_proxy_auth_method` do not configure the
212+
7. `force_enable_telemetry`.
213+
8. `_port` and `_connection_uri`.
214+
9. `_pool_connections` and `_proxy_auth_method` do not configure the
215215
kernel-owned network stack.
216216

217217
### Supported on Kernel, missing / ignored on Thrift

‎KERNEL_REV‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
bc39c7921acecd95e4eea0740becb883867a834b
1+
ebb8204b36951b751dd837b2c41ced8c821b2d94

‎src/databricks/sql/backend/kernel/_errors.py‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,11 @@ def reraise_kernel_error(
131131
cls = _CODE_TO_EXCEPTION.get(code, DatabaseError)
132132
file_transfer = getattr(exc, "error_code", None) == "FILE_TRANSFER_ERROR"
133133
if file_transfer:
134-
cls = ProgrammingError if code == "PermissionDenied" else OperationalError
134+
cls = (
135+
ProgrammingError
136+
if code == "PermissionDenied" and getattr(exc, "http_status", None) is None
137+
else OperationalError
138+
)
135139

136140
# For ServerOperationError, reproduce the Thrift backend's
137141
# ``context`` dict so callers that read

‎src/databricks/sql/backend/kernel/client.py‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
import inspect
2424
import logging
25+
import re
2526
import threading
2627
import uuid
2728
from typing import Any, Dict, List, Optional, Set, TYPE_CHECKING, Union
@@ -577,6 +578,14 @@ def execute_command(
577578
close_stmt = True
578579
try:
579580
try:
581+
if re.match(
582+
r"""PUT\s+(['"])__input_stream__\1(?:\s|$)""",
583+
_strip_leading_sql_comments(operation),
584+
re.IGNORECASE,
585+
):
586+
raise NotSupportedError(
587+
"Streaming PUT is not supported by the kernel backend."
588+
)
580589
stmt.set_sql(operation)
581590
allowed_paths = cursor.connection.staging_allowed_local_path
582591
if isinstance(allowed_paths, str):

‎tests/unit/test_kernel_client.py‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -844,6 +844,25 @@ def test_execute_command_forwards_allowed_local_paths(allowed, expected, async_o
844844
(stmt.submit if async_op else stmt.execute).assert_called_once()
845845

846846

847+
@pytest.mark.parametrize(
848+
"query",
849+
[
850+
"PUT '__input_stream__' INTO '/Volumes/c/s/v/file'",
851+
"/* upload */ PUT '__input_stream__' INTO '/Volumes/c/s/v/file'",
852+
],
853+
)
854+
def test_kernel_rejects_streaming_put(query):
855+
c = _make_client()
856+
c._kernel_session = MagicMock()
857+
with pytest.raises(NotSupportedError, match="Streaming PUT"):
858+
c.execute_command(
859+
query, MagicMock(), 1, 1, False, MagicMock(), False, [], False, False
860+
)
861+
stmt = c._kernel_session.statement.return_value
862+
stmt.execute.assert_not_called()
863+
stmt.close.assert_called_once()
864+
865+
847866
@pytest.mark.parametrize(
848867
"operation",
849868
[
@@ -2599,6 +2618,7 @@ def test_only_reserved_headers_omits_kwarg(self, monkeypatch):
25992618
"code, http_status, expected",
26002619
[
26012620
("PermissionDenied", None, ProgrammingError),
2621+
("PermissionDenied", 403, OperationalError),
26022622
("NotFound", None, FileNotFoundError),
26032623
("NotFound", 404, OperationalError),
26042624
("NetworkError", None, OperationalError),

0 commit comments

Comments
 (0)