Mysql Question: Commands out of sync

Keywords: MySQL Database

Recently, when using C++ to access MySQL (using the C API provided by mysql), an occasional error occurs:

Commands out of sync; you can't run this command now

Errors are explained in the Mysql document:

Commands out of sync
If you get "Commands out of sync; you can't run this command now" in your client code, you are calling client functions in the wrong order.
This can happen, for example, if you are using mysql_use_result() and try to execute a new query before you have called mysql_free_result(). It can also happen if you try to execute two queries that return data without calling mysql_use_result() or mysql_store_result() in between.

When query is executed, mysql places the result set in a result set. There are two reasons for the above problems:
First, a new query is executed before releasing the object referred to by MYSQL_RES (using mysql_free_result()).
The second is to execute two queries that return results without calling mysql_use_result() or mysql_store_result() to extract the result set.

MySQL communicates with the client using a "half-duplex" reply protocol. For each query sent by the client, the server "forcibly pushes" the result to the client. The client needs to execute mysql_use_result() or mysql_store_result() to retrieve the result from the server. This is a complete query interaction. Only submitting the query without retrieving the result will lead to Commands out of sync. .

Therefore, for query statements with returned results, the following processing is required:

TC_Mysql::MysqlData TC_Mysql::queryRecord(const string& sSql)
{
    MysqlData   data;

    /**
    Not connected, connected to the database
    */
    if(!_bConnected)
    {
        connect();
    }

    _sLastSql = sSql;

    int iRet = mysql_real_query(_pstMql, sSql.c_str(), sSql.length());
    if(iRet != 0)
    {
        /**
        Automatic reconnection
        */
        int iErrno = mysql_errno(_pstMql);
        if (iErrno == 2013 || iErrno == 2006)
        {
            connect();
            iRet = mysql_real_query(_pstMql, sSql.c_str(), sSql.length());
        }
    }

    if (iRet != 0)
    {
        throw TC_Mysql_Exception("[TC_Mysql::execute]: mysql_query: [ " + sSql+" ] :" + string(mysql_error(_pstMql)));  
    }

    // Save the result set
    MYSQL_RES *pstRes = mysql_store_result(_pstMql);

    if(pstRes == NULL)
    {
        throw TC_Mysql_Exception("[TC_Mysql::queryRecord]: mysql_store_result: " + sSql + " : " + string(mysql_error(_pstMql)));
    }

    vector<string> vtFields;
    MYSQL_FIELD *field;
    while((field = mysql_fetch_field(pstRes)))
    {
         vtFields.push_back(field->name);
    }

    map<string, string> mpRow;
    MYSQL_ROW stRow;

    while((stRow = mysql_fetch_row(pstRes)) != (MYSQL_ROW)NULL)
    {
        mpRow.clear();
        unsigned long * lengths = mysql_fetch_lengths(pstRes);
        for(size_t i = 0; i < vtFields.size(); i++)
        {
            if(stRow[i])
            {
                mpRow[vtFields[i]] = string(stRow[i], lengths[i]);
            }
            else
            {
                mpRow[vtFields[i]] = "";
            }
        }

        data.data().push_back(mpRow);
    }

    // Release result set
    mysql_free_result(pstRes);

    return data;
}

For queries that do not need to return results, the number of records affected by the query is obtained by mysql_affected_rows(_pstMql).

For multi-threaded cases, ensure that each thread accesses the database using a separate Mysql. Otherwise, thread 1 may not save the result set, and thread 2 will initiate a new query, which will result in a Commands out of sync error.

Posted by MK27 on Sat, 15 Dec 2018 10:21:03 -0800