Uploaded image for project: 'MariaDB Connector/C'
  1. MariaDB Connector/C
  2. CONC-194

mysql_stmt_fetch_column does not respect 'offset' parameter for blob fields

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Closed (View Workflow)
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: 2.2.3
    • Fix Version/s: 3.0.1, 2.3.1
    • Labels:
      None

      Description

      mysql_stmt_fetch_column always copy field data with offset 0.
      Code to repeat the bug (extended for blob field test_fetch_offset test from fetch.c suite)

      static int test_fetch_offset(MYSQL *mysql)
      {
        MYSQL_STMT *stmt;
        MYSQL_BIND my_bind[2];
        char       data[11], chunk[5];
        ulong      length[2];
        int        rc;
        my_bool    is_null[2];
        char       *query = "SELECT * FROM t1";
       
       
        rc= mysql_query(mysql, "drop table if exists t1");
        check_mysql_rc(rc, mysql);
        rc= mysql_query(mysql, "create table t1(a char(10), b mediumblob)");
        check_mysql_rc(rc, mysql);
        rc= mysql_query(mysql, "insert into t1 values('abcdefghij', 'klmnopqrstzy'), (null, null)");
        check_mysql_rc(rc, mysql);
       
        stmt= mysql_stmt_init(mysql);
        FAIL_IF(!stmt, mysql_error(mysql));
       
        rc= mysql_stmt_prepare(stmt, query, (unsigned long)strlen(query));
        check_stmt_rc(rc,stmt);
       
        memset(my_bind, '\0', sizeof(my_bind));
        my_bind[0].buffer_type= MYSQL_TYPE_STRING;
        my_bind[0].buffer= (void *)data;
        my_bind[0].buffer_length= 11;
        my_bind[0].is_null= &is_null[0];
        my_bind[0].length= &length[0];
       
        my_bind[1].buffer_type= MYSQL_TYPE_STRING;
        my_bind[1].buffer= NULL;
        my_bind[1].buffer_length= 0;
        my_bind[1].is_null= &is_null[1];
        my_bind[1].length= &length[1];
       
        rc= mysql_stmt_execute(stmt);
        check_stmt_rc(rc,stmt);
       
        rc= mysql_stmt_fetch_column(stmt, my_bind, 0, 0);
        FAIL_IF(!rc, "Error expected");
       
        rc= mysql_stmt_execute(stmt);
        check_stmt_rc(rc,stmt);
       
        rc= mysql_stmt_bind_result(stmt, my_bind);
        check_stmt_rc(rc,stmt);
       
        rc= mysql_stmt_store_result(stmt);
        check_stmt_rc(rc,stmt);
       
        rc= mysql_stmt_fetch(stmt);
        FAIL_UNLESS(rc == MYSQL_DATA_TRUNCATED, "rc != MYSQL_DATA_TRUNCATED");
       
        data[0]= '\0';
        rc= mysql_stmt_fetch_column(stmt, &my_bind[0], 0, 0);
        check_stmt_rc(rc,stmt);
       
       
        FAIL_IF(!(strncmp(data, "abcd", 4) == 0 && length[0] == 10), "Wrong value");
       
        rc= mysql_stmt_fetch_column(stmt, &my_bind[0], 0, 5);
        check_stmt_rc(rc,stmt);
        FAIL_IF(!(strncmp(data, "fg", 2) == 0 && length[0] == 10), "Wrong value");
       
        rc= mysql_stmt_fetch_column(stmt, &my_bind[0], 0, 9);
        check_stmt_rc(rc,stmt);
        FAIL_IF(!(strncmp(data, "j", 1) == 0 && length[0] == 10), "Wrong value");
       
        /* Now blob field */
        my_bind[1].buffer= chunk;
        my_bind[1].buffer_length= sizeof(chunk);
       
        rc= mysql_stmt_fetch_column(stmt, &my_bind[1], 1, 0);
        check_stmt_rc(rc,stmt);
       
        FAIL_IF(!(strncmp(chunk, "klmno", 5) == 0 && length[1] == 12), "Wrong value");
       
        rc= mysql_stmt_fetch_column(stmt, &my_bind[1], 1, 5);
        check_stmt_rc(rc,stmt);
        FAIL_IF(!(strncmp(chunk, "pqrst", 5) == 0 && length[1] == 12), "Wrong value");
       
        rc= mysql_stmt_fetch_column(stmt, &my_bind[1], 1, 10);
        check_stmt_rc(rc,stmt);
        FAIL_IF(!(strncmp(chunk, "zy", 2) == 0 && length[1] == 12), "Wrong value");
       
        rc= mysql_stmt_fetch(stmt);
        check_stmt_rc(rc,stmt);
       
        memset(is_null, 0, sizeof(is_null));
       
        rc= mysql_stmt_fetch_column(stmt, &my_bind[0], 0, 0);
        check_stmt_rc(rc,stmt);
       
        FAIL_IF(is_null[0] != 1, "Null flag not set");
       
        rc= mysql_stmt_fetch_column(stmt, &my_bind[1], 1, 0);
        check_stmt_rc(rc,stmt);
       
        FAIL_IF(is_null[1] != 1, "Null flag not set");
       
        rc= mysql_stmt_fetch(stmt);
        FAIL_IF(rc != MYSQL_NO_DATA, "Expected MYSQL_NO_DATA");
       
        rc= mysql_stmt_fetch_column(stmt, my_bind, 1, 0);
        FAIL_IF(!rc, "Error expected");
       
        mysql_stmt_close(stmt);
       
        rc= mysql_query(mysql, "drop table t1");
        check_mysql_rc(rc, mysql);
       
        return OK;
      }
      

      Proposed fix:

      diff --git a/libmariadb/my_stmt_codec.c b/libmariadb/my_stmt_codec.c
      index 7d90151..6e9dee2 100644
      --- a/libmariadb/my_stmt_codec.c
      +++ b/libmariadb/my_stmt_codec.c
      @@ -925,8 +925,9 @@ void ps_fetch_bin(MYSQL_BIND *r_param, const MYSQL_FIELD *field,
         if (!(field->flags & BINARY_FLAG) && r_param->buffer_type == MYSQL_TYPE_STRING)
           field_length++;
       
      -  copylen= MIN(field_length, r_param->buffer_length);
      -  memcpy(r_param->buffer, *row, copylen);
      +  /* Making sure that we do not copy past the field. e.g. if offset >= field_length, copylen is 0 */
      +  copylen= MIN(field_length - MIN(r_param->offset, field_length), r_param->buffer_length);
      +  memcpy(r_param->buffer, *row + MIN(r_param->offset, field_length), copylen);
         *r_param->error= copylen < field_length;
       
         /* don't count trailing zero if we fetch into string */
      @@ -934,9 +935,9 @@ void ps_fetch_bin(MYSQL_BIND *r_param, const MYSQL_FIELD *field,
             !*r_param->error)
           field_length--;
       
      -  *r_param->length= field_length;
      +  *r_param->length= field_length; /*copylen;*/
       
      -  (*row) += field_length;
      +  (*row) += copylen/*field_length*/;
       }
       /* }}} */
      

        Attachments

          Issue Links

            Activity

              People

              Assignee:
              georg Georg Richter
              Reporter:
              Lawrin Lawrin Novitsky
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

                Dates

                Created:
                Updated:
                Resolved: