Uploaded image for project: 'MariaDB Connector/C'
  1. MariaDB Connector/C
  2. CONC-141

Hang when working with prepared statements

Details

    • Bug
    • Status: Closed (View Workflow)
    • Major
    • Resolution: Fixed
    • 2.1
    • 3.0.0, 2.2.0
    • None
    • None
    • All

    Description

      There is a sequence of operations that can cause the client to hang when working with prepared statements. It only happens when 1) using stored procedures to return multiple result sets, 2) when an error occurs in the second or subsequent result set in the procedure, 3) when the statement is then re-used, and 4) when mysql_stmt_free_result() is called between receiving the error and reusing the statement. I think that the error is on line 1886 of my_stmt.c, but am not totally sure. (Perhaps need a line inserted at around 1890 of my_stmt.c to update the state once an error is detected.)

      To reproduce, first need to setup the database:

      create table test (KeyVal int not null primary key);
      insert into test (KeyVal) values (1);
      delimiter //
      create procedure TestProc()
      begin
      select * from Test;
      insert into Test (KeyVal) values (1);
      end//
      delimiter ;

      When this stored proc is run, it will return a two result sets, but with an error value in the second one.

      The C code side is:

      	char sQuery[] = "call testproc";
       
      	MYSQL* pSQL = mysql_init(nullptr);
      	mysql_real_connect(pSQL, "127.0.0.1", "user", "password", "db", 0, nullptr, 0));
      	MYSQL_STMT* pStmt = mysql_stmt_init(pSQL);
      	mysql_stmt_prepare(pStmt, sQuery, sizeof(sQuery) - 1));
      	mysql_stmt_execute(pStmt);
      	mysql_stmt_next_result(pStmt);  // Returns 1062 error for duplicate keys. stmt is in MYSQL_STMT_WAITING_USE_OR_STORE state on return from this function. This seems to be incorrect.
      	mysql_stmt_free_result(pStmt);  // Moves the stmt into the MYSQL_STMT_USER_FETCHING state. 
      	mysql_stmt_execute(pStmt);     // This hangs. It is waiting for the server to send a result set, but the server has already sent an error code.

      After writing the above, I did some additional testing, and everything seems to work if I remove the mysql_stmt_free_result() call. However, the behavior is inconsistent between when an error occurs in the first result set and when it occurs in a subsequent result set. (See line 1506 of my_stmt.c. If an error is returned by the first result set, the stmt is put into the MYSQL_STMT_PREPARED state.) There is another inconsistency there, too. When an error occurs in the first result set, stmt->upsert_status.affected_rows gets updated before returning the error code. In mysql_stmt_next_result(), this happens afterwards.

      Update:
      I have tested a fix. Inserting the following line at line 1892 in my_stmt.c fixes the problem:

          stmt->state= MYSQL_STMT_PREPARED;

      Attachments

        Activity

          georg Georg Richter added a comment -

          We need to check in mysql_stmt_next_result if more data is on the wire, if not stmt->state should be set to MYSQL_STMT_FETCH_DONE (return code 1).

          The given example is not correct:
          1) When an error in a stored procedure occurs you should preferable reset the statement (mysql_stmt_reset())
          2) You should check the return code of mysql_stmt_next_result (should be 1, error, no more result sets)
          3) mysql_stmt_free_result should be used when you have a result set. Since return code of mysql_stmt_next_result was 1, there is no result set (only error package, which was already read from wire).

          georg Georg Richter added a comment - We need to check in mysql_stmt_next_result if more data is on the wire, if not stmt->state should be set to MYSQL_STMT_FETCH_DONE (return code 1). The given example is not correct: 1) When an error in a stored procedure occurs you should preferable reset the statement ( mysql_stmt_reset() ) 2) You should check the return code of mysql_stmt_next_result (should be 1, error, no more result sets) 3) mysql_stmt_free_result should be used when you have a result set. Since return code of mysql_stmt_next_result was 1, there is no result set (only error package, which was already read from wire).
          georg Georg Richter added a comment -

          Fixed.

          Changeset: b950d2cf4882fb3424df8dee452efe42891e6530
          Branch: 2.2

          georg Georg Richter added a comment - Fixed. Changeset: b950d2cf4882fb3424df8dee452efe42891e6530 Branch: 2.2

          People

            georg Georg Richter
            A812371 Matt Fagan
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Git Integration

                Error rendering 'com.xiplink.jira.git.jira_git_plugin:git-issue-webpanel'. Please contact your Jira administrators.