[MDEV-15079] Parameter array operation inserts wrong values in autoincrement field if indicator was specified Created: 2018-01-26  Updated: 2018-04-25  Resolved: 2018-04-25

Status: Closed
Project: MariaDB Server
Component/s: Data Manipulation - Insert
Affects Version/s: 10.3.4
Fix Version/s: 10.3.7

Type: Bug Priority: Major
Reporter: Lawrin Novitsky Assignee: Oleksandr Byelkin
Resolution: Cannot Reproduce Votes: 0
Labels: None

Issue Links:
Problem/Incident
causes ODBC-132 Few Testcases fail against 10.3 server Closed

 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);
}



 Comments   
Comment by Lawrin Novitsky [ 2018-03-27 ]

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

Comment by Lawrin Novitsky [ 2018-04-17 ]

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

Comment by Oleksandr Byelkin [ 2018-04-25 ]

It was fixed, but test suite was added

Generated at Thu Feb 08 08:18:31 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.