Skip to content

Commit

Permalink
Support error packet without sqlstate (#1160)
Browse files Browse the repository at this point in the history
Fix #1156
  • Loading branch information
methane authored Feb 2, 2024
1 parent 9694747 commit bbd049f
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 13 deletions.
2 changes: 0 additions & 2 deletions pymysql/connections.py
Original file line number Diff line number Diff line change
Expand Up @@ -765,8 +765,6 @@ def _read_packet(self, packet_type=MysqlPacket):
dump_packet(recv_data)
buff += recv_data
# https://dev.mysql.com/doc/internals/en/sending-more-than-16mbyte.html
if bytes_to_read == 0xFFFFFF:
continue
if bytes_to_read < MAX_PACKET_LEN:
break

Expand Down
9 changes: 8 additions & 1 deletion pymysql/err.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,14 @@ def _map_error(exc, *errors):

def raise_mysql_exception(data):
errno = struct.unpack("<h", data[1:3])[0]
errval = data[9:].decode("utf-8", "replace")
# https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_err_packet.html
# Error packet has optional sqlstate that is 5 bytes and starts with '#'.
if data[3] == 0x23: # '#'
# sqlstate = data[4:9].decode()
# TODO: Append (sqlstate) in the error message. This will be come in next minor release.
errval = data[9:].decode("utf-8", "replace")
else:
errval = data[3:].decode("utf-8", "replace")
errorclass = error_map.get(errno)
if errorclass is None:
errorclass = InternalError if errno < 1000 else OperationalError
Expand Down
22 changes: 12 additions & 10 deletions pymysql/tests/test_err.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import unittest

import pytest
from pymysql import err


__all__ = ["TestRaiseException"]

def test_raise_mysql_exception():
data = b"\xff\x15\x04#28000Access denied"
with pytest.raises(err.OperationalError) as cm:
err.raise_mysql_exception(data)
assert cm.type == err.OperationalError
assert cm.value.args == (1045, "Access denied")

class TestRaiseException(unittest.TestCase):
def test_raise_mysql_exception(self):
data = b"\xff\x15\x04#28000Access denied"
with self.assertRaises(err.OperationalError) as cm:
err.raise_mysql_exception(data)
self.assertEqual(cm.exception.args, (1045, "Access denied"))
data = b"\xff\x10\x04Too many connections"
with pytest.raises(err.OperationalError) as cm:
err.raise_mysql_exception(data)
assert cm.type == err.OperationalError
assert cm.value.args == (1040, "Too many connections")
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ version = {attr = "pymysql.VERSION_STRING"}
exclude = [
"pymysql/tests/thirdparty",
]

[tool.ruff.lint]
ignore = ["E721"]

[tool.pdm.dev-dependencies]
Expand Down

0 comments on commit bbd049f

Please sign in to comment.