Bug #2992 bind of date /datetime is not works (Client Out of memory)
Submitted: 27 Feb 2004 2:21 Modified: 25 May 2004 0:50
Reporter: Gergo Bacskai Email Updates:
Status: Can't repeat Impact on me:
None 
Category:MySQL Server Severity:S2 (Serious)
Version:4.x 5.x OS:Linux (Linux Debian Woody)
Assigned to: Konstantin Osipov CPU Architecture:Any

[27 Feb 2004 2:21] Gergo Bacskai
Description:
Datetime bind is dump the client on 4.x and 5.x mysql server
here are the files
please read the comments on the files
------------------------------------------------------------------------
make.sh
------------------------------------------------------------------------
#!/bin/sh
gcc-2.95 -I. -I/usr/local/mysql/include/ -O0 -g3 -c ./xconv.c ./upc_functions.c
gcc-2.95 -O0 -g3 -I/usr/local/inclued/mysql/ -I. -o xconv xconv.o upc_functions.o -lmysqlclient -lz
------------------------------------------------------------------------
xconv.c
------------------------------------------------------------------------
/***************************************************************************
 *   Copyright (C) 2004 UPC by Papy Bela                                   *
 *   papyb@upc.hu                                                          *
 *                                                                         *
 ***************************************************************************/

#include <upc_functions.h>

#define MYSQL_HOST   "localhost"       /*database server name*/
#define MYSQL_USERID "root"            /* database user id */
#define MYSQL_PASSWD ""                /* userid password */
#define MYSQL_DB     "test"            /* table name */
#define MYSQL_PORT   3306              /* port */

/* This program works if the table use only one date column !
If I use 2-3 date/datetime column than the client goes out of memory 
We have tested under 4.x and 5.x binaries and own compiled source binaries too 
snapshots and original 4.1 binaries / sources too */

/* the function in functions.c are works very well with other tables and other structures ! */

/* we have used gcc 3.3.3 and gcc 2-95 for compile the server and this small program too but nothing new happend */

static const char *client_test_load_default_groups[]= { "client", 0 };

     struct {
       struct whead { long account_number,statement_number; } h;
     } *wpp,*std_wp;

     struct {
       struct whead h;
       MYSQL_TIME data_collection_from_date,data_collection_to_date, due_date;
     } my_wcb;

