Bug #4014 embedded server with prepare on MySQL 4.1.2
Submitted: 4 Jun 2004 17:20 Modified: 11 Jun 2004 20:14
Reporter: Ted Wennmark Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: Embedded Library ( libmysqld ) Severity:S2 (Serious)
Version:4.1.2 OS:Linux (SuSe)
Assigned to: Alexey Botchkov CPU Architecture:Any

[4 Jun 2004 17:20] Ted Wennmark
Description:
The server causes segmentation fault during execute of selects, insert update works 
fine. The testcode worked fine in release 4.1.1 but then updates did not work ...

core trace:
#0  alloc_root (mem_root=0x0, Size=10) at my_alloc.c:144
#1  0x0804eb42 in Protocol::net_store_data(char const*, unsigned) (this=0x8440204, from=0x0, length=10)
    at lib_sql.cc:768
#2  0x080a0e26 in Protocol_prep::store(char const*, unsigned, charset_info_st*) (this=0xa,
    from=0x8449281 "MySQL", ' ' <repeats 35 times>, length=5, fromcs=0x0) at protocol.cc:711
#3  0x082450d8 in Field::send_binary(Protocol*) (this=0x8440204, protocol=0x8440204)
    at ../sql/sql_string.h:79
#4  0x080a122f in Protocol_prep::store(Field*) (this=0x8440204, field=0x0) at protocol.cc:1082
#5  0x0806be6b in Item_field::send(Protocol*, String*) (this=0x0, protocol=0x0, buffer=0xbfffdc70)
    at item.cc:1741
#6  0x080af050 in select_send::send_data(List<Item>&) (this=0x8440ca0, items=@0x8440204) at sql_class.cc:741
#7  0x080d8ca8 in end_send (join=0x8440cb0, join_tab=0x8441a08) at sql_select.cc:6360
#8  0x080d79fa in sub_select (join=0x8440cb0, join_tab=0x84418c8, end_of_records=10) at sql_select.cc:5804
#9  0x080d1867 in do_select (join=0x8440cb0, fields=0x84418c8, table=0x0, procedure=0x0)
    at sql_select.cc:5688
#10 0x080c961f in JOIN::exec() (this=0x8440cb0) at sql_select.cc:1516
#11 0x080ca055 in mysql_select (thd=0x843fa18, rref_pointer_array=0x84446a4, tables=0x8444d60, wild_num=0,
    fields=@0x0, conds=0x0, og_num=0, order=0x0, group=0x0, having=0x0, proc_param=0x0,
    select_options=310659072, result=0x8440cb0, unit=0x84444e0, select_lex=0x84445bc) at sql_select.cc:1633
#12 0x080c660a in handle_select (thd=0x843fa18, lex=0x0, result=0x8440ca0) at sql_select.cc:181
#13 0x080bd118 in mysql_execute_command (thd=0x843fa18) at sql_parse.cc:1974
#14 0x080c39c1 in mysql_stmt_execute (thd=0x843fa18, packet=0x0, packet_length=5) at sql_prepare.cc:1673
#15 0x080bcbc6 in dispatch_command (command=138621328, thd=0x843fa18, packet=0x8433190 "\002",
    packet_length=5) at sql_parse.cc:1428
#16 0x0804d992 in emb_advanced_command (mysql=0x8432980, command=COM_SLEEP, header=0x0, header_length=0,
    arg=0x8433190 "\002", arg_length=4, skip_check=1 '\001') at lib_sql.cc:105
#17 0x0804dc94 in emb_stmt_execute (stmt=0x8433108) at lib_sql.cc:203
#18 0x08054871 in mysql_stmt_execute (stmt=0x8433108) at libmysql.c:2539
#19 0x0804bcd4 in main () at dbtest.c:203
#20 0x401914a2 in __libc_start_main () from /lib/libc.so.6

List:
139       gptr point;
140       reg1 USED_MEM *next= 0;
141       reg2 USED_MEM **prev;
142
143       Size= ALIGN_SIZE(Size);
144       if ((*(prev= &mem_root->free)) != NULL)
145       {
146         if ((*prev)->left < Size &&
147             mem_root->first_block_usage++ >= ALLOC_MAX_BLOCK_USAGE_BEFORE_DROP &&
148             (*prev)->left < ALLOC_MAX_BLOCK_TO_DROP)

How to repeat:
Test program (simply cut from your programs):
# include <stdlib.h>
# include <stdio.h>
# include "mysql.h"
# include "mysql_embed.h"
# include "string.h"

#define STRING_SIZE 50

#define DROP_SAMPLE_TABLE "DROP TABLE IF EXISTS test_table"
#define CREATE_SAMPLE_TABLE "CREATE TABLE test_table(col1 BIGINT not null auto_increment primary key,\
                                                 col2 CHAR(40)) ENGINE=MEMORY"
