Thanks to visit codestin.com
Credit goes to github.com

Skip to content

SSCursor does not handle timeouts properly #1032

Closed
@Nothing4You

Description

@Nothing4You

Describe the bug
There's various cases where timeouts during queries can lead to surprising results.

To Reproduce
I'm currently working on tests cases for them and which outcomes I can observe.

Schema:

CREATE TABLE tbl (
id MEDIUMINT NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
PRIMARY KEY (id));

INSERT INTO tbl VALUES(1, 'a')
INSERT INTO tbl VALUES(2, 'b')
INSERT INTO tbl VALUES(3, 'c')

Code:

with connection.cursor(cursor=pymysql.cursors.SSCursor) as cur:
    sql = "SELECT /*+ MAX_EXECUTION_TIME(1) */ *,sleep(1) FROM tbl WHERE name='a'"
    cur.execute(sql)
    cur.fetchone()

This can lead to a ProgrammingError, I suspect it's this happens when the query is not cached.
I cannot reliably reproduce it yet, restarting the DB increases chance for this to happen, after the first query it won't happen for most attempts.

Traceback (most recent call last):
  File ".../PyMySQL/pmtest.py", line 72, in <module>
    r = cur.fetchone()
  File ".../PyMySQL/pymysql/cursors.py", line 442, in fetchone
    self._check_executed()
  File ".../PyMySQL/pymysql/cursors.py", line 70, in _check_executed
    raise err.ProgrammingError("execute() first")
pymysql.err.ProgrammingError: execute() first
debug output
packet length: 7
call[1]: _read_packet (line 717)
call[2]: _roundtrip (line 120)
call[3]: caching_sha2_password_auth (line 266)
call[4]: _request_authentication (line 933)
call[5]: connect (line 636)
call[6]: __init__ (line 352)
------------------------------------------------------------------
00 00 00 02 00 00 00                             .......
------------------------------------------------------------------

Succeed to auth
packet length: 23
call[1]: _execute_command (line 820)
call[2]: _send_autocommit_mode (line 454)
call[3]: autocommit (line 436)
call[4]: connect (line 649)
call[5]: __init__ (line 352)
call[6]: <module> (line 7)
------------------------------------------------------------------
13 00 00 00 03 53 45 54 20 41 55 54 4F 43 4F 4D  .....SET AUTOCOM
4D 49 54 20 3D 20 30                             MIT = 0
------------------------------------------------------------------

packet length: 7
call[1]: _read_packet (line 717)
call[2]: _read_ok_packet (line 442)
call[3]: _send_autocommit_mode (line 457)
call[4]: autocommit (line 436)
call[5]: connect (line 649)
call[6]: __init__ (line 352)
------------------------------------------------------------------
00 00 00 00 00 00 00                             .......
------------------------------------------------------------------

packet length: 75
call[1]: _execute_command (line 820)
call[2]: query (line 548)
call[3]: _query (line 429)
call[4]: execute (line 158)
call[5]: <module> (line 63)
47 00 00 00 03 53 45 4C 45 43 54 20 2F 2A 2B 20  G....SELECT /*+
4D 41 58 5F 45 58 45 43 55 54 49 4F 4E 5F 54 49  MAX_EXECUTION_TI
4D 45 28 31 29 20 2A 2F 20 2A 2C 73 6C 65 65 70  ME(1) */ *,sleep
28 31 29 20 46 52 4F 4D 20 74 62 6C 20 57 48 45  (1) FROM tbl WHE
52 45 20 6E 61 6D 65 3D 27 62 27                 RE name='b'
------------------------------------------------------------------

packet length: 83
call[1]: _read_packet (line 717)
call[2]: init_unbuffered_query (line 1174)
call[3]: _read_query_result (line 772)
call[4]: query (line 549)
call[5]: _query (line 429)
call[6]: execute (line 158)
------------------------------------------------------------------
FF D0 0B 23 48 59 30 30 30 51 75 65 72 79 20 65  ...#HY000Query e
78 65 63 75 74 69 6F 6E 20 77 61 73 20 69 6E 74  xecution was int
65 72 72 75 70 74 65 64 2C 20 6D 61 78 69 6D 75  errupted, maximu
6D 20 73 74 61 74 65 6D 65 6E 74 20 65 78 65 63  m statement exec
75 74 69 6F 6E 20 74 69 6D 65 20 65 78 63 65 65  ution time excee
64 65 64                                         ded
------------------------------------------------------------------

fetching row 0
Traceback (most recent call last):
  File ".../PyMySQL/pmtest.py", line 72, in <module>
    r = cur.fetchone()
  File ".../PyMySQL/pymysql/cursors.py", line 442, in fetchone
    self._check_executed()
  File ".../PyMySQL/pymysql/cursors.py", line 70, in _check_executed
    raise err.ProgrammingError("execute() first")
pymysql.err.ProgrammingError: execute() first

This is just one of the problematic test cases, there's several more issues.
I'll add more info in additional comments.

Expected behavior
Query success or OperationalError.

Environment

  • OS: macOS 12
  • Server and version: MySQL 8.0.28 Homebrew
  • PyMySQL version: 3fb9dd9

Additional context
More to come...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions