Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MySQL C API Handle TEXT field

When one uses Prepared Statements in MySQL C API to handle TEXT field result, one has to specify the length of the string for an out binding:

 MYSQL_BIND    out_bind;
 char          str_data[STRING_SIZE]; 
 my_bool       is_null;
 my_bool       error;

 ....
 /* STRING COLUMN */
 out_bind.buffer_type = MYSQL_TYPE_STRING;
 out_bind.buffer = str_data;
 out_bind.buffer_length = STRING_SIZE;
 out_bind.is_null= &is_null;
 out_bind.length= &length;
 out_bind.error= &error;

 mysql_stmt_bind_result(statement, out_bind)

In the given example STRING_SIZE is the known constant, but how to be with TEXT fields where data length can vary from small sizes to megabytes?

Is there standard approaches for this?

like image 951
MajesticRa Avatar asked Jul 07 '11 18:07

MajesticRa


2 Answers

The manual page for mysql_stmt_fetch says:

In some cases you might want to determine the length of a column value before fetching it with mysql_stmt_fetch(). ... To accomplish this, you can use these strategies:

  • Before invoking mysql_stmt_fetch() to retrieve individual rows, pass STMT_ATTR_UPDATE_MAX_LENGTH to mysql_stmt_attr_set(), then invoke mysql_stmt_store_result() to buffer the entire result on the client side. Setting the STMT_ATTR_UPDATE_MAX_LENGTH attribute causes the maximal length of column values to be indicated by the max_length member of the result set metadata returned by mysql_stmt_result_metadata().

  • Invoke mysql_stmt_fetch() with a zero-length buffer for the column in question and a pointer in which the real length can be stored. Then use the real length with mysql_stmt_fetch_column().

You might also like to read the manual page for mysql_stmt_bind_result

like image 117
pmg Avatar answered Nov 06 '22 14:11

pmg


I had the same issue. I have solved this problem like pmg saids in first point, using STMT_ATTR_UPDATE_MAX_LENGTH setting, here is my code :

MYSQL_STMT    *stmt;
MYSQL_BIND    bind[1];
MYSQL_BIND    bind_result[1];

// _con your mysql connection 
stmt = mysql_stmt_init(_con);
if (!stmt)
{
  fprintf(stderr, " mysql_stmt_init(), out of memory\n");
  exit(0);
}

char* aQuery = (char*) "'your query'";
if (mysql_stmt_prepare(stmt, aQuery, strlen(aQuery)))
{
  fprintf(stderr, " mysql_stmt_prepare(), INSERT failed\n");
  fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
  exit(0);
}

    // Here fill binded parameters (here a string)
memset(bind, 0, sizeof(bind));

const char* aStr = ioType.c_str();
long unsigned int aSize = ioType.size();

bind[0].buffer_type= MYSQL_TYPE_STRING;
bind[0].buffer= (char *) aStr;
bind[0].buffer_length= 2048;
bind[0].is_null= 0;
bind[0].length= &aSize;

/* Bind the buffers */
if (mysql_stmt_bind_param(stmt, bind))
{
  fprintf(stderr, " mysql_stmt_bind_param() failed\n");
  fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
  exit(0);
}

    // Reauest meta data information
MYSQL_RES* aRes = mysql_stmt_result_metadata(stmt);

    // Set STMT_ATTR_UPDATE_MAX_LENGTH attribute
my_bool aBool = 1;
mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &aBool);

/* Execute the select statement - 1*/
if (mysql_stmt_execute(stmt))
{
  fprintf(stderr, " mysql_stmt_execute(), 1 failed\n");
  fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
  exit(0);
}

if (mysql_stmt_store_result(stmt)) {
  fprintf(stderr, " mysql_stmt_execute(), 1 failed\n");
  fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
  exit(0);
}       

// Retrieving meta data information
MYSQL_FIELD* aField = &aRes->fields[0];

fprintf(stdout, " field %s \n",aField->name);
fprintf(stdout, " field length %d \n",(int) aField->length);
fprintf(stdout, " field max length %d \n", (int) aField->max_length);


int totalrows = mysql_stmt_num_rows(stmt);
fprintf(stdout, " fetched %d description\n",totalrows);
fprintf(stdout, " field count %d \n",(int) aRes->field_count);

long unsigned int aMaxSize;
char* aBuffer = (char*) malloc(aField->max_length);

memset (bind_result, 0, sizeof (bind_result));
bind_result[0].buffer_type= MYSQL_TYPE_BLOB;
bind_result[0].is_null= 0;
bind_result[0].buffer= (char *) aBuffer;
bind_result[0].buffer_length= aField->max_length;
bind_result[0].length= &aMaxSize;

mysql_stmt_bind_result(stmt, bind_result);

std::string aStrData;
while(!mysql_stmt_fetch(stmt))
{
    fprintf(stdout, " size %d\n", (int) aMaxSize);
    aStrData = std::string(aBuffer,aMaxSize);
    fprintf(stdout, " data %s\n", aStrData.c_str());
}

free(aBuffer);

mysql_free_result(aRes);

if (mysql_stmt_close(stmt))
{
  fprintf(stderr, " failed while closing the statement\n");
  fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
  exit(0);
}

Hope this helps !

like image 22
JBV06 Avatar answered Nov 06 '22 16:11

JBV06