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

Parameter array operation inserts wrong values in autoincrement field if indicator was specified

Details

    Description

      If we have auto_increment field in the table, and we insert there a few rows using parameter array, and we have indicator array set for the auto_increment field, and for some row indicator value is set to STMT_INDICATOR_NULL or STMT_INDICATOR_IGNORE, for all subsequent rows server insert values like if same indicator value was set for them, too. i.e. it auto-incremented values instead of values specified in bound array.

      I don't think C/C can be here to blame - I traced execution, and things look sane. Besides same error is not exposed with 10.2 server.

      I am not sure if that is "major" issue, as this does not look like very probable scenario, but on other hand c/odbc testcases have it. Besides I don't think it's very hard to fix.

      Below is short program to repeat it

      #include <stdio.h>
      #include <stdarg.h>
      #include <stdlib.h>
      #include <string.h>
      #include <mysql.h>
       
      #ifndef OK
      # define OK 0
      #endif
      #ifndef FAIL
      # define FAIL 1
      #endif
      #ifndef SKIP
      # define SKIP -1
      #endif
      #ifndef FALSE
      # define FALSE 0
      #endif
      #ifndef TRUE
      # define TRUE 1
      #endif
       
      void
      diag(char const *fmt, ...)
      {
        va_list ap;
        va_start(ap, fmt);
        fprintf(stdout, "# ");
        vfprintf(stdout, fmt, ap);
        fprintf(stdout, "\n");
        va_end(ap);
      }
       
      #define check_stmt_rc(_rc, _stmt) \
      if (_rc)\
      {\
        diag("Error: [%s] %s(%d) (%s: %d)", mysql_stmt_sqlstate(_stmt), mysql_stmt_error(_stmt), mysql_stmt_errno(_stmt), __FILE__, __LINE__);\
        return(FAIL);\
      }
       
      #define check_mysql_rc(rc, mysql) \
      if (rc)\
      {\
        diag("Error (%d): %s (%d) in %s line %d", rc, mysql_error(mysql), \
             mysql_errno(mysql), __FILE__, __LINE__);\
        return(FAIL);\
      }
       
      #define FAIL_IF(expr, reason)\
      if (expr)\
      {\
        diag("Error: %s (%s: %d)", (reason) ? reason : "", __FILE__, __LINE__);\
        return FAIL;\
      }
       
       
      int main(int argc, char *argv)
      {
        MYSQL      *ma;
        MYSQL_STMT *stmt;
        MYSQL_BIND bind[1];
        MYSQL_RES  *res;
        MYSQL_ROW  row;
        char       indicator[]= {0, STMT_INDICATOR_NULL, 0/*STMT_INDICATOR_IGNORE*/};
        my_bool   error[1];
        int        i, id[]= {2, 3, 777}, param_count= 1, count= sizeof(id)/sizeof(id[0]);
        my_bool    UpdateMaxLength= 1;
         
        ma = mysql_init(NULL);
        if (!mysql_real_connect(ma, "localhost", "root", "", "test", 3306, NULL, 0))
        {
          printf("Could not connect: %s\n", mysql_error(ma));
          exit(1);
        }
        else
        {
          printf("Server info %s\nClient info: %s\n",
            mysql_get_server_info(ma), mysql_get_client_info());
        }
       
        stmt = mysql_stmt_init(ma);
       
        if (!stmt)
        {
          diag("Could not init stmt handler(s)");
          return FAIL;
        }
       
        check_mysql_rc(mysql_query(ma, "DROP TABLE IF EXISTS ai_field_value"), ma);
        check_mysql_rc(mysql_query(ma, "CREATE TABLE ai_field_value (id int not null primary key auto_increment)"), ma);
        check_stmt_rc(mysql_stmt_prepare(stmt, "INSERT INTO ai_field_value(id) values(?)", -1), stmt);
       
        memset(bind, 0, sizeof(bind));
        bind[0].buffer_type = MYSQL_TYPE_LONG;
        bind[0].buffer = (void *)id;
        bind[0].buffer_length = 0;
        bind[0].is_null = NULL;
        bind[0].length = NULL;
        bind[0].error = error;
        bind[0].u.indicator= indicator;
       
        mysql_stmt_attr_set(stmt, STMT_ATTR_ARRAY_SIZE, (void*)&count);
        check_stmt_rc(mysql_stmt_bind_param(stmt, bind), stmt);
       
        check_stmt_rc(mysql_stmt_execute(stmt), stmt);
       
        mysql_stmt_close(stmt);
       
        check_mysql_rc(mysql_query(ma, "SELECT id FROM ai_field_value"), ma);
       
        res= mysql_store_result(ma);
        
        i= 0;
        while (row= mysql_fetch_row(res))
        {
          diag("id= %s", row[0]);
          FAIL_IF(atoi(row[0]) != id[i++], "Values is differented form the expected");
        }
        check_mysql_rc(mysql_query(ma, "DROP TABLE ai_field_value"), ma);
       
        mysql_close(ma);
        
        exit(0);
      }
      

      Attachments

        Issue Links

          Activity

            Lawrin Lawrin Novitsky added a comment - - edited

            I guess this bug has been fixed, since corresponding ODBC tests do not fail any more against 10.3

            Lawrin Lawrin Novitsky added a comment - - edited I guess this bug has been fixed, since corresponding ODBC tests do not fail any more against 10.3

            I am just repeating once again here, that the bug was never observed with the 10.2 server, but with 10.3 server only

            Lawrin Lawrin Novitsky added a comment - I am just repeating once again here, that the bug was never observed with the 10.2 server, but with 10.3 server only

            It was fixed, but test suite was added

            sanja Oleksandr Byelkin added a comment - It was fixed, but test suite was added

            People

              sanja Oleksandr Byelkin
              Lawrin Lawrin Novitsky
              Votes:
              0 Vote for this issue
              Watchers:
              6 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.