int main(int argc, char* argv[]) {

  MYSQL *mysql;
  MYSQL_BIND my_bind[40]; MYSQL_STMT *my_stmt;
  struct my_nu my_null[40];
  int my_sor;

  load_defaults("my",client_test_load_default_groups,&argc,&argv);
  ClientConnect(&mysql,MYSQL_HOST,MYSQL_USERID,MYSQL_PASSWD,MYSQL_DB,MYSQL_PORT);

   mysql_query(mysql,"DROP table wiz_customer_wo");
 
     mysql_query(mysql,"create table IF NOT EXISTS wiz_customer_wo ("
             "account_number int(10)"
             ",statement_number int(10)"
             ",data_collection_from_date datetime"
             ",data_collection_to_date datetime"   /* the insert works if you use 1 (simple) date datatype !*/
             ",due_date date"
             ") ");
 
     my_sor=0;
     MyBindO(my_bind,my_sor,my_wcb.h.account_number,FIELD_TYPE_LONG,NULL);
     MyBindO(my_bind,my_sor,my_wcb.h.statement_number,FIELD_TYPE_LONG,NULL);
     MyBindO(my_bind,my_sor,my_wcb.data_collection_from_date,FIELD_TYPE_DATETIME,my_null);
     MyBindO(my_bind,my_sor,my_wcb.data_collection_to_date,FIELD_TYPE_DATETIME,my_null);
     MyBindO(my_bind,my_sor,my_wcb.due_date,FIELD_TYPE_STRING,my_null);
     NuTo(my_bind,my_null,0,my_sor);
     MyPrepareOut(mysql,"insert delayed into wiz_customer_wo values (?,?,?,?,?)",&my_stmt,my_bind);
      
       my_wcb.data_collection_from_date.year=2002; /* Here you can fill fully these variables) */
       my_wcb.data_collection_from_date.month=1;
       my_wcb.data_collection_from_date.day=2;

      my_wcb.data_collection_to_date=my_wcb.data_collection_from_date;

	/* Here you can fill all the date variabe2 */
	
     Mysql_Execute(my_stmt,"wcb_ins_stmt :"); /* Here goes the execute error */
     mysql_stmt_close(my_stmt); 
  return 1;
}
------------------------------------------------------------------------
upc_functions.c
------------------------------------------------------------------------
/***************************************************************************
 *   Copyright (C) 2004 by root                                            *
 *   root@bu1wks2682                                                       *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <upc_functions.h>
void CreateIndex (char *table,char *index_name,char *field,MYSQL *mysql) {
 char bufi[200],sqlt[300],*cp; int i;
 if (index_name==NULL) {
  cp=bufi; sprintf(bufi,"%s_%s",table,field);
  for (i=strlen(table); i<strlen(bufi) ; i++) if (bufi[i]==',') bufi[i]='_';
 } else cp=index_name;
 printf("\nCreate Index: %s\n",cp);
 sprintf(sqlt, "create index %s on %s(%s) ",cp,table,field);
 mysql_query(mysql,sqlt);
}

void Mybind (MYSQL_BIND *array,int *row,void *variable, int length,
 #ifdef __cplusplus
  enum_field_types type,
 #else 
  int type,
 #endif
  struct my_nu *my_null) {
  array[*row].buffer=(char*)variable;
  if (type==FIELD_TYPE_STRING || type==FIELD_TYPE_VAR_STRING) { 
   my_null[*row].length=array[*row].buffer_length=length;
  } 
  array[(*row)++].buffer_type=type;
}

static void print_st_error(MYSQL_STMT *stmt, const char *msg) {
 if (stmt && mysql_stmt_errno(stmt))  {
   if (stmt->mysql && stmt->mysql->server_version)
     fprintf(stdout," [MySQL-%s]\n",stmt->mysql->server_version);
   else fprintf(stdout," [MySQL]\n ");
   fprintf(stdout,"[%d] %s\n",mysql_stmt_errno(stmt),mysql_stmt_error(stmt));
 } else if (msg) fprintf(stderr, " [MySQL] %s\n", msg);
}

int Mysql_Execute (MYSQL_STMT *stmt,char *text) {int error;
 if ((error=mysql_execute(stmt))) print_st_error(stmt, text);
 return error;
}

int Mysql_Fetch (MYSQL_STMT *stmt,char *text) { int error;
 if ((error = mysql_fetch(stmt))!=MYSQL_NO_DATA) {
  if (error) print_st_error(stmt,text);
 }
 return error;
}

void NuTo (MYSQL_BIND *my_bind,struct my_nu *my_null,int from,int to) {
 for (;from<to;from++) {
  my_bind[from].is_null=&my_null[from].is_null; my_bind[from].length=&my_null[from].length;
  my_null[from].is_null=0;
 }
}

void Mysql_Error (MYSQL *mysql,char *text) {
 printf("%s Error: %s\n",text,mysql_error(mysql));
 exit(0);
}

void ClientConnect(MYSQL **mysql,char *mysql_host,char *mysql_userid, char *mysql_passwd,char *mysql_db,int mysql_port) {  
  printf(" -- Establishing a connection to '%s' ...\n",mysql_host );
 if (!(*mysql = mysql_init(NULL))) { printf(" -- mysql_init() failed\n");}
 if (!(mysql_real_connect(*mysql,mysql_host,mysql_userid,mysql_passwd,mysql_db ,mysql_port,NULL,0))) {
  printf(" -- connection failed\n"); mysql_close(*mysql);
  printf(" -- Check the connection options using --help or -?\n");
 }
}

void Mysql_Query (MYSQL *mysql,char *query_str) {
 printf(" -- Mysql_Query\n");
 if (mysql_query(mysql, query_str))
 {
  printf(" -- Rossz query In\n");
  printf(" -- [%d] %s\n",mysql_errno(mysql),mysql_error(mysql));
 }
}

void MyPrepareIn (MYSQL *mysql,char *query_str,MYSQL_STMT **stmt ,MYSQL_BIND *my_bind) {
 printf(" -- MyPrepareIn\n");
 if (!(*stmt = mysql_prepare(mysql, query_str, strlen(query_str)))) 
 {
  printf(" -- Rossz prepare In\n");
  printf(" -- [%d] %s\n",mysql_errno(mysql),mysql_error(mysql));
 }
 if (mysql_bind_result(*stmt, my_bind)){printf(" -- Rossz bind result In\n");}
 if (mysql_execute(*stmt)) 
 {
  printf(" -- execute In failed %s\n",mysql_stmt_error(*stmt));
  fprintf(stdout," -- [%d] %s\n",mysql_errno(mysql),mysql_error(mysql));
 }
}

void MyPrepareOut (MYSQL *mysql,char *query_str,MYSQL_STMT **stmt,MYSQL_BIND *my_bind) {
 if (!(*stmt = mysql_prepare(mysql, query_str, strlen(query_str)))) {
  printf("\nRossz prepare Out\n");
  fprintf(stdout,"[%d] %s\n",mysql_errno(mysql),mysql_error(mysql));
  fprintf(stdout,"characterset = %s\n",mysql_character_set_name(mysql));
 }
 if (mysql_bind_param(*stmt, my_bind)) printf("Rossz bind result Out");
 fprintf(stdout,"[%d] %s\n",mysql_errno(mysql),mysql_error(mysql));
}

/* utils */

byte const mon[13]={0,31,29,31,30,31,30,31,31,30,31,30,31};

void GetXDate (MYSQL_TIME *rd) {  struct tm tm; time_t now;
 now=time((time_t*)NULL); tm=*localtime(&now);
 rd->year=tm.tm_year; rd->month=tm.tm_mon+1; rd->day=tm.tm_mday;
}

int CompSdat (MYSQL_TIME *tol,MYSQL_TIME *ig) { long l1,l2;
 l1=tol->year*10000+tol->month*100+tol->day;
 l2=ig->year*10000+ig->month*100+ig->day;
 if (l1==l2) return 0;
 return ((l1>l2) ? 1:-1);
}

int Days (MYSQL_TIME *tol,MYSQL_TIME *ig) {
 int j,nap=0; MYSQL_TIME seg; unsigned char bmo[sizeof(mon) / sizeof(mon[0])];
 memcpy(bmo,mon,sizeof(bmo));
 if (CompSdat(tol,ig)>0) return 0;
 if (tol->year<ig->year) {
  if (tol->year&3) bmo[2]=28;
  nap=bmo[tol->month]-tol->day+1;
  for (j=tol->month+1; j<13; j++) nap+=bmo[j];
  for (j=tol->year+1; j<ig->year; j++) nap+=(j&3) ? 365:366;
  seg.year=ig->year;seg.month=seg.day=1;
 }
 else seg=*tol;
 if (seg.month<ig->month) {
  bmo[2]=(ig->year&3) ? 28:29;
  nap+=bmo[seg.month]-seg.day+1;
  for (j=seg.month+1; j<ig->month; j++) nap+=bmo[j];
  seg.day=1;
 }
 nap+=ig->day-seg.day;
 return nap;
}
/* utils end */

How to repeat:
run this example bellow

Suggested fix:
... develope .-)
[27 Feb 2004 2:21] Gergo Bacskai
make.sh

Attachment: make (text/plain), 193 bytes.

[27 Feb 2004 2:21] Gergo Bacskai
upc_functions.c

Attachment: upc_functions.c (application/octet-stream, text), 6.04 KiB.

[27 Feb 2004 2:21] Gergo Bacskai
upc_functions.h

Attachment: upc_functions.h (application/octet-stream, text), 1.23 KiB.

[27 Feb 2004 2:22] Gergo Bacskai
I have uploaded all the files ....
[27 Feb 2004 2:23] Gergo Bacskai
please remove the sources from the first comment !
[25 Mar 2004 11:21] Dean Ellis
Verified against 4.1.2-alpha-log with a smaller but similar test case.  Thank you.
[24 May 2004 0:17] Konstantin Osipov
Dean, Gergo,

besides possible libmysql bug, you should always bzero all structures supplied to the API.
This is not an issue for MYSQL_STMT, as it's created inside the API, but is critical
for MYSQL_BIND and MYSQL_TIME, which have internal/not-used-in-your-case members.
Yes, I know that this haven't been documented yet, and we probably should add a special 
call to create such kinds of structures.
[25 May 2004 0:50] Konstantin Osipov
I run the test case against latest MySQL 4.1 tree and wasn't able to repeat the bug (assuming that all MYSQL_BIND and MYSQL_TIME structures were properly initialized).
Without bzero() of MYSQL_TIME structe the test indeed crash, but not crash the server.

If you still consider this a bug, please reopen this bug report.