Skip to content

Commit a611aee

Browse files
committed
BUG#37275524: Exception is not interpreted properly on prepared
statements when C extension is in use This patch fixes the issue where incorrect error class is being raised by the connector while working with the prepared statements using C-Extension by ensuring that correct exception structure is maintained while forwarding the exception from C-API to the connector interface. Change-Id: Idfa0ee340dcd4f4b69cf27893f67278074ae8250
1 parent e56c4ec commit a611aee

File tree

8 files changed

+134
-72
lines changed

8 files changed

+134
-72
lines changed

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ v9.3.0
1919
- BUG#37447394: Unable to escape a parameter marker (`%s`) used in a query that should not be treated as a parameter marker
2020
- BUG#37418436: Arbitrary File Read in MySQL Python Client library
2121
- BUG#37399636: The C-extension has a memory leak when working with prepared statements
22+
- BUG#37275524: Exception is not interpreted properly on prepared statements when C extension is in use
2223
- BUG#36098290: mysql-connector-python is distributed without setup.py or pyproject.toml
2324

2425
v9.2.0

mysql-connector-python/lib/mysql/connector/connection_cext.py

Lines changed: 79 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -214,9 +214,11 @@ def autocommit(self, value: bool) -> None:
214214
self._cmysql.autocommit(value)
215215
self._autocommit = value
216216
except MySQLInterfaceError as err:
217-
raise get_mysql_exception(
218-
msg=err.msg, errno=err.errno, sqlstate=err.sqlstate
219-
) from err
217+
if hasattr(err, "errno"):
218+
raise get_mysql_exception(
219+
err.errno, msg=err.msg, sqlstate=err.sqlstate
220+
) from err
221+
raise InterfaceError(str(err)) from err
220222

221223
@property
222224
def read_timeout(self) -> Optional[int]:
@@ -255,9 +257,11 @@ def database(self, value: str) -> None:
255257
try:
256258
self._cmysql.select_db(value)
257259
except MySQLInterfaceError as err:
258-
raise get_mysql_exception(
259-
msg=err.msg, errno=err.errno, sqlstate=err.sqlstate
260-
) from err
260+
if hasattr(err, "errno"):
261+
raise get_mysql_exception(
262+
err.errno, msg=err.msg, sqlstate=err.sqlstate
263+
) from err
264+
raise InterfaceError(str(err)) from err
261265

262266
@property
263267
def in_transaction(self) -> bool:
@@ -352,9 +356,11 @@ def _open_connection(self) -> None:
352356
if self.converter:
353357
self.converter.str_fallback = self._converter_str_fallback
354358
except MySQLInterfaceError as err:
355-
raise get_mysql_exception(
356-
msg=err.msg, errno=err.errno, sqlstate=err.sqlstate
357-
) from err
359+
if hasattr(err, "errno"):
360+
raise get_mysql_exception(
361+
err.errno, msg=err.msg, sqlstate=err.sqlstate
362+
) from err
363+
raise InterfaceError(str(err)) from err
358364

359365
self._do_handshake()
360366

@@ -386,9 +392,11 @@ def close(self) -> None:
386392
except MySQLInterfaceError as err:
387393
if OTEL_ENABLED:
388394
record_exception_event(self._span, err)
389-
raise get_mysql_exception(
390-
msg=err.msg, errno=err.errno, sqlstate=err.sqlstate
391-
) from err
395+
if hasattr(err, "errno"):
396+
raise get_mysql_exception(
397+
err.errno, msg=err.msg, sqlstate=err.sqlstate
398+
) from err
399+
raise InterfaceError(str(err)) from err
392400
finally:
393401
if OTEL_ENABLED:
394402
end_span(self._span)
@@ -452,9 +460,11 @@ def info_query(self, query: StrOrBytes) -> Optional[RowType]:
452460
raise InterfaceError("Query should not return more than 1 row")
453461
self._cmysql.free_result()
454462
except MySQLInterfaceError as err:
455-
raise get_mysql_exception(
456-
msg=err.msg, errno=err.errno, sqlstate=err.sqlstate
457-
) from err
463+
if hasattr(err, "errno"):
464+
raise get_mysql_exception(
465+
err.errno, msg=err.msg, sqlstate=err.sqlstate
466+
) from err
467+
raise InterfaceError(str(err)) from err
458468

459469
return first_row
460470

