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

Closing a statement while another statement has a cursor opened causes erratic behaviour (random errors, hangs, crashes, etc)

    XMLWordPrintable

Details

    Description

      Closing a statement that has not started retrieval while there is a cursor opened in another statement causes the mariadb client to loose sync with the physical protocol state which in turn causes erratic behaviour in following interactions with the API: wrong return codes, crashes, hangs, etc

      Correct behaviour should be for "mysql_stmt_close" to close the current cursor (regardless of what statement opened it). Then attempts to fetch data from a cursor while there is none active (regardless of the statement used in the mysql_stmt_fetch call) should return an error saying there is no cursor opened.

      The interaction causing the issue to surface is:

      create stmt1
      prepare stmt1
      create stmt2
      prepare stmt2
      fetch stmt1
      close stmt2 -> from this point onwards the client is in an inconsistent state. Any interaction with the client from this point onwards will be subject to undeterministic behavior.

      NOTE: The application I work on and where this causes wrong behaviour (crashes in my case) allows customers to choose how statements interact with connections. The customer can for instance use a connection per stmt or can decide to have concurrent statements using the same connection. This flexibility is in place since this application supports many other c connectors (oracle, postgres, etc) where retrieving data concurrently from different statements is supported by their respectives clients. In short, getting real useful errors indicating the interaction attempted is not supported by the underlying connector is ok but getting crashes or undeterministic behaviour is not.

      For your convenience I have attached a patch.diff (generated from "master") with test cases that reproduce this issue. The patch adds this test cases in the "ps_bugs" executable that comes as part of the mariadb c connector test suite.

      Also, I have done an initial investigation which shows that the culprit seems to be in line 379 (this is from "master" at the time of writing) in function mthd_stmt_flush_unbuffered() in file mariadb_stmt.c:

       369 void mthd_stmt_flush_unbuffered(MYSQL_STMT *stmt)
       370 {
       371   ulong packet_len;
       372   int in_resultset= stmt->state > MYSQL_STMT_EXECUTED &&
       373                     stmt->state < MYSQL_STMT_FETCH_DONE;
       374   while ((packet_len = ma_net_safe_read(stmt->mysql)) != packet_error)
       375   {
       376     unsigned int last_status= stmt->mysql->server_status;
       377     uchar *pos= stmt->mysql->net.read_pos;
       378 
       
      "in_resultset" is 0 since "stmt" has not started fetching yet. However, there is 
      a cursor open at this point on a different statement so "pos" is not pointing 
      at an OK packet but at the header (also 0x00) of a row packet.
       
      Fix: The mariadb client should not be using the state of the stmt struct to 
      know if it is in the middle of a fetch but the state of the MYSQL struct.
       
       379     if (!in_resultset && *pos == 0) /* OK */
       380     {
       381       pos++;
       382       net_field_length(&pos);
       383       net_field_length(&pos);
       384       stmt->mysql->server_status= uint2korr(pos);
       385       ma_status_callback(stmt->mysql, last_status);
       386       goto end;
       387     }
       388     if (packet_len < 8 && *pos == 254) /* EOF */
       389     {
       390       if (mariadb_connection(stmt->mysql))
       391       {
       392         stmt->mysql->server_status= uint2korr(pos + 3);
       393         ma_status_callback(stmt->mysql, last_status);
       394         if (in_resultset)
       395           goto end;
       396         in_resultset= 1;
       397       }
       398       else
       399         goto end;
       400     }
       401   }
       402 end:
       403   stmt->state= MYSQL_STMT_FETCH_DONE;
       404 }
       

      Please have a look.

      Thanks

      Attachments

        Activity

          People

            georg Georg Richter
            Josep Josep Yus
            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.