Skip to content

Commit 8cd33d5

Browse files
committed
Fixed memory leak in parser
1 parent cb0c3c8 commit 8cd33d5

File tree

6 files changed

+52
-43
lines changed

6 files changed

+52
-43
lines changed

doc/source/module.rst

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ The mariadb module supports the standard defined by DB API 2.0 (PEP-249).
1616
Establishes a connection to a database server and returns a new connection
1717
object.
1818

19-
:parameters:
19+
Parameters:
2020

2121
.. versionadded:: 1.1.0
2222

@@ -53,9 +53,11 @@ The mariadb module supports the standard defined by DB API 2.0 (PEP-249).
5353
- **ssl_crlpath** (string): Defines a path to a PEM file that should contain one or more revoked X509 certificates to use for TLS. This option requires that you use the absolute path, not a relative path.
5454
- **ssl_verify_cert** (bool): Enables server certificate verification.
5555
- **ssl** (bool): Always use a secure TLS connection
56-
.. versionadded:: 1.0.1
56+
.. versionadded:: 1.0.1
57+
5758
- **autocommit** (bool or None): Specifies the autocommit settings: None will use the server default. True will enable autocommit, False will disable it (default).
5859
.. versionadded:: 1.0.3
60+
5961
- **converter** (dict): Specifies a conversion dictionary, where keys are FIELD_TYPE values and values are conversion functions.
6062

6163
:return: Returns a connection object or raises an error if the connection between client and server couldn't be established.

docs/_sources/module.rst.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ The mariadb module supports the standard defined by DB API 2.0 (PEP-249).
1616
Establishes a connection to a database server and returns a new connection
1717
object.
1818

19-
:parameters:
19+
Parameters:
2020

2121
.. versionadded:: 1.1.0
2222

@@ -53,9 +53,11 @@ The mariadb module supports the standard defined by DB API 2.0 (PEP-249).
5353
- **ssl_crlpath** (string): Defines a path to a PEM file that should contain one or more revoked X509 certificates to use for TLS. This option requires that you use the absolute path, not a relative path.
5454
- **ssl_verify_cert** (bool): Enables server certificate verification.
5555
- **ssl** (bool): Always use a secure TLS connection
56-
.. versionadded:: 1.0.1
56+
.. versionadded:: 1.0.1
57+
5758
- **autocommit** (bool or None): Specifies the autocommit settings: None will use the server default. True will enable autocommit, False will disable it (default).
5859
.. versionadded:: 1.0.3
60+
5961
- **converter** (dict): Specifies a conversion dictionary, where keys are FIELD_TYPE values and values are conversion functions.
6062

6163
:return: Returns a connection object or raises an error if the connection between client and server couldn't be established.

docs/module.html

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,9 @@ <h3>Navigation</h3>
5252
<span class="sig-prename descclassname"><span class="pre">mariadb.</span></span><span class="sig-name descname"><span class="pre">connect</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">cursorclass</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">mariadb.connections.Connection</span> <span class="pre">**</span> <span class="pre">kwargs</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#mariadb.connect" title="Permalink to this definition"></a></dt>
5353
<dd><p>Establishes a connection to a database server and returns a new connection
5454
object.</p>
55+
<p>Parameters:</p>
5556
</dd></dl>
5657

