Skip to content

Commit cf9a436

Browse files
authored
Merge pull request #19 from ydb-platform/dbapi-excp-mapping
dbapi: ydb driver exception mapping
2 parents 188ba2a + ff75f5c commit cf9a436

File tree

3 files changed

+73
-10
lines changed

3 files changed

+73
-10
lines changed

test_dbapi/test_dbapi.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def test_connection(connection):
1515
cur.execute("DROP TABLE foo", context={"isddl": True})
1616

1717
assert not connection.check_exists("/local/foo")
18-
with pytest.raises(dbapi.DatabaseError):
18+
with pytest.raises(dbapi.ProgrammingError):
1919
connection.describe("/local/foo")
2020

2121
cur.execute("CREATE TABLE foo(id Int64 NOT NULL, PRIMARY KEY (id))", context={"isddl": True})
@@ -107,3 +107,34 @@ def test_cursor(connection):
107107

108108
cur.close()
109109
cur2.close()
110+
111+
112+
def test_errors(connection):
113+
with pytest.raises(dbapi.InterfaceError):
114+
dbapi.connect("localhost:2136", database="/local666")
115+
116+
cur = connection.cursor()
117+
118+
with suppress(dbapi.DatabaseError):
119+
cur.execute("DROP TABLE test", context={"isddl": True})
120+
121+
with pytest.raises(dbapi.DataError):
122+
cur.execute("SELECT 18446744073709551616")
123+
124+
with pytest.raises(dbapi.DataError):
125+
cur.execute("SELECT * FROM 拉屎")
126+
127+
with pytest.raises(dbapi.DataError):
128+
cur.execute("SELECT floor(5 / 2)")
129+
130+
with pytest.raises(dbapi.ProgrammingError):
131+
cur.execute("SELECT * FROM test")
132+
133+
cur.execute("CREATE TABLE test(id Int64, PRIMARY KEY (id))", context={"isddl": True})
134+
135+
cur.execute("INSERT INTO test(id) VALUES(1)")
136+
with pytest.raises(dbapi.IntegrityError):
137+
cur.execute("INSERT INTO test(id) VALUES(1)")
138+
139+
cur.execute("DROP TABLE test", context={"isddl": True})
140+
cur.close()

ydb_sqlalchemy/dbapi/connection.py

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

33
import ydb
44
from .cursor import Cursor
5-
from .errors import DatabaseError
5+
from .errors import InterfaceError, ProgrammingError, DatabaseError
66

77

88
class Connection:
@@ -19,10 +19,12 @@ def describe(self, table_path):
1919
full_path = posixpath.join(self.database, table_path)
2020
try:
2121
return self.pool.retry_operation_sync(lambda cli: cli.describe_table(full_path))
22+
except ydb.issues.SchemeError as e:
23+
raise ProgrammingError(e.message, e.issues, e.status) from e
2224
except ydb.Error as e:
23-
raise DatabaseError(e.message, e.issues, e.status)
24-
except Exception:
25-
raise DatabaseError(f"Failed to describe table {table_path}")
25+
raise DatabaseError(e.message, e.issues, e.status) from e
26+
except Exception as e:
27+
raise DatabaseError(f"Failed to describe table {table_path}") from e
2628

2729
def check_exists(self, table_path):
2830
try:
@@ -61,8 +63,8 @@ def _create_driver(endpoint, database, **conn_kwargs):
6163
try:
6264
driver.wait(timeout=5, fail_fast=True)
6365
except ydb.Error as e:
64-
raise DatabaseError(e.message, e.issues, e.status)
65-
except Exception:
66+
raise InterfaceError(e.message, e.issues, e.status) from e
67+
except Exception as e:
6668
driver.stop()
67-
raise DatabaseError(f"Failed to connect to YDB, details {driver.discovery_debug_details()}")
69+
raise InterfaceError(f"Failed to connect to YDB, details {driver.discovery_debug_details()}") from e
6870
return driver

ydb_sqlalchemy/dbapi/cursor.py

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,15 @@
77
from typing import Optional, Dict, Any
88

99
import ydb
10-
from .errors import IntegrityError, DatabaseError, ProgrammingError
10+
from .errors import (
11+
InternalError,
12+
IntegrityError,
13+
DataError,
14+
DatabaseError,
15+
ProgrammingError,
16+
OperationalError,
17+
NotSupportedError,
18+
)
1119

1220

1321
logger = logging.getLogger(__name__)
@@ -107,6 +115,28 @@ def _execute_in_pool(cli):
107115
return cli.transaction().execute(prepared_query, sql_params, commit_tx=True)
108116
except (ydb.issues.AlreadyExists, ydb.issues.PreconditionFailed) as e:
109117
raise IntegrityError(e.message, e.issues, e.status) from e
118+
except (ydb.issues.Unsupported, ydb.issues.Unimplemented) as e:
119+
raise NotSupportedError(e.message, e.issues, e.status) from e
120+
except (ydb.issues.BadRequest, ydb.issues.SchemeError) as e:
121+
raise ProgrammingError(e.message, e.issues, e.status) from e
122+
except (
123+
ydb.issues.TruncatedResponseError,
124+
ydb.issues.ConnectionError,
125+
ydb.issues.Aborted,
126+
ydb.issues.Unavailable,
127+
ydb.issues.Overloaded,
128+
ydb.issues.Undetermined,
129+
ydb.issues.Timeout,
130+
ydb.issues.Cancelled,
131+
ydb.issues.SessionBusy,
132+
ydb.issues.SessionExpired,
133+
ydb.issues.SessionPoolEmpty,
134+
) as e:
135+
raise OperationalError(e.message, e.issues, e.status) from e
136+
except ydb.issues.GenericError as e:
137+
raise DataError(e.message, e.issues, e.status) from e
138+
except ydb.issues.InternalError as e:
139+
raise InternalError(e.message, e.issues, e.status) from e
110140
except ydb.Error as e:
111141
raise DatabaseError(e.message, e.issues, e.status) from e
112142

@@ -144,7 +174,7 @@ def _rows_iterable(self, chunks_iterable):
144174
# of this PEP to return a sequence: https://www.python.org/dev/peps/pep-0249/#fetchmany
145175
yield row[::]
146176
except ydb.Error as e:
147-
raise DatabaseError(e.message, e.issues, e.status)
177+
raise DatabaseError(e.message, e.issues, e.status) from e
148178

149179
def _ensure_prefetched(self):
150180
if self.rows is not None and self._rows_prefetched is None:

0 commit comments

Comments
 (0)