Bug #20087 C API: mysql_stmt_execute crash if called when the server is down
Submitted: 26 May 2006 7:40 Modified: 26 Jun 2006 15:39
Reporter: David Lombardi Email Updates:
Status: No Feedback Impact on me:
None 
Category:MySQL Server Severity:S1 (Critical)
Version:5.0.21 OS:Windows (Windows XP SP2)
Assigned to: MySQL Verification Team CPU Architecture:Any

[26 May 2006 7:40] David Lombardi
Description:
Calling mysql_stmt_execute may generate an Access Violation when called after the MySQL server has been shutdown or terminated (i.e. to simulate a server crash).

The prepared statement is a INSERT into a table.

MySQL server and client library version 5.0.21.
DLL version of the client library
Dev Env: Borland C++ Builder 6.0 Upd Pack 4.

How to repeat:
Have the server up and running and have the client app connect to the server and prepare an INSERT statement.
The connection is set with the OPT_RECONNECT.

While the app is executing the prepared statement (in a loop), shutdown the server.

The statement execution during fails in a controlled manner, the second or third execution of mysql_stmt_execute triggers an access violation exception.

Similar outcomes if the server is killed: the difference is that the first execution reports a failure condition of "Lost connection..." instead of "shutdown in progress".

NOTE: With SELECT statements, I never experienced an access violation (I do not have UPDATEs statements).
[26 May 2006 15:39] MySQL Verification Team
Thank you for the bug report. Could you please provide the C/C++ test
case code and table definition and data insert if needed.
Thanks in advance.
[26 Jun 2006 23:00] Bugs System
No feedback was provided for this bug for over a month, so it is
being suspended automatically. If you are able to provide the
information that was originally requested, please do so and change
the status of the bug back to "Open".
[21 Jun 2008 15:10] Roman Bobrov
I've got the same bug with version 5.0.51b (both server and client) on Windows XP SP2.
The complete project (Microsoft Visual Studio 6.0) to reproduce it is uploaded to FTP as bug-data-20087.zip
Here is the listing of main function:

extern "C" int WINAPI _tWinMain(HINSTANCE hInstance, 
    HINSTANCE /*hPrevInstance*/, LPTSTR lpCmdLine, int /*nShowCmd*/)
{
  lpCmdLine = GetCommandLine(); //this line necessary for _ATL_MIN_CRT

  HRESULT hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  _Module.Init(NULL, hInstance);

  PCSTR pcszError = NULL;
  MYSQL* pInitConn = ::mysql_init(NULL);
  if (pInitConn != NULL)
  {
    // connect to localhost using anonymous account
    // InnoDB is used by default
    my_bool fTrue = true;
    ::mysql_options(pInitConn,MYSQL_OPT_RECONNECT,(PCSTR)&fTrue);
    DWORD dwProtocol = MYSQL_PROTOCOL_TCP;
    ::mysql_options(pInitConn,MYSQL_OPT_PROTOCOL,(PCSTR)&dwProtocol);
    ::mysql_options(pInitConn,MYSQL_SET_CHARSET_NAME,(PCSTR)"cp1251");

    PCSTR pcszURL = "127.0.0.1";
    //PCSTR pcszURL = "192.168.0.104";
    PCSTR pcszLogin = NULL;
    PCSTR pcszPassword = NULL;

    MYSQL* pDBConn = ::mysql_real_connect(pInitConn,pcszURL,pcszLogin,pcszPassword,NULL,3306,NULL,0);
    if (pDBConn != NULL)
    {
      DWORD dwVersion = ::mysql_get_server_version(pDBConn);

      // create and connect to MyCrashTest db
      int nResult = ::mysql_query(pDBConn,"CREATE DATABASE IF NOT EXISTS MyCrashTest");
      nResult = ::mysql_query(pDBConn,"USE MyCrashTest");
      if (nResult == 0)
      {
        // create InsertTest table
        nResult = ::mysql_query(pDBConn,"CREATE TABLE InsertTest(`ID` INT AUTO_INCREMENT PRIMARY KEY, `Value` INT UNSIGNED DEFAULT \"0\")");

        // create prepared statement to insert data into InsertTest table
        MYSQL_STMT* pStmt = ::mysql_stmt_init(pDBConn);
        if (pStmt != NULL)
        {
          DWORD dwFields = 1;
          MYSQL_BIND* pBind = new MYSQL_BIND[dwFields];
          ::ZeroMemory(pBind,sizeof(MYSQL_BIND) * dwFields);

          DWORD dwLength = 4;
          my_bool fIsNull = false;
          DWORD dwValue = 0;

          pBind[0].length = &dwLength;
          pBind[0].is_null = &fIsNull;
          pBind[0].is_unsigned = TRUE;
          pBind[0].buffer = &dwValue;
          pBind[0].buffer_length = 4;
          pBind[0].buffer_type = MYSQL_TYPE_LONG;

          PCSTR pcszQuery = "INSERT INTO InsertTest (`Value`) VALUES (?)";
          int nPrepareRet = ::mysql_stmt_prepare(pStmt,pcszQuery,::lstrlen(pcszQuery));
          if (nPrepareRet == 0)
          {
            if (::mysql_stmt_param_count(pStmt) == dwFields)
            {
              my_bool fBinded = ::mysql_stmt_bind_param(pStmt,pBind);
              if (fBinded == 0)
              {
                // OK, now insert 3 values...

                // server is still working
                dwValue = ::GetTickCount();
                int nExecuteRet = ::mysql_stmt_execute(pStmt);
                // must be ok

                // NOW STOP THE MYSQL PROCESS (KILL SERVER)

                // server is stopped
                ::Sleep(500);
                dwValue = ::GetTickCount();
                nExecuteRet = ::mysql_stmt_execute(pStmt);
                // must be error (Can't connect to MySQL server)

                ::Sleep(500);
                dwValue = ::GetTickCount();
                nExecuteRet = ::mysql_stmt_execute(pStmt);
                // must be Access Violation (0xC0000005)
              }
            }
          }
          ::mysql_stmt_close(pStmt);

          delete[] pBind;
        }
      }
    }
    ::mysql_close(pInitConn);
    pInitConn = NULL;
  }

  _Module.Term();
  CoUninitialize();
  return 0;
}