int QueryThread::run() { // Note: The m_abort flag does not actually abort, after the mysql_query function: // MySql documentation states: // "When using mysql_use_result(), you must execute mysql_fetch_row() until // a NULL value is returned, otherwise, the unfetched rows are returned as // part of the result set for your next query. The C API gives the error Commands // out of sync; you can't run this command now if you forget to do this!" // In otherwords: once we've started, we can't stop. So what we actually do is run the // query in full, and just not post any events if this flag is set. MYSQL* sql = 0; { MutexLocker lock(m_resultInfo); m_columns.clear(); m_columnType.clear(); } if (checkAbort()) { MutexLocker lock(m_resultInfo); m_abort = false; postEvent(QUERY_ABORTED); return 0; } sql = m_database->lockHandle(); if (mysql_query(sql, m_query.c_str()) != 0) { MutexLocker lock(m_resultInfo); m_error = true; m_errorText = mysql_error(sql); postEvent( QUERY_ERROR ); m_database->unlockHandle(); return 0; } MYSQL_RES* pResult = mysql_use_result(sql); if (!pResult) { if (checkAbort()) { m_database->unlockHandle(); return 0; } if(mysql_errno(sql)) { MutexLocker lock(m_resultInfo); m_error = true; m_errorText = mysql_error(sql); postEvent( QUERY_ERROR ); } else { MutexLocker lock(m_resultInfo); m_error = false; m_lastInsert = mysql_insert_id(sql); m_affectedRows = mysql_affected_rows(sql); postEvent( QUERY_SUCCESS_NO_DATA ); } m_database->unlockHandle(); return 0; } int numColumns = mysql_num_fields(pResult); { { MutexLocker lock(m_resultInfo); for(int i = 0; i < numColumns; i++) { MYSQL_FIELD* field = mysql_fetch_field_direct(pResult, i); if (field && field->name && strlen(field->name)) { m_columns.push_back( std::string(field->name) ); if (field->type == MYSQL_TYPE_TINY || field->type == MYSQL_TYPE_SHORT || field->type == MYSQL_TYPE_LONG || field->type == MYSQL_TYPE_LONG) m_columnType.push_back( INTEGER ); else if (field->type == MYSQL_TYPE_FLOAT || field->type == MYSQL_TYPE_DOUBLE) m_columnType.push_back( FLOATING_POINT ); else m_columnType.push_back( STRING ); } else { std::stringstream col; col << (i+1); m_columns.push_back( col.str() ); m_columnType.push_back( STRING ); } } } if (!checkAbort()) postEvent( QUERY_COLUMNS ); } MYSQL_ROW CurrentRow = mysql_fetch_row(pResult); while (CurrentRow) { if (checkAbort()) { CurrentRow = mysql_fetch_row(pResult); continue; } DataRow* row = new DataRow; for(int i = 0; i < numColumns; i++) { if (CurrentRow[i]) { row->push_back( new std::string( CurrentRow[i] ) ); } else { row->push_back( 0 ); } } postEvent( QUERY_DATA, row ); CurrentRow = mysql_fetch_row(pResult); } if(mysql_errno(sql)) { { MutexLocker lock(m_resultInfo); m_error = true; m_errorText = mysql_error(sql); } if (!checkAbort()) postEvent( QUERY_ERROR ); else { postEvent( QUERY_ABORTED ); MutexLocker lock(m_resultInfo); m_abort = false; } } else { { MutexLocker lock(m_resultInfo); m_error = false; m_lastInsert = mysql_insert_id(sql); m_affectedRows = mysql_affected_rows(sql); } if (!checkAbort()) postEvent( QUERY_SUCCESS ); else { postEvent( QUERY_ABORTED ); MutexLocker lock(m_resultInfo); m_abort = false; } } m_database->unlockHandle(); mysql_free_result(pResult); return 0; }