Skip to content

Commit fcd55de

Browse files
committed
refactor: deprecate usage of cursor.execute statements in favor of the in class implementation of execute.
1 parent 297a19e commit fcd55de

File tree

2 files changed

+33
-14
lines changed

2 files changed

+33
-14
lines changed

pandas/io/sql.py

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -997,7 +997,7 @@ def _execute_insert(self, conn, keys: list[str], data_iter) -> int:
997997
Each item contains a list of values to be inserted
998998
"""
999999
data = [dict(zip(keys, row)) for row in data_iter]
1000-
result = conn.execute(self.table.insert(), data)
1000+
result = self.pd_sql.execute(self.table.insert(), data)
10011001
return result.rowcount
10021002

10031003
def _execute_insert_multi(self, conn, keys: list[str], data_iter) -> int:
@@ -1014,7 +1014,7 @@ def _execute_insert_multi(self, conn, keys: list[str], data_iter) -> int:
10141014

10151015
data = [dict(zip(keys, row)) for row in data_iter]
10161016
stmt = insert(self.table).values(data)
1017-
result = conn.execute(stmt)
1017+
result = self.pd_sql.execute(stmt)
10181018
return result.rowcount
10191019

10201020
def insert_data(self) -> tuple[list[str], list[np.ndarray]]:
@@ -1651,10 +1651,18 @@ def run_transaction(self):
16511651

16521652
def execute(self, sql: str | Select | TextClause, params=None):
16531653
"""Simple passthrough to SQLAlchemy connectable"""
1654+
from sqlalchemy.exc import DBAPIError as SQLAlchemyDatabaseError
1655+
16541656
args = [] if params is None else [params]
16551657
if isinstance(sql, str):
1656-
return self.con.exec_driver_sql(sql, *args)
1657-
return self.con.execute(sql, *args)
1658+
execute_function = self.con.exec_driver_sql
1659+
else:
1660+
execute_function = self.con.execute
1661+
1662+
try:
1663+
return execute_function(sql, *args)
1664+
except SQLAlchemyDatabaseError as exc:
1665+
raise DatabaseError(f"Execution failed on sql '{sql}': {exc}") from exc
16581666

16591667
def read_table(
16601668
self,
@@ -2108,17 +2116,19 @@ def run_transaction(self):
21082116
self.con.commit()
21092117

21102118
def execute(self, sql: str | Select | TextClause, params=None):
2119+
from adbc_driver_manager import DatabaseError as ADBCDatabaseError
2120+
21112121
if not isinstance(sql, str):
21122122
raise TypeError("Query must be a string unless using sqlalchemy.")
21132123
args = [] if params is None else [params]
21142124
cur = self.con.cursor()
21152125
try:
21162126
cur.execute(sql, *args)
21172127
return cur
2118-
except Exception as exc:
2128+
except ADBCDatabaseError as exc:
21192129
try:
21202130
self.con.rollback()
2121-
except Exception as inner_exc: # pragma: no cover
2131+
except ADBCDatabaseError as inner_exc: # pragma: no cover
21222132
ex = DatabaseError(
21232133
f"Execution failed on sql: {sql}\n{exc}\nunable to rollback"
21242134
)
@@ -2335,6 +2345,9 @@ def to_sql(
23352345
engine : {'auto', 'sqlalchemy'}, default 'auto'
23362346
Raises NotImplementedError if not set to 'auto'
23372347
"""
2348+
from adbc_driver_manager import DatabaseError as ADBCDatabaseError
2349+
import pyarrow as pa
2350+
23382351
if index_label:
23392352
raise NotImplementedError(
23402353
"'index_label' is not implemented for ADBC drivers"
@@ -2369,17 +2382,18 @@ def to_sql(
23692382
elif if_exists == "append":
23702383
mode = "append"
23712384

2372-
import pyarrow as pa
2373-
23742385
try:
23752386
tbl = pa.Table.from_pandas(frame, preserve_index=index)
23762387
except pa.ArrowNotImplementedError as exc:
23772388
raise ValueError("datatypes not supported") from exc
23782389

23792390
with self.con.cursor() as cur:
2380-
total_inserted = cur.adbc_ingest(
2381-
table_name=name, data=tbl, mode=mode, db_schema_name=schema
2382-
)
2391+
try:
2392+
total_inserted = cur.adbc_ingest(
2393+
table_name=name, data=tbl, mode=mode, db_schema_name=schema
2394+
)
2395+
except ADBCDatabaseError as exc:
2396+
raise DatabaseError("Execution failed") from exc
23832397

23842398
self.con.commit()
23852399
return total_inserted
@@ -2520,8 +2534,13 @@ def insert_statement(self, *, num_rows: int) -> str:
25202534
return insert_statement
25212535

25222536
def _execute_insert(self, conn, keys, data_iter) -> int:
2537+
from sqlite3 import DatabaseError as SQLiteDatabaseError
2538+
25232539
data_list = list(data_iter)
2524-
conn.executemany(self.insert_statement(num_rows=1), data_list)
2540+
try:
2541+
conn.executemany(self.insert_statement(num_rows=1), data_list)
2542+
except SQLiteDatabaseError as exc:
2543+
raise DatabaseError("Execution failed") from exc
25252544
return conn.rowcount
25262545

25272546
def _execute_insert_multi(self, conn, keys, data_iter) -> int:

pandas/tests/io/test_sql.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3409,8 +3409,8 @@ def test_to_sql_with_negative_npinf(conn, request, input):
34093409
mark = pytest.mark.xfail(reason="GH 36465")
34103410
request.applymarker(mark)
34113411

3412-
msg = "inf cannot be used with MySQL"
3413-
with pytest.raises(ValueError, match=msg):
3412+
msg = "Execution failed on sql"
3413+
with pytest.raises(pd.errors.DatabaseError, match=msg):
34143414
df.to_sql(name="foobar", con=conn, index=False)
34153415
else:
34163416
assert df.to_sql(name="foobar", con=conn, index=False) == 1

0 commit comments

Comments
 (0)