57-
<dl class="field-list simple">
58-
<dt class="field-odd">parameters</dt>
59-
<dd class="field-odd"><p></p></dd>
60-
</dl>
6158
<div class="versionadded">
6259
<p><span class="versionmodified added">New in version 1.1.0: </span></p>
6360
<ul class="simple">
@@ -102,10 +99,16 @@ <h3>Navigation</h3>
10299
</ul>
103100
</div>
104101
<div class="versionadded">
105-
<p><span class="versionmodified added">New in version 1.0.1: </span>- <strong>autocommit</strong> (bool or None): Specifies the autocommit settings: None will use the server default. True will enable autocommit, False will disable it (default).</p>
102+
<p><span class="versionmodified added">New in version 1.0.1: </span></p>
103+
<ul class="simple">
104+
<li><p><strong>autocommit</strong> (bool or None): Specifies the autocommit settings: None will use the server default. True will enable autocommit, False will disable it (default).</p></li>
105+
</ul>
106106
</div>
107107
<div class="versionadded">
108-
<p><span class="versionmodified added">New in version 1.0.3: </span>- <strong>converter</strong> (dict): Specifies a conversion dictionary, where keys are FIELD_TYPE values and values are conversion functions.</p>
108+
<p><span class="versionmodified added">New in version 1.0.3: </span></p>
109+
<ul class="simple">
110+
<li><p><strong>converter</strong> (dict): Specifies a conversion dictionary, where keys are FIELD_TYPE values and values are conversion functions.</p></li>
111+
</ul>
109112
<dl class="field-list simple">
110113
<dt class="field-odd">return</dt>
111114
<dd class="field-odd"><p>Returns a connection object or raises an error if the connection between client and server couldn’t be established.</p>

mariadb/cursors.py

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -99,30 +99,31 @@ def _substitute_parameters(self):
9999

100100
new_stmt= self.statement
101101
replace_diff= 0
102-
for i in range (0,len(self._paramlist)):
103-
if self._paramstyle == PARAMSTYLE_PYFORMAT:
104-
val= self._data[self._keys[i]]
105-
else:
106-
val= self._data[i]
107-
if val is None:
108-
replace= "NULL";
109-
else:
110-
if isinstance(val, INDICATOR.MrdbIndicator):
111-
if val == INDICATOR.NULL:
112-
replace= "NULL"
113-
if val == INDICATOR.DEFAULT:
114-
replace= "DEFAULT"
115-
elif isinstance(val, Number):
116-
replace= val.__str__()
102+
if self._paramlist:
103+
for i in range (0,len(self._paramlist)):
104+
if self._paramstyle == PARAMSTYLE_PYFORMAT:
105+
val= self._data[self._keys[i]]
106+
else:
107+
val= self._data[i]
108+
if val is None:
109+
replace= "NULL";
117110
else:
118-
if isinstance(val, (bytes, bytearray)):
119-
replace= "\"%s\"" % self.connection.escape_string(val.decode(encoding='latin1'))
111+
if isinstance(val, INDICATOR.MrdbIndicator):
112+
if val == INDICATOR.NULL:
113+
replace= "NULL"
114+
if val == INDICATOR.DEFAULT:
115+
replace= "DEFAULT"
116+
elif isinstance(val, Number):
117+
replace= val.__str__()
120118
else:
121-
replace= "\"%s\"" % self.connection.escape_string(val.__str__())
122-
ofs= self._paramlist[i] + replace_diff
123-
124-
new_stmt= new_stmt[:ofs] + replace.__str__() + new_stmt[ofs+1:]
125-
replace_diff+= len(replace) - 1
119+
if isinstance(val, (bytes, bytearray)):
120+
replace= "\"%s\"" % self.connection.escape_string(val.decode(encoding='latin1'))
121+
else:
122+
replace= "\"%s\"" % self.connection.escape_string(val.__str__())
123+
ofs= self._paramlist[i] + replace_diff
124+
125+
new_stmt= new_stmt[:ofs] + replace.__str__() + new_stmt[ofs+1:]
126+
replace_diff+= len(replace) - 1
126127
return new_stmt
127128

128129
def _check_execute_params(self):
@@ -138,8 +139,8 @@ def _check_execute_params(self):
138139

