Skip to content

Commit df2b54a

Browse files
committed
BUG#30203754: PREPARED STMT FAILS ON CEXT with BIGINTS
BUG#33481203: OverflowError for MySQL BIGINT on c-ext On Windows PyLong_FromLong() raises overflowerror when value is over 2147483647, this patch changes the use of a long for long long to fully support BIGINTS on windows platform.
1 parent ae5b9b6 commit df2b54a

File tree

4 files changed

+63
-25
lines changed

4 files changed

+63
-25
lines changed

CHANGES.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ v8.0.29
1919
- BUG#33861549: Replace SHOW VARIABLES inefficient statements
2020
- BUG#33747585: Fix error when using an expression as a column without an alias
2121
- BUG#33729842: Character set 'utf8mb3' support
22+
- BUG#33481203: OverflowError for MySQL BIGINT on c-ext
23+
- BUG#30203754: Prepared stmt fails on cext with BIGINTS
2224
- BUG#28877987: Return bytes or bytearray if decoding fails
2325
- BUG#27634914: Remove mention of unsupported functionality in Session docstring
2426
- BUG#23338623: Add support for Decimal parsing in protocol.py

src/include/mysql_capi.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2014, 2021, Oracle and/or its affiliates.
2+
* Copyright (c) 2014, 2022, Oracle and/or its affiliates.
33
*
44
* This program is free software; you can redistribute it and/or modify
55
* it under the terms of the GNU General Public License, version 2.0, as
@@ -248,7 +248,7 @@ MySQL_create_prep_stmt(MySQL *self);
248248
struct MySQL_binding {
249249
PyObject *str_value;
250250
union {
251-
long l;
251+
long long l;
252252
float f;
253253
MYSQL_TIME t;
254254
} buffer;
@@ -259,7 +259,7 @@ struct column_info {
259259
bool_ is_error;
260260
unsigned long length;
261261
union {
262-
long l;
262+
long long l;
263263
float f;
264264
double d;
265265
} small_buffer;

src/mysql_capi.c

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2193,15 +2193,11 @@ MySQL_query(MySQL *self, PyObject *args, PyObject *kwds)
21932193
continue;
21942194
}
21952195

2196-
/* LONG */
2196+
/* LONG AND LONGLONG */
21972197
if (PyLong_Check(value)) {
2198-
pbind->buffer.l = PyLong_AsLong(value);
2198+
pbind->buffer.l = PyLong_AsLongLong(value);
21992199
mbind->buffer = &pbind->buffer.l;
2200-
#if LONG_MAX >= INT64_T_MAX
22012200
mbind->buffer_type = MYSQL_TYPE_LONGLONG;
2202-
#else
2203-
mbind->buffer_type = MYSQL_TYPE_LONG;
2204-
#endif
22052201
mbind->is_null = (bool_ *) 0;
22062202
if (mbind->length) {
22072203
*mbind->length = sizeof(mbind->buffer_type);
@@ -3397,16 +3393,12 @@ MySQLPrepStmt_execute(MySQLPrepStmt *self, PyObject *args)
33973393
continue;
33983394
}
33993395

3400-
/* LONG */
3396+
/* LONG AND LONGLONG*/
34013397
if (PyLong_Check(value))
34023398
{
3403-
pbind->buffer.l= PyLong_AsLong(value);
3399+
pbind->buffer.l= PyLong_AsLongLong(value);
34043400
mbind->buffer= &pbind->buffer.l;
3405-
#if LONG_MAX >= INT64_T_MAX
34063401
mbind->buffer_type= MYSQL_TYPE_LONGLONG;
3407-
#else
3408-
mbind->buffer_type= MYSQL_TYPE_LONG;
3409-
#endif
34103402
mbind->is_null= (bool_ *)0;
34113403
mbind->length= 0;
34123404
continue;
@@ -3672,17 +3664,13 @@ MySQLPrepStmt_handle_result(MySQLPrepStmt *self)
36723664
break;
36733665
case MYSQL_TYPE_TINY:
36743666
case MYSQL_TYPE_SHORT:
3675-
case MYSQL_TYPE_LONG:
36763667
case MYSQL_TYPE_INT24:
36773668
case MYSQL_TYPE_YEAR:
3678-
#if LONG_MAX >= INT64_T_MAX
3669+
case MYSQL_TYPE_LONG:
36793670
case MYSQL_TYPE_LONGLONG:
36803671
self->bind[i].buffer_type= MYSQL_TYPE_LONGLONG;
3681-
#else
3682-
self->bind[i].buffer_type= MYSQL_TYPE_LONG;
3683-
#endif
36843672
self->bind[i].buffer= &self->cols[i].small_buffer.l;
3685-
self->bind[i].buffer_length= sizeof(long);
3673+
self->bind[i].buffer_length= sizeof(long long);
36863674
break;
36873675
case MYSQL_TYPE_FLOAT:
36883676
self->bind[i].buffer_type= MYSQL_TYPE_FLOAT;
@@ -3717,7 +3705,6 @@ MySQLPrepStmt_handle_result(MySQLPrepStmt *self)
37173705

37183706
mysql_field_seek(self->res, 0);
37193707
self->fields= MySQLPrepStmt_fetch_fields(self);
3720-
37213708
Py_RETURN_TRUE;
37223709
}
37233710

@@ -3823,12 +3810,10 @@ MySQLPrepStmt_fetch_row(MySQLPrepStmt *self)
38233810
case MYSQL_TYPE_SHORT:
38243811
case MYSQL_TYPE_INT24:
38253812
case MYSQL_TYPE_LONG:
3826-
#if LONG_MAX >= INT64_T_MAX
38273813
case MYSQL_TYPE_LONGLONG:
3828-
#endif
38293814
case MYSQL_TYPE_YEAR:
38303815
PyTuple_SET_ITEM(
3831-
row, i, PyLong_FromLong(self->cols[i].small_buffer.l));
3816+
row, i, PyLong_FromLongLong(self->cols[i].small_buffer.l));
38323817
break;
38333818
case MYSQL_TYPE_FLOAT:
38343819
PyTuple_SET_ITEM(

tests/test_bugs.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6357,6 +6357,57 @@ def test_prepared_statement_parameters(self):
63576357
self.cnx.cmd_query(f"DROP TABLE IF EXISTS {self.table_name}")
63586358

63596359

6360+
class BugOra30203754(tests.MySQLConnectorTests):
6361+
"""BUG#30203754: PREPARED STMT FAILS ON CEXT with BIGINTS
6362+
6363+
BUG#33481203: OverflowError for MySQL BIGINT supported value
6364+
9223372036854775807 on c-ext prep
6365+
"""
6366+
6367+
table_name = "BugOra30203754"
6368+
6369+
@foreach_cnx()
6370+
def test_prepared_statement_bigints(self):
6371+
self.cnx.cmd_query(f"DROP TABLE IF EXISTS {self.table_name}")
6372+
self.cnx.cmd_query(
6373+
f"CREATE TABLE {self.table_name}"
6374+
" (indx INT key auto_increment, bigints BIGINT)"
6375+
)
6376+
test_cases = (
6377+
-9223372036854775808,
6378+
-9223372036854775807,
6379+
-922337203685477580,
6380+
-2147483648,
6381+
0,
6382+
2147483647,
6383+
2147483648,
6384+
922337203685477580,
6385+
9223372036854775806,
6386+
9223372036854775807,
6387+
)
6388+
6389+
prepared_options = [True, False]
6390+
for prepared in prepared_options:
6391+
with self.cnx.cursor(prepared=prepared) as cur:
6392+
for tc in test_cases:
6393+
query = f"select %s"
6394+
cur.execute(query, (tc,))
6395+
rows = cur.fetchall()
6396+
self.assertEqual(tc, rows[0][0])
6397+
6398+
for tc in test_cases:
6399+
query = f"INSERT INTO {self.table_name} (bigints) VALUES (%s)"
6400+
cur.execute(query, (tc,))
6401+
self.cnx.commit()
6402+
6403+
for index, tc in enumerate (test_cases):
6404+
query = f"SELECT bigints FROM {self.table_name} WHERE indx = '{index+1}'"
6405+
cur.execute(query)
6406+
rows = cur.fetchall()
6407+
self.assertEqual(tc, rows[0][0])
6408+
self.cnx.cmd_query(f"DROP TABLE IF EXISTS {self.table_name}")
6409+
6410+
63606411
class BugOra31528783(tests.MySQLConnectorTests):
63616412
"""BUG#31528783: ZEROFILL NOT HANDLED BY THE PYTHON CONNECTOR."""
63626413

0 commit comments

Comments
 (0)