[MDEV-26497] PyMySQL syntax error in prepared statement - behaviour different from MySQL Created: 2021-08-30  Updated: 2021-09-21  Resolved: 2021-09-21

Status: Closed
Project: MariaDB Server
Component/s: Prepared Statements
Affects Version/s: 10.0.38, 10.2.40, 10.3.32, 10.5.13
Fix Version/s: N/A

Type: Bug Priority: Major
Reporter: Daniel Black Assignee: Sergei Golubchik
Resolution: Not a Bug Votes: 0
Labels: None


 Description   

From:

https://github.com/grooverdan/PyMySQL/runs/3458715957?check_suite_focus=true#step:8:181

https://github.com/grooverdan/PyMySQL/runs/3458715926?check_suite_focus=true#step:8:179

10.5.13-MariaDB-4b6ef03dcda608109f0455732ab9ed65f32b06bb, 10.3.32-MariaDB-b378ddb3d3c3af75195d328018259369671bb029

=================================== FAILURES ===================================
_____________________________ TestCursor.test_json _____________________________
 
self = <pymysql.tests.test_basic.TestCursor testMethod=test_json>
 
        def test_json(self):
            args = self.databases[0].copy()
            args["charset"] = "utf8mb4"
            conn = pymysql.connect(**args)
            if not self.mysql_server_is(conn, (5, 7, 0)):
                pytest.skip("JSON type is not supported on MySQL <= 5.6")
    
            self.safe_create_table(
                conn,
                "test_json",
                """\
    create table test_json (
        id int not null,
        json JSON not null,
        primary key (id)
    );""",
            )
            cur = conn.cursor()
    
            json_str = '{"hello": "こんにちは"}'
            cur.execute("INSERT INTO test_json (id, `json`) values (42, %s)", (json_str,))
            cur.execute("SELECT `json` from `test_json` WHERE `id`=42")
            res = cur.fetchone()[0]
            self.assertEqual(json.loads(res), json.loads(json_str))
    
>           cur.execute("SELECT CAST(%s AS JSON) AS x", (json_str,))
 
pymysql/tests/test_basic.py:309: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
pymysql/cursors.py:158: in execute
    result = self._query(query)
pymysql/cursors.py:325: in _query
    conn.query(q)
pymysql/connections.py:546: in query
    self._affected_rows = self._read_query_result(unbuffered=unbuffered)
pymysql/connections.py:775: in _read_query_result
    result.read()
pymysql/connections.py:1152: in read
    first_packet = self.connection._read_packet()
pymysql/connections.py:725: in _read_packet
    packet.raise_for_error()
pymysql/protocol.py:221: in raise_for_error
    err.raise_mysql_exception(self._data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
 
data = b"\xff(\x04#42000You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'JSON) AS x' at line 1"

These test passed on 10.3.31, 10.5.12 (version in "Set up MySQL" step)
https://github.com/PyMySQL/PyMySQL/runs/3448912434?check_suite_focus=true



 Comments   
Comment by Daniel Black [ 2021-08-30 ]

Not a regression. Previous tests where skipped due to the version matching the 5.5.5

hacking pymysql to expose version

pymysql/tests/test_basic.py::TestCursor::test_json SKIPPED (JSON type is not supported on MySQL <= 5.6 - found 5.5.5-10.2.41-MariaDB-1:10.2.41+maria~bionic)        [ 75%]

However hacking the version like quay.io/mariadb-foundation/mariadb-devel containers do, or removing the version check in the tests, causes the failure where MySQL tests will pass.

$ container=$(podman run -d -e  MARIADB_ALLOW_EMPTY_ROOT_PASSWORD=1 -e MARIADB_USER=test2 -e MARIADB_PASSWORD="some password" -e MARIADB_DATABASE=test2 -p 3306:3306 mariadb:10.3.30  --local-infile); sleep 4; podman exec -i $container mysql -e 'create database test1'
 
~/repos/PyMySQL mariadb-devel-ci
$ cp  ./ci/docker.json  ./pymysql/tests/databases.json
$ vi pymysql/tests/test_basic.py (remove version test)
$ pytest  -k TestCursor -v
=========================================================================== test session starts ===========================================================================
platform linux -- Python 3.9.6, pytest-6.2.2, py-1.10.0, pluggy-0.13.1 -- /home/dan/.py3/bin/python
cachedir: .pytest_cache
rootdir: /home/dan/repos/PyMySQL
collected 176 items / 172 deselected / 4 selected                                                                                                                         
 
pymysql/tests/test_basic.py::TestCursor::test_aggregates PASSED                                                                                                     [ 25%]
pymysql/tests/test_basic.py::TestCursor::test_fetch_no_result PASSED                                                                                                [ 50%]
pymysql/tests/test_basic.py::TestCursor::test_json FAILED                                                                                                           [ 75%]
pymysql/tests/test_basic.py::TestCursor::test_single_tuple PASSED                                                                                                   [100%]
 
================================================================================ FAILURES =================================================================================
__________________________________________________________________________ TestCursor.test_json ___________________________________________________________________________
 
self = <pymysql.tests.test_basic.TestCursor testMethod=test_json>
 
        def test_json(self):
            args = self.databases[0].copy()
            args["charset"] = "utf8mb4"
            conn = pymysql.connect(**args)
    
            self.safe_create_table(
                conn,
                "test_json",
                """\
    create table test_json (
        id int not null,
        json JSON not null,
        primary key (id)
    );""",
            )
            cur = conn.cursor()
    
            json_str = '{"hello": "こんにちは"}'
            cur.execute("INSERT INTO test_json (id, `json`) values (42, %s)", (json_str,))
            cur.execute("SELECT `json` from `test_json` WHERE `id`=42")
            res = cur.fetchone()[0]
            self.assertEqual(json.loads(res), json.loads(json_str))
    
>           cur.execute("SELECT CAST(%s AS JSON) AS x", (json_str,))
 
pymysql/tests/test_basic.py:307: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
pymysql/cursors.py:158: in execute
    result = self._query(query)
pymysql/cursors.py:325: in _query
    conn.query(q)
pymysql/connections.py:546: in query
    self._affected_rows = self._read_query_result(unbuffered=unbuffered)
pymysql/connections.py:775: in _read_query_result
    result.read()
pymysql/connections.py:1152: in read
    first_packet = self.connection._read_packet()
pymysql/connections.py:725: in _read_packet
    packet.raise_for_error()
pymysql/protocol.py:221: in raise_for_error
    err.raise_mysql_exception(self._data)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
 
data = b"\xff(\x04#42000You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'JSON) AS x' at line 1"
 
    def raise_mysql_exception(data):
        errno = struct.unpack("<h", data[1:3])[0]
        errval = data[9:].decode("utf-8", "replace")
        errorclass = error_map.get(errno)
        if errorclass is None:
            errorclass = InternalError if errno < 1000 else OperationalError
>       raise errorclass(errno, errval)
E       pymysql.err.ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'JSON) AS x' at line 1")
 
pymysql/err.py:143: ProgrammingError
========================================================================= short test summary info =========================================================================
FAILED pymysql/tests/test_basic.py::TestCursor::test_json - pymysql.err.ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that correspond...
=============================================================== 1 failed, 3 passed, 172 deselected in 0.39s ===============================================================

Comment by Daniel Black [ 2021-08-30 ]

by removing the mariadb version hack: https://github.com/grooverdan/PyMySQL/commit/fa11c45c5bb68657a731fc730b45299d61183977

Even 10.0.38 affected:

https://github.com/grooverdan/PyMySQL/runs/3459443038?check_suite_focus=true

Comment by Sergei Golubchik [ 2021-09-21 ]

You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'JSON) AS x

this is expected

Generated at Thu Feb 08 09:45:45 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.