139140
# check if number of place holders matches the number of
140141
# supplied elements in data tuple
141-
if (not self._data and len(self._paramlist) > 0) or \
142-
(len(self._data) != len(self._paramlist)):
142+
if self._paramlist and ((not self._data and len(self._paramlist) > 0) or \
143+
(len(self._data) != len(self._paramlist))):
143144
raise mariadb.DataError("Number of parameters in statement (%s)"\
144145
" doesn't match the number of data elements (%s)."\
145146
% (len(self._paramlist), len(self._data)))
@@ -342,7 +343,6 @@ def close(self):
342343
The cursor will be unusable from this point forward; an Error (or subclass)
343344
exception will be raised if any operation is attempted with the cursor."
344345
"""
345-
346346
super().close()
347347

348348
def fetchone(self):
@@ -462,7 +462,6 @@ def __enter__(self):
462462

463463
def __exit__(self, exc_type, exc_val, exc_tb):
464464
"""Closes cursor."""
465-
466465
self.close()
467466

468467
def __del__(self):

mariadb/mariadb_cursor.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,8 @@ void MrdbCursor_clearparseinfo(MrdbParseInfo *parseinfo)
391391
if (parseinfo->statement)
392392
MARIADB_FREE_MEM(parseinfo->statement);
393393
Py_XDECREF(parseinfo->keys);
394+
if (parseinfo->paramlist)
395+
Py_XDECREF(parseinfo->paramlist);
394396
memset(parseinfo, 0, sizeof(MrdbParseInfo));
395397
}
396398

@@ -467,8 +469,7 @@ void MrdbCursor_clear(MrdbCursor *self, uint8_t new_stmt)
467469
self->fields= NULL;
468470
self->row_count= 0;
469471
self->affected_rows= 0;
470-
MARIADB_FREE_MEM(self->parseinfo.statement);
471-
memset(&self->parseinfo, 0, sizeof(MrdbParseInfo));
472+
MrdbCursor_clearparseinfo(&self->parseinfo);
472473
MARIADB_FREE_MEM(self->values);
473474
MARIADB_FREE_MEM(self->bind);
474475
MARIADB_FREE_MEM(self->statement);
@@ -520,8 +521,7 @@ void ma_cursor_close(MrdbCursor *self)
520521
self->stmt= NULL;
521522
}
522523

523-
MARIADB_FREE_MEM(self->parseinfo.statement);
524-
524+
MrdbCursor_clearparseinfo(&self->parseinfo);
525525
self->is_closed= 1;
526526
}
527527
}
@@ -822,10 +822,12 @@ static PyObject *MrdbCursor_seek(MrdbCursor *self, PyObject *args)
822822
{
823823
return NULL;
824824
}
825+
Py_BEGIN_ALLOW_THREADS;
825826
if (self->parseinfo.is_text)
826827
mysql_data_seek(self->result, new_position);
827828
else
828829
mysql_stmt_data_seek(self->stmt, new_position);
830+
Py_END_ALLOW_THREADS;
829831

830832
Py_RETURN_NONE;
831833
}
@@ -899,8 +901,7 @@ Mariadb_row_count(MrdbCursor *self)
899901
static PyObject *
900902
Mariadb_row_number(MrdbCursor *self)
901903
{
902-
unsigned int field_count= self->field_count;
903-
if (!field_count) {
904+
if (!self->field_count) {
904905
Py_RETURN_NONE;
905906
}
906907
return PyLong_FromLongLong(self->row_number);
@@ -989,6 +990,7 @@ MrdbCursor_parse(MrdbCursor *self, PyObject *args)
989990
memcpy(self->parseinfo.statement, parser->statement.str, parser->statement.length);
990991
self->parseinfo.statement_len= parser->statement.length;
991992
self->parseinfo.paramlist= parser->param_list;
993+
parser->param_list= NULL;
992994
self->parseinfo.is_text= (parser->command == SQL_NONE || parser->command == SQL_OTHER);
993995
self->parseinfo.command= parser->command;
994996

@@ -1000,6 +1002,7 @@ MrdbCursor_parse(MrdbCursor *self, PyObject *args)
10001002
PyObject *key;
10011003
key= PyUnicode_FromString(parser->keys[i].str);
10021004
PyTuple_SetItem(tmp, i, key);
1005+
Py_DECREF(key);
10031006
}
10041007
self->parseinfo.keys= tmp;
10051008
}

mariadb/mariadb_parser.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,9 @@ MrdbParser_init(MYSQL *mysql, const char *statement, size_t length)
106106
memcpy(p->statement.str, statement, length);
107107
p->statement.length= length;
108108
p->mysql= mysql;
109-
p->param_list= PyList_New(0);
110109
p->param_count= 0;
111110
}
111+
p->param_list= PyList_New(0);
112112
return p;
113113
}
114114

0 commit comments

Comments
 (0)