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

              People

              • Assignee:
                sanja Oleksandr Byelkin
                Reporter:
                Lawrin Lawrin Novitsky
              • Votes:
                0 Vote for this issue
                Watchers:
                6 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: