Skip to content

Commit 58f7be0

Browse files
sfc-gh-alingsfc-gh-pczajka
authored andcommitted
SNOW-2007887: improve error message handling related to timeout (#2236)
1 parent b55d3d5 commit 58f7be0

File tree

2 files changed

+32
-2
lines changed

2 files changed

+32
-2
lines changed

src/snowflake/connector/cursor.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1083,7 +1083,15 @@ def execute(
10831083
logger.debug(ret)
10841084
err = ret["message"]
10851085
code = ret.get("code", -1)
1086-
if self._timebomb and self._timebomb.executed:
1086+
if (
1087+
self._timebomb
1088+
and self._timebomb.executed
1089+
and "SQL execution canceled" in err
1090+
):
1091+
# Modify the error message only if the server error response indicates the query was canceled.
1092+
# If the error occurs before the cancellation request reaches the backend
1093+
# (e.g., due to a very short timeout), we retain the original error message
1094+
# as the query might have encountered an issue prior to cancellation.
10871095
err = (
10881096
f"SQL execution was cancelled by the client due to a timeout. "
10891097
f"Error message received from the server: {err}"

test/integ/test_cursor.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from datetime import date, datetime, timezone
1515
from typing import TYPE_CHECKING, NamedTuple
1616
from unittest import mock
17+
from unittest.mock import MagicMock
1718

1819
import pytest
1920
import pytz
@@ -826,6 +827,7 @@ def test_invalid_bind_data_type(conn_cnx):
826827
cnx.cursor().execute("select 1 from dual where 1=%s", ([1, 2, 3],))
827828

828829

830+
@pytest.mark.skipolddriver
829831
def test_timeout_query(conn_cnx):
830832
with conn_cnx() as cnx:
831833
with cnx.cursor() as c:
@@ -836,10 +838,30 @@ def test_timeout_query(conn_cnx):
836838
)
837839
assert err.value.errno == 604, (
838840
"Invalid error code"
839-
and "SQL execution was cancelled by the client due to a timeout"
841+
and "SQL execution was cancelled by the client due to a timeout. Error message received from the server: SQL execution canceled"
840842
in err.value.msg
841843
)
842844

845+
with pytest.raises(errors.ProgrammingError) as err:
846+
# we can not precisely control the timing to send cancel query request right after server
847+
# executes the query but before returning the results back to client
848+
# it depends on python scheduling and server processing speed, so we mock here
849+
with mock.patch.object(
850+
c, "_timebomb", new_callable=MagicMock
851+
) as mock_timerbomb:
852+
mock_timerbomb.executed = True
853+
c.execute(
854+
"select 123'",
855+
timeout=0.1,
856+
)
857+
assert c._timebomb.executed is True and err.value.errno == 1003, (
858+
"Invalid error code"
859+
and "SQL compilation error:\nsyntax error line 1 at position 10 unexpected '''."
860+
in err.value.msg
861+
and "SQL execution was cancelled by the client due to a timeout"
862+
not in err.value.msg
863+
)
864+
843865

844866
def test_executemany(conn, db_parameters):
845867
"""Executes many statements. Client binding is supported by either dict, or list data types.

0 commit comments

Comments
 (0)