#define INSERT_SAMPLE "INSERT INTO test_table(col2) VALUES(?)"
#define SELECT_SAMPLE "SELECT col1, col2 FROM test_table"

int main ()
{

MYSQL         *mysql;
MYSQL_STMT    *stmt;
MYSQL_BIND    bind;
my_ulonglong  affected_rows;
int           param_count;
char          str_data[STRING_SIZE];
unsigned long str_length;
my_bool       is_null;
/* SELECT */
MYSQL_STMT    *s_stmt;
MYSQL_BIND    s_bind[2];
MYSQL_RES     *prepare_meta_result;
unsigned long length[2];
int           column_count, row_count;
int           int_data;
my_bool       s_is_null[4];

char *args[]={"dbtest"};
char *groups[]={"odendbs"};

printf("hej\n");
if (mysql_server_init(sizeof(args) / sizeof(char *), args, groups))
    exit(0);

printf("hej\n");
mysql=mysql_init(0);
mysql_options(mysql,MYSQL_READ_DEFAULT_GROUP,"foo");
if (!mysql_real_connect(mysql,"localhost",NULL,NULL,"test",0,NULL,0))
{
    fprintf(stderr, "Failed to connect to database: Error: %s\n",
          mysql_error(mysql));
}

if (mysql_query(mysql, DROP_SAMPLE_TABLE))
{
  fprintf(stderr, " DROP TABLE failed\n");
  fprintf(stderr, " %s\n", mysql_error(mysql));
  exit(0);
}

if (mysql_query(mysql, CREATE_SAMPLE_TABLE))
{
  fprintf(stderr, " CREATE TABLE failed\n");
  fprintf(stderr, " %s\n", mysql_error(mysql));
  exit(0);
}

/* INSERT */
stmt = mysql_stmt_init(mysql);
if (!stmt)
{
  fprintf(stderr, " mysql_stmt_init(), out of memory\n");
  exit(0);
}
if (mysql_stmt_prepare(stmt, INSERT_SAMPLE, strlen(INSERT_SAMPLE)))
{
  fprintf(stderr, " mysql_stmt_prepare(), INSERT failed\n");
  fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
  exit(0);
}
fprintf(stdout, " prepare, INSERT successful\n");

param_count= mysql_stmt_param_count(stmt);
fprintf(stdout, " total parameters in INSERT: %d\n", param_count);

if (param_count != 1) /* validate parameter count */
{
  fprintf(stderr, " invalid parameter count returned by MySQL\n");
  exit(0);
}

/* STRING PARAM */
bind.buffer_type= MYSQL_TYPE_VAR_STRING;
bind.buffer= (char *)str_data;
bind.buffer_length= STRING_SIZE;
bind.is_null= 0;
bind.length= &str_length;

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

/* Specify the data values for the first row */
strncpy(str_data, "MySQL", STRING_SIZE); /* string  */
str_length= strlen(str_data);

/* Execute the INSERT 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);
}

/* Get the total number of affected rows */
affected_rows= mysql_stmt_affected_rows(stmt);
fprintf(stdout, " total affected rows(insert 1): %ld\n", affected_rows);

if (affected_rows != 1) /* validate affected rows */
{
  fprintf(stderr, " invalid affected rows by MySQL\n");
  exit(0);
}

/* Specify data values for second row, then re-execute the statement */
strncpy(str_data, "The most popular open source database", STRING_SIZE);
str_length= strlen(str_data);

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

/* Get the total rows affected */
affected_rows= mysql_stmt_affected_rows(stmt);
fprintf(stdout, " total affected rows(insert 2): %ld\n", affected_rows);

if (affected_rows != 1) /* validate affected rows */
{
  fprintf(stderr, " invalid affected rows by MySQL\n");
  exit(0);
}

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

/* SELECT */
s_stmt = mysql_stmt_init(mysql);
if (!s_stmt)
{
  fprintf(stderr, " mysql_stmt_init(), out of memory\n");
  exit(0);
}
if (mysql_stmt_prepare(s_stmt, SELECT_SAMPLE, strlen(SELECT_SAMPLE)))
{
  fprintf(stderr, " mysql_stmt_prepare(), SELECT failed\n");
  fprintf(stderr, " %s\n", mysql_stmt_error(s_stmt));
  exit(0);
}
fprintf(stdout, " prepare, SELECT successful\n");

/* Get the parameter count from the statement */
param_count= mysql_stmt_param_count(s_stmt);
fprintf(stdout, " total parameters in SELECT: %d\n", param_count);

if (param_count != 0) /* validate parameter count */
{
  fprintf(stderr, " invalid parameter count returned by MySQL\n");
  exit(0);
}

/* Fetch result set meta information */
prepare_meta_result = mysql_stmt_result_metadata(s_stmt);
if (!prepare_meta_result)
{
  fprintf(stderr,
         " mysql_stmt_result_metadata(), returned no meta information\n");
  fprintf(stderr, " %s\n", mysql_stmt_error(s_stmt));
  exit(0);
}

/* Get total columns in the query */
column_count= mysql_num_fields(prepare_meta_result);
fprintf(stdout, " total columns in SELECT statement: %d\n", column_count);

if (column_count != 2) /* validate column count */
{
  fprintf(stderr, " invalid column count returned by MySQL\n");
  exit(0);
}

/* Execute the SELECT query */
fprintf(stdout, "before mysql_stmt_execute\n");
if (mysql_stmt_execute(s_stmt))
{
  fprintf(stderr, " mysql_stmt_execute(), failed\n");
  fprintf(stderr, " %s\n", mysql_stmt_error(s_stmt));
  exit(0);
}

/* Bind the result buffers for all 4 columns before fetching them */

/* INTEGER COLUMN */
s_bind[0].buffer_type= MYSQL_TYPE_LONG;
s_bind[0].buffer= (char *)&int_data;
s_bind[0].is_null= &s_is_null[0];
s_bind[0].length= &length[0];

/* STRING COLUMN */
s_bind[1].buffer_type= MYSQL_TYPE_VAR_STRING;
s_bind[1].buffer= (char *)str_data;
s_bind[1].buffer_length= STRING_SIZE;
s_bind[1].is_null= &s_is_null[1];
s_bind[1].length= &length[1];

fprintf(stdout, "before mysql_stmt_bind_result\n");
if (mysql_stmt_bind_result(s_stmt, s_bind))
{
  fprintf(stderr, " mysql_stmt_bind_result() failed\n");
  fprintf(stderr, " %s\n", mysql_stmt_error(s_stmt));
  exit(0);
}

fprintf(stdout, "before mysql_stmt_store_result\n");
if (mysql_stmt_store_result(s_stmt))
{
  fprintf(stderr, " mysql_stmt_store_result() failed\n");
  fprintf(stderr, " %s\n", mysql_stmt_error(s_stmt));
  exit(0);
}

/* Fetch all rows */
row_count= 0;
fprintf(stdout, "Fetching results ...\n");
while (!mysql_stmt_fetch(s_stmt))
{
  row_count++;
  fprintf(stdout, "  row %d\n", row_count);

  /* column 1 */
  fprintf(stdout, "   column1 (integer)  : ");
  if (s_is_null[0])
    fprintf(stdout, " NULL\n");
  else
    fprintf(stdout, " %d(%ld)\n", int_data, length[0]);

  /* column 2 */
  fprintf(stdout, "   column2 (string)   : ");
  if (s_is_null[1])
    fprintf(stdout, " NULL\n");
  else
    fprintf(stdout, " %s(%ld)\n", str_data, length[1]);

  fprintf(stdout, "\n");
}

/* Validate rows fetched */
fprintf(stdout, " total rows fetched: %d\n", row_count);
if (row_count != 2)
{
  fprintf(stderr, " MySQL failed to return all rows\n");
  exit(0);
}

/* Free the prepared result metadata */
mysql_free_result(prepare_meta_result);

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

mysql_close(mysql);

mysql_server_end();

return 0;
}

Makefile:
#MYSQL=/home/ted/mysql-4.1
#MYSQL=/home/mauritz/mysql-4.1.X
MYSQL=/home/mauritz/mysql-4.1.2
#MYSQL=/home/ted/ccdb/mysql-4.1.1-alpha

CCC=$(CXX)
ASFLAGS=$(XARCH)

CFLAGS=-g `$(MYSQL)/bin/mysql_config --cflags`
CCFLAGS=$(CFLAGS)
CXXFLAGS=$(CFLAGS)

LDLIBS_client   =  `$(MYSQL)/bin/mysql_config --libs`
LDLIBS_embedded = `$(MYSQL)/bin/mysql_config --embedded`

OBJS    = dbtest.o

all: dbtest_client dbtest_embedded

dbtest_client:  ${OBJS}
        ${CCC} ${CCFLAGS} -o $@ ${OBJS} ${LDLIBS_client}

dbtest_embedded: ${OBJS}
        ${CCC} ${CCFLAGS} -o $@ ${OBJS} ${LDLIBS_embedded}

clean:
        -rm *.o dbtest_client dbtest_embedded

gcc:
gcc (GCC) 3.2

Suggested fix:
No idea ....
[5 Jun 2004 0:49] Dean Ellis
Verified against 4.1.3 with the supplied test case.  Thank you.
[9 Jun 2004 19:22] Alexey Botchkov
bk commit - 4.1 tree (hf:1.1911) BUG#4014
[11 Jun 2004 20:14] Alexey Botchkov
Thank you for your bug report. This issue has been committed to our
source repository of that product and will be incorporated into the
next release.

If necessary, you can access the source repository and build the latest
available version, including the bugfix, yourself. More information 
about accessing the source trees is available at
    http://www.mysql.com/doc/en/Installing_source_tree.html