mirror of
https://github.com/php/php-src.git
synced 2025-08-16 14:08:47 +02:00
PDO MySQL: Fix leak with libmysqlclient and multiple rowsets
stmt->column_count gets reset before the next_rowset handler is invoked, so we need to fetch the value from the result set instead. Arguably PDO should be separating the destruction of the previous result set and the switch to the next result set more cleanly...
This commit is contained in:
parent
54a63d91b8
commit
c927c831e6
1 changed files with 29 additions and 46 deletions
|
@ -30,13 +30,34 @@
|
|||
|
||||
#ifdef PDO_USE_MYSQLND
|
||||
# define pdo_mysql_stmt_execute_prepared(stmt) pdo_mysql_stmt_execute_prepared_mysqlnd(stmt)
|
||||
# define pdo_free_bound_result(res) zval_ptr_dtor(res.zv)
|
||||
#else
|
||||
# define pdo_mysql_stmt_execute_prepared(stmt) pdo_mysql_stmt_execute_prepared_libmysql(stmt)
|
||||
# define pdo_free_bound_result(res) efree(res.buffer)
|
||||
#endif
|
||||
|
||||
|
||||
static void pdo_mysql_free_result(pdo_mysql_stmt *S)
|
||||
{
|
||||
if (S->result) {
|
||||
#ifndef PDO_USE_MYSQLND
|
||||
if (S->bound_result) {
|
||||
/* We can't use stmt->column_count here, because it gets reset before the
|
||||
* next_rowset handler is called. */
|
||||
unsigned column_count = mysql_num_fields(S->result);
|
||||
for (unsigned i = 0; i < column_count; i++) {
|
||||
efree(S->bound_result[i].buffer);
|
||||
}
|
||||
|
||||
efree(S->bound_result);
|
||||
efree(S->out_null);
|
||||
efree(S->out_length);
|
||||
S->bound_result = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
mysql_free_result(S->result);
|
||||
S->result = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int pdo_mysql_stmt_dtor(pdo_stmt_t *stmt) /* {{{ */
|
||||
{
|
||||
|
@ -44,11 +65,8 @@ static int pdo_mysql_stmt_dtor(pdo_stmt_t *stmt) /* {{{ */
|
|||
|
||||
PDO_DBG_ENTER("pdo_mysql_stmt_dtor");
|
||||
PDO_DBG_INF_FMT("stmt=%p", S->stmt);
|
||||
if (S->result) {
|
||||
/* free the resource */
|
||||
mysql_free_result(S->result);
|
||||
S->result = NULL;
|
||||
}
|
||||
|
||||
pdo_mysql_free_result(S);
|
||||
if (S->einfo.errmsg) {
|
||||
pefree(S->einfo.errmsg, stmt->dbh->is_persistent);
|
||||
S->einfo.errmsg = NULL;
|
||||
|
@ -68,18 +86,6 @@ static int pdo_mysql_stmt_dtor(pdo_stmt_t *stmt) /* {{{ */
|
|||
if (S->in_length) {
|
||||
efree(S->in_length);
|
||||
}
|
||||
|
||||
if (S->bound_result)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < stmt->column_count; i++) {
|
||||
pdo_free_bound_result(S->bound_result[i]);
|
||||
}
|
||||
|
||||
efree(S->bound_result);
|
||||
efree(S->out_null);
|
||||
efree(S->out_length);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!S->done && !Z_ISUNDEF(stmt->database_object_handle)
|
||||
|
@ -209,15 +215,6 @@ static int pdo_mysql_stmt_execute_prepared_libmysql(pdo_stmt_t *stmt) /* {{{ */
|
|||
if (S->result) {
|
||||
int calc_max_length = H->buffered && S->max_length == 1;
|
||||
S->fields = mysql_fetch_fields(S->result);
|
||||
if (S->bound_result) {
|
||||
int i;
|
||||
for (i = 0; i < stmt->column_count; i++) {
|
||||
efree(S->bound_result[i].buffer);
|
||||
}
|
||||
efree(S->bound_result);
|
||||
efree(S->out_null);
|
||||
efree(S->out_length);
|
||||
}
|
||||
|
||||
php_pdo_stmt_set_column_count(stmt, (int)mysql_num_fields(S->result));
|
||||
S->bound_result = ecalloc(stmt->column_count, sizeof(MYSQL_BIND));
|
||||
|
@ -306,12 +303,7 @@ static int pdo_mysql_stmt_execute_prepared_mysqlnd(pdo_stmt_t *stmt) /* {{{ */
|
|||
PDO_DBG_RETURN(0);
|
||||
}
|
||||
|
||||
if (S->result) {
|
||||
/* TODO: add a test to check if we really have zvals here... */
|
||||
mysql_free_result(S->result);
|
||||
S->result = NULL;
|
||||
}
|
||||
|
||||
pdo_mysql_free_result(S);
|
||||
PDO_DBG_RETURN(pdo_mysql_stmt_after_execute_prepared(stmt));
|
||||
}
|
||||
/* }}} */
|
||||
|
@ -330,10 +322,7 @@ static int pdo_mysql_stmt_execute(pdo_stmt_t *stmt) /* {{{ */
|
|||
}
|
||||
|
||||
/* ensure that we free any previous unfetched results */
|
||||
if (S->result) {
|
||||
mysql_free_result(S->result);
|
||||
S->result = NULL;
|
||||
}
|
||||
pdo_mysql_free_result(S);
|
||||
|
||||
if (mysql_real_query(H->server, stmt->active_query_string, stmt->active_query_stringlen) != 0) {
|
||||
pdo_mysql_error_stmt(stmt);
|
||||
|
@ -355,10 +344,7 @@ static int pdo_mysql_stmt_next_rowset(pdo_stmt_t *stmt) /* {{{ */
|
|||
if (S->stmt) {
|
||||
mysql_stmt_free_result(S->stmt);
|
||||
}
|
||||
if (S->result) {
|
||||
mysql_free_result(S->result);
|
||||
S->result = NULL;
|
||||
}
|
||||
pdo_mysql_free_result(S);
|
||||
|
||||
#ifdef PDO_USE_MYSQLND
|
||||
if (S->stmt) {
|
||||
|
@ -845,10 +831,7 @@ static int pdo_mysql_stmt_cursor_closer(pdo_stmt_t *stmt) /* {{{ */
|
|||
PDO_DBG_INF_FMT("stmt=%p", S->stmt);
|
||||
|
||||
S->done = 1;
|
||||
if (S->result) {
|
||||
mysql_free_result(S->result);
|
||||
S->result = NULL;
|
||||
}
|
||||
pdo_mysql_free_result(S);
|
||||
if (S->stmt) {
|
||||
mysql_stmt_free_result(S->stmt);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue