Commit 0c58737a authored by unknown's avatar unknown
Browse files

A fix and test case for Bug#4231 "Wrong result with MYSQL_TIME

parameters": when unpacking binary time recieved from client, handle
the case when length is 0: it means all MYSQL_TIME members are zero.


include/my_time.h:
  Declaration for set_zero_time: a tiny piece of code, which I
  see no reason to not reuse.
libmysql/libmysql.c:
  set_zero_time implementation is now shared between client and
  server.
sql-common/my_time.c:
  set_zero_time implementation added.
sql/sql_prepare.cc:
  A fix for Bug#4231 "Wrong result with MYSQL_TIME parameters": 
  when unpacking binary time recieved from client, handle the
  case when length is 0: it means all MYSQL_TIME members are zero.
tests/client_test.c:
  Test case for bug#4231 "Wrong result with MYSQL_TIME parameters"
parent 3c3db073
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -58,6 +58,8 @@ void init_time(void);
my_time_t 
my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone, bool *in_dst_time_gap);

void set_zero_time(MYSQL_TIME *tm);

C_MODE_END

#endif /* _my_time_h_ */
+0 −7
Original line number Diff line number Diff line
@@ -3167,13 +3167,6 @@ mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number,
 Fetch and conversion of result set rows (binary protocol).
*********************************************************************/

static void set_zero_time(MYSQL_TIME *tm)
{
  bzero((void *)tm, sizeof(*tm));
  tm->time_type= MYSQL_TIMESTAMP_NONE;
}


/*
  Read date, (time, datetime) value from network buffer and store it
  in MYSQL_TIME structure.
+10 −0
Original line number Diff line number Diff line
@@ -716,3 +716,13 @@ my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone, bool *in_dst_time_gap)
  
  return (my_time_t) tmp;
} /* my_system_gmt_sec */


/* Set MYSQL_TIME structure to 0000-00-00 00:00:00.000000 */

void set_zero_time(MYSQL_TIME *tm)
{
  bzero((void*) tm, sizeof(*tm));
  tm->time_type= MYSQL_TIMESTAMP_NONE;
}
+30 −20
Original line number Diff line number Diff line
@@ -329,15 +329,22 @@ static void set_param_double(Item_param *param, uchar **pos, ulong len)
}

#ifndef EMBEDDED_LIBRARY

/*
  Read date/time/datetime parameter values from network (binary
  protocol). See writing counterparts of these functions in
  libmysql.c (store_param_{time,date,datetime}).
*/

static void set_param_time(Item_param *param, uchar **pos, ulong len)
{
  ulong length;
  uint day;
  MYSQL_TIME tm;
  ulong length= get_param_length(pos, len);

  if ((length= get_param_length(pos, len)) >= 8)
  if (length >= 8)
  {
    uchar *to= *pos;
    TIME  tm;
    uint day;

    tm.neg= (bool) to[0];
    day= (uint) sint4korr(to+1);
@@ -359,21 +366,22 @@ static void set_param_time(Item_param *param, uchar **pos, ulong len)
      tm.second= 59;
    }
    tm.day= tm.year= tm.month= 0;

  }
  else
    set_zero_time(&tm);
  param->set_time(&tm, MYSQL_TIMESTAMP_TIME,
                  MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
  }
  *pos+= length;
}

static void set_param_datetime(Item_param *param, uchar **pos, ulong len)
{
  uint length;
  MYSQL_TIME tm;
  ulong length= get_param_length(pos, len);

  if ((length= get_param_length(pos, len)) >= 4)
  if (length >= 4)
  {
    uchar *to= *pos;
    TIME  tm;

    tm.neg=    0;
    tm.year=   (uint) sint2korr(to);
@@ -394,21 +402,22 @@ static void set_param_datetime(Item_param *param, uchar **pos, ulong len)
      tm.hour= tm.minute= tm.second= 0;

    tm.second_part= (length > 7) ? (ulong) sint4korr(to+7) : 0;

  }
  else
    set_zero_time(&tm);
  param->set_time(&tm, MYSQL_TIMESTAMP_DATETIME,
                  MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
  }
  *pos+= length;
}

static void set_param_date(Item_param *param, uchar **pos, ulong len)
{
  ulong length;
  MYSQL_TIME tm;
  ulong length= get_param_length(pos, len);

  if ((length= get_param_length(pos, len)) >= 4)
  if (length >= 4)
  {
    uchar *to= *pos;
    TIME tm;
    /*
      Note, that though ranges of hour, minute and second are not checked
      here we rely on them being < 256: otherwise
@@ -421,10 +430,11 @@ static void set_param_date(Item_param *param, uchar **pos, ulong len)
    tm.hour= tm.minute= tm.second= 0;
    tm.second_part= 0;
    tm.neg= 0;

  }
  else
    set_zero_time(&tm);
  param->set_time(&tm, MYSQL_TIMESTAMP_DATE,
                  MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
  }
  *pos+= length;
}

+74 −0
Original line number Diff line number Diff line
@@ -10091,6 +10091,78 @@ static void test_bug5126()
}


static void test_bug4231()
{
  MYSQL_STMT *stmt;
  MYSQL_BIND bind[2];
  MYSQL_TIME tm[2];
  const char *stmt_text;
  int rc;

  myheader("test_bug4231");

  stmt_text= "DROP TABLE IF EXISTS t1";
  rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
  myquery(rc);

  stmt_text= "CREATE TABLE t1 (a int)";
  rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
  myquery(rc);

  stmt_text= "INSERT INTO t1 VALUES (1)";
  rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
  myquery(rc);

  stmt= mysql_stmt_init(mysql);
  stmt_text= "SELECT a FROM t1 WHERE ? = ?";
  rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
  check_execute(stmt, rc);

  /* Bind input buffers */
  bzero(bind, sizeof(bind));
  bzero(tm, sizeof(tm));

  bind[0].buffer_type= MYSQL_TYPE_TIME;
  bind[0].buffer= (void*) tm;
  bind[1].buffer_type= MYSQL_TYPE_TIME;
  bind[1].buffer= (void*) tm+1;

  mysql_stmt_bind_param(stmt, bind);
  check_execute(stmt, rc);

  /*
    First set server-side params to some non-zero non-equal values:
    then we will check that they are not used when client sends
    new (zero) times.
  */
  tm[0].time_type = MYSQL_TIMESTAMP_DATE;
  tm[0].year = 2000;
  tm[0].month = 1;
  tm[0].day = 1;
  tm[1]= tm[0];
  --tm[1].year;                                 /* tm[0] != tm[1] */

  rc= mysql_stmt_execute(stmt);
  check_execute(stmt, rc);

  rc= mysql_stmt_fetch(stmt);

  /* binds are unequal, no rows should be returned */
  DBUG_ASSERT(rc == MYSQL_NO_DATA);

  /* Set one of the dates to zero */
  tm[0].year= tm[0].month= tm[0].day= 0;
  tm[1]= tm[1];
  mysql_stmt_execute(stmt);
  rc= mysql_stmt_fetch(stmt);
  DBUG_ASSERT(rc == 0);

  mysql_stmt_close(stmt);
  stmt_text= "DROP TABLE t1";
  rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
  myquery(rc);
}

/*
  Read and parse arguments and MySQL options from my.cnf
*/
@@ -10389,6 +10461,8 @@ int main(int argc, char **argv)
    test_bug4030();         /* test conversion string -> time types in
                               libmysql */
    test_bug5126();         /* support for mediumint type in libmysql */
    test_bug4231();         /* proper handling of all-zero times and
                               dates in the server */
    /*
      XXX: PLEASE RUN THIS PROGRAM UNDER VALGRIND AND VERIFY THAT YOUR TEST
      DOESN'T CONTAIN WARNINGS/ERRORS BEFORE YOU PUSH.