MariaDB Connector C, mysql_stmt_fetch_column() and memory corruption

316 Views Asked by At

I'm working on a wrapper for MariaDB Connector C. There is a typical situation when a developer doesn't know a length of a data stored in a field. As I figured out, one of the ways to obtain a real length of the field is to pass a buffer of lengths to mysql_stmt_bind_result and then to fetch each column by calling mysql_stmt_fetch_column. But I can't understand how the function mysql_stmt_fetch_column works because I'm getting a memory corruption and app abortion.

Here is how I'm trying to reach my goal

// preparations here
...
if (!mysql_stmt_execute(stmt))
{
    int columnNum = mysql_stmt_field_count(stmt);

    if (columnNum > 0)
    {
        MYSQL_RES*   metadata = mysql_stmt_result_metadata(stmt);
        MYSQL_FIELD* fields   = mysql_fetch_fields(metadata);
        MYSQL_BIND*  result   = new MYSQL_BIND[columnNum];

        std::memset(result,     0, sizeof (MYSQL_BIND) * columnNum);

        std::vector<unsigned long> lengths;

        lengths.resize(columnNum);

        for (int i = 0; i < columnNum; ++i)
            result[i].length = &lengths[i];

        if (!mysql_stmt_bind_result(stmt, result))
        {
            while (true)
            {
                  int status = mysql_stmt_fetch(stmt);

                  if (status == 1)
                  {
                      m_lastError = mysql_stmt_error(stmt);
                      isOK = false;
                      break;
                  }
                  else if (status == MYSQL_NO_DATA)
                  {
                      isOK = true;
                      break;
                  }

                  for (int i = 0; i < columnNum; ++i)
                  {
                      my_bool isNull = true;

                      if (lengths.at(i) > 0)
                      {
                          result[i].buffer_type   = fields[i].type;
                          result[i].is_null       = &isNull;
                          result[i].buffer        = malloc(lengths.at(i));
                          result[i].buffer_length = lengths.at(i);

                          mysql_stmt_fetch_column(stmt, result, i, 0);

                          if (!isNull)
                          {
                              // here I'm trying to read a result and I'm getting a valid result only from the first column
                          }
                      }
                  }
             }
        }
  }

If I put an array to the mysql_stmt_fetch_column then I'm fetching the only first field valid, all other fields are garbage. If I put a single MYSQL_BIND structure to this function, then I'm getting an abortion of the app on approximately 74th field (funny thing that it's always this field). If I use another array of MYSQL_BIND then the situation is the same as the first case.

Please help me to understand how to use it correctly! Thanks

Minimal reproducible example

0

There are 0 best solutions below