Uploaded image for project: 'MariaDB Server'
  1. MariaDB Server
  2. MDEV-41501

Server crash in Protocol_binary::prepare_for_resend on bulk DELETE ... RETURNING after reprepare

    XMLWordPrintable

Details

    Description

      Bulk execution (COM_STMT_BULK_EXECUTE) of DELETE ... RETURNING crashes the server when the first parameter set needs a reprepare (for example after ALTER TABLE between prepare and execute).

      How to repeat

      Connector/C, array binding (STMT_ATTR_ARRAY_SIZE = 3):

      mysql_query(m, "CREATE OR REPLACE TABLE tr (id INT PRIMARY KEY)");
      mysql_query(m, "INSERT INTO tr VALUES (1),(2),(3),(4)");
      stmt= mysql_stmt_init(m);
      mysql_stmt_prepare(stmt, "DELETE FROM tr WHERE id=? RETURNING id", -1);
      mysql_query(m, "ALTER TABLE tr ADD COLUMN x INT");   /* forces reprepare */
      int id[3]= {1, 2, 3};
      unsigned int n= 3;
      MYSQL_BIND b;
      memset(&b, 0, sizeof(b));
      b.buffer_type= MYSQL_TYPE_LONG;
      b.buffer= id;
      mysql_stmt_attr_set(stmt, STMT_ATTR_ARRAY_SIZE, &n);
      mysql_stmt_bind_param(stmt, &b);
      mysql_stmt_execute(stmt);                            /* server crashes */

      Reproduced on 10.11 (10.11.19 debug) and 11.4 (11.4.13 debug, source revision 4813c2f0a8a79e4e4c000cc8c9447096fafe7033):

      got signal 11 ;
      sql/protocol.cc:1744(Protocol_binary::prepare_for_resend())
      sql/sql_class.cc:3289(select_send::send_data(List<Item>&))
      sql/sql_delete.cc:899(Sql_cmd_delete::delete_from_single_table(THD*))
      sql/sql_delete.cc:1915(Sql_cmd_delete::execute_inner(THD*))
      sql/sql_select.cc:34838(Sql_cmd_dml::execute(THD*))
      sql/sql_parse.cc:4451(mysql_execute_command(THD*, bool))
      sql/sql_prepare.cc:5119(Prepared_statement::execute(String*, bool))
      sql/sql_prepare.cc:4697(Prepared_statement::execute_bulk_loop(String*, bool, unsigned char*, unsigned char*))
      sql/sql_prepare.cc:3410(mysql_stmt_execute_common(...))
      sql/sql_prepare.cc:3235(mysqld_stmt_bulk_execute(THD*, char*, unsigned int))
      sql/sql_parse.cc:1838(dispatch_command(...))

      Cause

      The DELETE code sends the RETURNING result set metadata only if !thd->get_stmt_da()->is_set(). It uses that test to recognise the first iteration of a non-optimized bulk operation.

      When the first iteration fails with ER_NEED_REPREPARE, execute_bulk_loop() calls thd->clear_error(). In bulk mode, Diagnostics_area::reset_diagnostics_area() then sets m_status= DA_OK_BULK. After the reprepare, is_set() is already true in the first iteration, so the metadata is never sent and send_data() crashes.

      The "metadata already sent" state should be tracked explicitly rather than derived from the diagnostics area. MDEV-23864 uses the same guard for INSERT ... RETURNING executed per parameter set, so a fix should cover both.

      Attachments

        Issue Links

          Activity

            People

              sanja Oleksandr Byelkin
              sanja Oleksandr Byelkin
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

                Created:
                Updated:

                Git Integration

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