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

array bound (bulk) parameters of NULL propagate on next rows

Details

    Description

      When using BULK insert of arrays, if there is a NULL in the data for a column, all following rows will also have NULL for the same column.

      Attachments

        Activity

          static int bulk_null_null(MYSQL *mysql)
          {
            struct st_bulk4 {
              char char_value[20];
              char indicator1;
              int  int_value;
              char indicator2;
            };
           
            struct st_bulk4 val[]= {{"Row 1", STMT_INDICATOR_NTS, 3, STMT_INDICATOR_NONE},
                                    {"Row 2", STMT_INDICATOR_NULL, 3, STMT_INDICATOR_NULL},
                                    {"Row 3", STMT_INDICATOR_NTS, 3, STMT_INDICATOR_NONE}};
            int rc;
            MYSQL_BIND bind[2];
            MYSQL_RES *res;
            MYSQL_STMT *stmt= mysql_stmt_init(mysql);
            size_t row_size= sizeof(struct st_bulk4);
            int array_size= 3;
            unsigned long lengths[3]= {-1, -1, -1};
           
            if (!bulk_enabled)
              return SKIP;
            rc= mysql_query(mysql, "DROP TABLE IF EXISTS bulk_null");
            check_mysql_rc(rc,mysql);
            rc= mysql_query(mysql, "CREATE TABLE bulk_null (name varchar(20), row int)");
            check_mysql_rc(rc,mysql);
           
            rc= mysql_stmt_prepare(stmt, "INSERT INTO bulk_null VALUES (?,?)", -1);
            check_stmt_rc(rc, stmt);
           
            memset(bind, 0, sizeof(MYSQL_BIND)*2);
            
            rc= mysql_stmt_attr_set(stmt, STMT_ATTR_ARRAY_SIZE, &array_size);
            check_stmt_rc(rc, stmt);
            rc= mysql_stmt_attr_set(stmt, STMT_ATTR_ROW_SIZE, &row_size);
            check_stmt_rc(rc, stmt);
           
            bind[0].buffer_type= MYSQL_TYPE_STRING;
            bind[0].u.indicator= &val[0].indicator1;
            bind[0].buffer= &val[0].char_value;
            bind[0].length= lengths;
            bind[1].buffer_type= MYSQL_TYPE_LONG;
            bind[1].buffer= &val[0].int_value;
            bind[1].u.indicator= &val[0].indicator2;
           
            rc= mysql_stmt_bind_param(stmt, bind);
            check_stmt_rc(rc, stmt);
            rc= mysql_stmt_execute(stmt);
            check_stmt_rc(rc, stmt);
           
            mysql_stmt_close(stmt);
           
            rc= mysql_query(mysql, "SELECT * FROM bulk_null WHERE row=3");
            check_mysql_rc(rc, mysql);
            res= mysql_store_result(mysql);
            rc= (int)mysql_num_rows(res);
            mysql_free_result(res);
            FAIL_IF(rc != 2, "expected 2 rows");
            rc= mysql_query(mysql, "DROP TABLE bulk_null");
            check_mysql_rc(rc, mysql);
            return OK;
          }
          

          sanja Oleksandr Byelkin added a comment - static int bulk_null_null(MYSQL *mysql) { struct st_bulk4 { char char_value[20]; char indicator1; int int_value; char indicator2; };   struct st_bulk4 val[]= {{"Row 1", STMT_INDICATOR_NTS, 3, STMT_INDICATOR_NONE}, {"Row 2", STMT_INDICATOR_NULL, 3, STMT_INDICATOR_NULL}, {"Row 3", STMT_INDICATOR_NTS, 3, STMT_INDICATOR_NONE}}; int rc; MYSQL_BIND bind[2]; MYSQL_RES *res; MYSQL_STMT *stmt= mysql_stmt_init(mysql); size_t row_size= sizeof(struct st_bulk4); int array_size= 3; unsigned long lengths[3]= {-1, -1, -1};   if (!bulk_enabled) return SKIP; rc= mysql_query(mysql, "DROP TABLE IF EXISTS bulk_null"); check_mysql_rc(rc,mysql); rc= mysql_query(mysql, "CREATE TABLE bulk_null (name varchar(20), row int)"); check_mysql_rc(rc,mysql);   rc= mysql_stmt_prepare(stmt, "INSERT INTO bulk_null VALUES (?,?)", -1); check_stmt_rc(rc, stmt);   memset(bind, 0, sizeof(MYSQL_BIND)*2); rc= mysql_stmt_attr_set(stmt, STMT_ATTR_ARRAY_SIZE, &array_size); check_stmt_rc(rc, stmt); rc= mysql_stmt_attr_set(stmt, STMT_ATTR_ROW_SIZE, &row_size); check_stmt_rc(rc, stmt);   bind[0].buffer_type= MYSQL_TYPE_STRING; bind[0].u.indicator= &val[0].indicator1; bind[0].buffer= &val[0].char_value; bind[0].length= lengths; bind[1].buffer_type= MYSQL_TYPE_LONG; bind[1].buffer= &val[0].int_value; bind[1].u.indicator= &val[0].indicator2;   rc= mysql_stmt_bind_param(stmt, bind); check_stmt_rc(rc, stmt); rc= mysql_stmt_execute(stmt); check_stmt_rc(rc, stmt);   mysql_stmt_close(stmt);   rc= mysql_query(mysql, "SELECT * FROM bulk_null WHERE row=3"); check_mysql_rc(rc, mysql); res= mysql_store_result(mysql); rc= (int)mysql_num_rows(res); mysql_free_result(res); FAIL_IF(rc != 2, "expected 2 rows"); rc= mysql_query(mysql, "DROP TABLE bulk_null"); check_mysql_rc(rc, mysql); return OK; }

          Problem is that Item_param::null_value is not reset by set_(int_decimal...) methods after it was set_null.

          10.2 has exactly the same problem, but it masked by Item_param::save_in_field() which do not process null_value (work only according to Item_param::state).

          sanja Oleksandr Byelkin added a comment - Problem is that Item_param::null_value is not reset by set_(int_decimal...) methods after it was set_null. 10.2 has exactly the same problem, but it masked by Item_param::save_in_field() which do not process null_value (work only according to Item_param::state).

          People

            sanja Oleksandr Byelkin
            monty Michael Widenius
            Votes:
            1 Vote for this issue
            Watchers:
            4 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.