Fix bug #78192 PDO SQLite SegFault when reuse statement after schema has changed

Reset stmt->columns when column count changed on new execution of prepared statement
This commit is contained in:
Vincent 2019-06-26 11:37:08 +02:00 committed by Christoph M. Becker
parent 7d28a24c66
commit 05c00a832c
3 changed files with 92 additions and 2 deletions

View file

@ -43,6 +43,46 @@ static int pdo_sqlite_stmt_dtor(pdo_stmt_t *stmt)
return 1;
}
/**
* Change the column count on the statement.
*
* Since PHP 7.2 sqlite3_prepare_v2 is used which auto recompile prepared statement on schema change.
* Instead of raise an error on schema change, the result set will change, and the statement's columns must be updated.
*
* See bug #78192
*/
static void pdo_sqlite_stmt_set_column_count(pdo_stmt_t *stmt, int new_count)
{
/* Columns not yet "described" */
if (!stmt->columns) {
stmt->column_count = new_count;
return;
}
/*
* The column count has not changed : no need to reload columns description
* Note: Do not handle attribute name change, without column count change
*/
if (new_count == stmt->column_count) {
return;
}
/* Free previous columns to force reload description */
int i;
for (i = 0; i < stmt->column_count; i++) {
if (stmt->columns[i].name) {
zend_string_release(stmt->columns[i].name);
stmt->columns[i].name = NULL;
}
}
efree(stmt->columns);
stmt->columns = NULL;
stmt->column_count = new_count;
}
static int pdo_sqlite_stmt_execute(pdo_stmt_t *stmt)
{
pdo_sqlite_stmt *S = (pdo_sqlite_stmt*)stmt->driver_data;
@ -55,11 +95,11 @@ static int pdo_sqlite_stmt_execute(pdo_stmt_t *stmt)
switch (sqlite3_step(S->stmt)) {
case SQLITE_ROW:
S->pre_fetched = 1;
stmt->column_count = sqlite3_data_count(S->stmt);
pdo_sqlite_stmt_set_column_count(stmt, sqlite3_data_count(S->stmt));
return 1;
case SQLITE_DONE:
stmt->column_count = sqlite3_column_count(S->stmt);
pdo_sqlite_stmt_set_column_count(stmt, sqlite3_column_count(S->stmt));
stmt->row_count = sqlite3_changes(S->H->db);
sqlite3_reset(S->stmt);
S->done = 1;