@@ -542,11 +552,13 @@ def get_rows(
542552
except MySQLInterfaceError as err:
543553
if prep_stmt:
544554
prep_stmt.free_result()
545-
raise InterfaceError(str(err)) from err
546-
self.free_result()
547-
raise get_mysql_exception(
548-
msg=err.msg, errno=err.errno, sqlstate=err.sqlstate
549-
) from err
555+
else:
556+
self.free_result()
557+
if hasattr(err, "errno"):
558+
raise get_mysql_exception(
559+
err.errno, msg=err.msg, sqlstate=err.sqlstate
560+
) from err
561+
raise InterfaceError(str(err)) from err
550562

551563
return rows, _eof
552564

@@ -603,9 +615,11 @@ def cmd_init_db(self, database: str) -> None:
603615
try:
604616
self._cmysql.select_db(database)
605617
except MySQLInterfaceError as err:
606-
raise get_mysql_exception(
607-
msg=err.msg, errno=err.errno, sqlstate=err.sqlstate
608-
) from err
618+
if hasattr(err, "errno"):
619+
raise get_mysql_exception(
620+
err.errno, msg=err.msg, sqlstate=err.sqlstate
621+
) from err
622+
raise InterfaceError(str(err)) from err
609623

610624
def fetch_eof_columns(
611625
self, prep_stmt: Optional[CMySQLPrepStmt] = None
@@ -669,6 +683,10 @@ def cmd_stmt_prepare(
669683
stmt.converter_str_fallback = self._converter_str_fallback
670684
return CMySQLPrepStmt(stmt)
671685
except MySQLInterfaceError as err:
686+
if hasattr(err, "errno"):
687+
raise get_mysql_exception(
688+
err.errno, msg=err.msg, sqlstate=err.sqlstate
689+
) from err
672690
raise InterfaceError(str(err)) from err
673691

674692
@with_context_propagation
@@ -682,6 +700,10 @@ def cmd_stmt_execute(
682700
try:
683701
statement_id.stmt_execute(*args, query_attrs=self.query_attrs)
684702
except MySQLInterfaceError as err:
703+
if hasattr(err, "errno"):
704+
raise get_mysql_exception(
705+
err.errno, msg=err.msg, sqlstate=err.sqlstate
706+
) from err
685707
raise InterfaceError(str(err)) from err
686708

687709
self._columns = []
@@ -704,9 +726,11 @@ def cmd_stmt_close(
704726
try:
705727
statement_id.stmt_close()
706728
except MySQLInterfaceError as err:
707-
raise get_mysql_exception(
708-
err.errno, msg=err.msg, sqlstate=err.sqlstate
709-
) from err
729+
if hasattr(err, "errno"):
730+
raise get_mysql_exception(
731+
err.errno, msg=err.msg, sqlstate=err.sqlstate
732+
) from err
733+
raise InterfaceError(str(err)) from err
710734

711735
def cmd_stmt_reset(
712736
self,
@@ -719,6 +743,10 @@ def cmd_stmt_reset(
719743
try:
720744
statement_id.stmt_reset()
721745
except MySQLInterfaceError as err:
746+
if hasattr(err, "errno"):
747+
raise get_mysql_exception(
748+
err.errno, msg=err.msg, sqlstate=err.sqlstate
749+
) from err
722750
raise InterfaceError(str(err)) from err
723751

724752
@with_context_propagation
@@ -749,9 +777,11 @@ def cmd_query(
749777
query_attrs=self.query_attrs,
750778
)
751779
except MySQLInterfaceError as err:
752-
raise get_mysql_exception(
753-
err.errno, msg=err.msg, sqlstate=err.sqlstate
754-
) from err
780+
if hasattr(err, "errno"):
781+
raise get_mysql_exception(
782+
err.errno, msg=err.msg, sqlstate=err.sqlstate
783+
) from err
784+
raise InterfaceError(str(err)) from err
755785
except AttributeError as err:
756786
addr = (
757787
self._unix_socket if self._unix_socket else f"{self._host}:{self._port}"
@@ -966,9 +996,11 @@ def cmd_change_user(
966996
)
967997

968998
except MySQLInterfaceError as err:
969-
raise get_mysql_exception(
970-
msg=err.msg, errno=err.errno, sqlstate=err.sqlstate
971-
) from err
999+
if hasattr(err, "errno"):
1000+
raise get_mysql_exception(
1001+
err.errno, msg=err.msg, sqlstate=err.sqlstate
1002+
) from err
1003+
raise InterfaceError(str(err)) from err
9721004

9731005
# If charset isn't defined, we use the same charset ID defined previously,
9741006
# otherwise, we run a verification and update the charset ID.
@@ -1000,9 +1032,11 @@ def cmd_refresh(self, options: int) -> Optional[CextEofPacketType]:
10001032
self.handle_unread_result()
10011033
self._cmysql.refresh(options)
10021034
except MySQLInterfaceError as err:
1003-
raise get_mysql_exception(
1004-
msg=err.msg, errno=err.errno, sqlstate=err.sqlstate
1005-
) from err
1035+
if hasattr(err, "errno"):
1036+
raise get_mysql_exception(
1037+
err.errno, msg=err.msg, sqlstate=err.sqlstate
1038+
) from err
1039+
raise InterfaceError(str(err)) from err
10061040

10071041
return self.fetch_eof_status()
10081042

@@ -1029,9 +1063,11 @@ def cmd_shutdown(self, shutdown_type: Optional[int] = None) -> None:
10291063
try:
10301064
self._cmysql.shutdown(level)
10311065
except MySQLInterfaceError as err:
1032-
raise get_mysql_exception(
1033-
msg=err.msg, errno=err.errno, sqlstate=err.sqlstate
1034-
) from err
1066+
if hasattr(err, "errno"):
1067+
raise get_mysql_exception(
1068+
err.errno, msg=err.msg, sqlstate=err.sqlstate
1069+
) from err
1070+
raise InterfaceError(str(err)) from err
10351071
self.close()
10361072

10371073
def cmd_statistics(self) -> StatsPacketType:
@@ -1042,9 +1078,11 @@ def cmd_statistics(self) -> StatsPacketType:
10421078
stat = self._cmysql.stat()
10431079
return MySQLProtocol().parse_statistics(stat, with_header=False)
10441080
except (MySQLInterfaceError, InterfaceError) as err:
1045-
raise get_mysql_exception(
1046-
msg=err.msg, errno=err.errno, sqlstate=err.sqlstate
1047-
) from err
1081+
if hasattr(err, "errno"):
1082+
raise get_mysql_exception(
1083+
err.errno, msg=err.msg, sqlstate=err.sqlstate
1084+
) from err
1085+
raise InterfaceError(str(err)) from err
10481086

10491087
def cmd_process_kill(self, mysql_pid: int) -> None:
10501088
"""Kill a MySQL process"""

mysql-connector-python/lib/mysql/connector/cursor_cext.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -238,9 +238,11 @@ def _fetch_warnings(self) -> Optional[List[WarningType]]:
238238
warns = self._connection.get_rows(raw=self._raw)[0]
239239
self._connection.consume_results()
240240
except MySQLInterfaceError as err:
241-
raise get_mysql_exception(
242-
msg=err.msg, errno=err.errno, sqlstate=err.sqlstate
243-
) from err
241+
if hasattr(err, "errno"):
242+
raise get_mysql_exception(
243+
err.errno, msg=err.msg, sqlstate=err.sqlstate
244+
) from err
245+
raise InterfaceError(str(err)) from err
244246
except Exception as err:
245247
raise InterfaceError(f"Failed getting warnings; {err}") from None
246248

@@ -359,9 +361,11 @@ def execute(
359361
)
360362
)
361363
except MySQLInterfaceError as err:
362-
raise get_mysql_exception(
363-
msg=err.msg, errno=err.errno, sqlstate=err.sqlstate
364-
) from err
364+
if hasattr(err, "errno"):
365+
raise get_mysql_exception(
366+
err.errno, msg=err.msg, sqlstate=err.sqlstate
367+
) from err
368+
raise InterfaceError(str(err)) from err
365369
return None
366370

367371
def _batch_insert(
@@ -648,9 +652,11 @@ def nextset(self) -> Optional[bool]:
648652
)
649653
)
650654
except MySQLInterfaceError as err:
651-
raise get_mysql_exception(
652-
msg=err.msg, errno=err.errno, sqlstate=err.sqlstate
653-
) from err
655+
if hasattr(err, "errno"):
656+
raise get_mysql_exception(
657+
err.errno, msg=err.msg, sqlstate=err.sqlstate
658+
) from err
659+
raise InterfaceError(str(err)) from err
654660
return True
655661

656662
self._reset_result(free=True)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy