mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
Proposed fix for Bug#4026 "Microseconds part of TIME/DATETIME types
is broken (prepared statements)": fixed date handling in many places of prepared statements code.
This commit is contained in:
parent
dabc0e774e
commit
dc11d3cfa1
7 changed files with 214 additions and 56 deletions
|
@ -1667,6 +1667,27 @@ static int stmt_read_row_buffered(MYSQL_STMT *stmt, unsigned char **row);
|
|||
static int stmt_read_row_no_data(MYSQL_STMT *stmt, unsigned char **row);
|
||||
|
||||
|
||||
/*
|
||||
Maximum sizes of MYSQL_TYPE_DATE, MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME
|
||||
values stored in network buffer.
|
||||
*/
|
||||
|
||||
/* 1 (length) + 2 (year) + 1 (month) + 1 (day) */
|
||||
static const unsigned MAX_DATE_REP_LENGTH= 5;
|
||||
|
||||
/*
|
||||
1 (length) + 1 (is negative) + 4 (day count) + 1 (hour)
|
||||
+ 1 (minute) + 1 (seconds) + 4 (microseconds)
|
||||
*/
|
||||
static const unsigned MAX_TIME_REP_LENGTH= 13;
|
||||
|
||||
/*
|
||||
1 (length) + 2 (year) + 1 (month) + 1 (day) +
|
||||
1 (hour) + 1 (minute) + 1 (second) + 4 (microseconds)
|
||||
*/
|
||||
static const unsigned MAX_DATETIME_REP_LENGTH= 12;
|
||||
|
||||
|
||||
/**************** Misc utility functions ****************************/
|
||||
|
||||
/*
|
||||
|
@ -2030,6 +2051,30 @@ static unsigned int alloc_stmt_fields(MYSQL_STMT *stmt)
|
|||
return stmt->field_count;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Update result set columns metadata if it was sent again in
|
||||
reply to COM_EXECUTE.
|
||||
*/
|
||||
|
||||
static void update_stmt_fields(MYSQL_STMT *stmt)
|
||||
{
|
||||
MYSQL_FIELD *field= stmt->mysql->fields;
|
||||
MYSQL_FIELD *field_end= field + stmt->field_count;
|
||||
MYSQL_FIELD *stmt_field= stmt->fields;
|
||||
|
||||
DBUG_ASSERT(stmt->field_count == stmt->mysql->field_count);
|
||||
|
||||
for (; field < field_end; ++field, ++stmt_field)
|
||||
{
|
||||
stmt_field->charsetnr= field->charsetnr;
|
||||
stmt_field->length = field->length;
|
||||
stmt_field->type = field->type;
|
||||
stmt_field->flags = field->flags;
|
||||
stmt_field->decimals = field->decimals;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Returns prepared statement metadata in the form of a result set.
|
||||
|
||||
|
@ -2166,7 +2211,7 @@ static void store_param_double(NET *net, MYSQL_BIND *param)
|
|||
static void store_param_time(NET *net, MYSQL_BIND *param)
|
||||
{
|
||||
MYSQL_TIME *tm= (MYSQL_TIME *) param->buffer;
|
||||
char buff[15], *pos;
|
||||
char buff[MAX_TIME_REP_LENGTH], *pos;
|
||||
uint length;
|
||||
|
||||
pos= buff+1;
|
||||
|
@ -2177,7 +2222,7 @@ static void store_param_time(NET *net, MYSQL_BIND *param)
|
|||
pos[7]= (uchar) tm->second;
|
||||
int4store(pos+8, tm->second_part);
|
||||
if (tm->second_part)
|
||||
length= 11;
|
||||
length= 12;
|
||||
else if (tm->hour || tm->minute || tm->second || tm->day)
|
||||
length= 8;
|
||||
else
|
||||
|
@ -2189,7 +2234,7 @@ static void store_param_time(NET *net, MYSQL_BIND *param)
|
|||
|
||||
static void net_store_datetime(NET *net, MYSQL_TIME *tm)
|
||||
{
|
||||
char buff[12], *pos;
|
||||
char buff[MAX_DATETIME_REP_LENGTH], *pos;
|
||||
uint length;
|
||||
|
||||
pos= buff+1;
|
||||
|
@ -2280,7 +2325,7 @@ static my_bool store_param(MYSQL_STMT *stmt, MYSQL_BIND *param)
|
|||
Param->length should ALWAYS point to the correct length for the type
|
||||
Either to the length pointer given by the user or param->buffer_length
|
||||
*/
|
||||
if ((my_realloc_str(net, 9 + *param->length)))
|
||||
if ((my_realloc_str(net, *param->length)))
|
||||
{
|
||||
set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate);
|
||||
DBUG_RETURN(1);
|
||||
|
@ -2557,16 +2602,37 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt)
|
|||
*/
|
||||
if (mysql->methods->stmt_execute(stmt))
|
||||
DBUG_RETURN(1);
|
||||
if (!stmt->field_count && mysql->field_count)
|
||||
if (mysql->field_count)
|
||||
{
|
||||
/*
|
||||
This is 'SHOW'/'EXPLAIN'-like query. Current implementation of
|
||||
prepared statements can't send result set metadata for this queries
|
||||
on prepare stage. Read it now.
|
||||
*/
|
||||
alloc_stmt_fields(stmt);
|
||||
/* Server has sent result set metadata */
|
||||
if (stmt->field_count == 0)
|
||||
{
|
||||
/*
|
||||
This is 'SHOW'/'EXPLAIN'-like query. Current implementation of
|
||||
prepared statements can't send result set metadata for these queries
|
||||
on prepare stage. Read it now.
|
||||
*/
|
||||
alloc_stmt_fields(stmt);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
Update result set metadata if it for some reason changed between
|
||||
prepare and execute, i.e.:
|
||||
- in case of 'SELECT ?' we don't know column type unless data was
|
||||
supplied to mysql_stmt_execute, so updated column type is sent
|
||||
now.
|
||||
- if data dictionary changed between prepare and execute, for
|
||||
example a table used in the query was altered.
|
||||
Note, that now (4.1.3) we always send metadata in reply to
|
||||
COM_EXECUTE (even if it is not necessary), so either this or
|
||||
previous always branch works.
|
||||
TODO: send metadata only when it's really necessary and add a warning
|
||||
'Metadata changed' when it's sent twice.
|
||||
*/
|
||||
update_stmt_fields(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
stmt->state= MYSQL_STMT_EXECUTE_DONE;
|
||||
if (stmt->field_count)
|
||||
{
|
||||
|
@ -2693,15 +2759,17 @@ my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND * bind)
|
|||
param->store_param_func= store_param_double;
|
||||
break;
|
||||
case MYSQL_TYPE_TIME:
|
||||
/* Buffer length ignored for DATE, TIME and DATETIME */
|
||||
param->store_param_func= store_param_time;
|
||||
param->buffer_length= MAX_TIME_REP_LENGTH;
|
||||
break;
|
||||
case MYSQL_TYPE_DATE:
|
||||
param->store_param_func= store_param_date;
|
||||
param->buffer_length= MAX_DATE_REP_LENGTH;
|
||||
break;
|
||||
case MYSQL_TYPE_DATETIME:
|
||||
case MYSQL_TYPE_TIMESTAMP:
|
||||
param->store_param_func= store_param_datetime;
|
||||
param->buffer_length= MAX_DATETIME_REP_LENGTH;
|
||||
break;
|
||||
case MYSQL_TYPE_TINY_BLOB:
|
||||
case MYSQL_TYPE_MEDIUM_BLOB:
|
||||
|
@ -2861,15 +2929,15 @@ static uint read_binary_time(MYSQL_TIME *tm, uchar **pos)
|
|||
}
|
||||
|
||||
to= *pos;
|
||||
tm->second_part= (length > 8 ) ? (ulong) sint4korr(to+7): 0;
|
||||
tm->neg= (bool) to[0];
|
||||
|
||||
tm->day= (ulong) sint4korr(to+1);
|
||||
tm->hour= (uint) to[5];
|
||||
tm->minute= (uint) to[6];
|
||||
tm->second= (uint) to[7];
|
||||
tm->second_part= (length > 8) ? (ulong) sint4korr(to+8) : 0;
|
||||
|
||||
tm->year= tm->month= 0;
|
||||
tm->neg= (bool)to[0];
|
||||
return length;
|
||||
}
|
||||
|
||||
|
@ -2886,7 +2954,11 @@ static uint read_binary_datetime(MYSQL_TIME *tm, uchar **pos)
|
|||
}
|
||||
|
||||
to= *pos;
|
||||
tm->second_part= (length > 7 ) ? (ulong) sint4korr(to+7): 0;
|
||||
|
||||
tm->neg= 0;
|
||||
tm->year= (uint) sint2korr(to);
|
||||
tm->month= (uint) to[2];
|
||||
tm->day= (uint) to[3];
|
||||
|
||||
if (length > 4)
|
||||
{
|
||||
|
@ -2896,11 +2968,7 @@ static uint read_binary_datetime(MYSQL_TIME *tm, uchar **pos)
|
|||
}
|
||||
else
|
||||
tm->hour= tm->minute= tm->second= 0;
|
||||
|
||||
tm->year= (uint) sint2korr(to);
|
||||
tm->month= (uint) to[2];
|
||||
tm->day= (uint) to[3];
|
||||
tm->neg= 0;
|
||||
tm->second_part= (length > 7) ? (ulong) sint4korr(to+7) : 0;
|
||||
return length;
|
||||
}
|
||||
|
||||
|
|
12
sql/item.cc
12
sql/item.cc
|
@ -629,6 +629,7 @@ Item_param::Item_param(unsigned pos_in_query_arg) :
|
|||
state(NO_VALUE),
|
||||
item_result_type(STRING_RESULT),
|
||||
item_type(STRING_ITEM),
|
||||
param_type(MYSQL_TYPE_STRING),
|
||||
pos_in_query(pos_in_query_arg),
|
||||
set_param_func(default_set_param_func)
|
||||
{
|
||||
|
@ -808,6 +809,17 @@ bool Item_param::get_time(TIME *res)
|
|||
}
|
||||
|
||||
|
||||
bool Item_param::get_date(TIME *res, uint fuzzydate)
|
||||
{
|
||||
if (state == TIME_VALUE)
|
||||
{
|
||||
*res= value.time;
|
||||
return 0;
|
||||
}
|
||||
return Item::get_date(res, fuzzydate);
|
||||
}
|
||||
|
||||
|
||||
double Item_param::val()
|
||||
{
|
||||
switch (state) {
|
||||
|
|
13
sql/item.h
13
sql/item.h
|
@ -465,6 +465,16 @@ public:
|
|||
/* Cached values for virtual methods to save us one switch. */
|
||||
enum Item_result item_result_type;
|
||||
enum Type item_type;
|
||||
|
||||
/*
|
||||
Used when this item is used in a temporary table.
|
||||
This is NOT placeholder metadata sent to client, as this value
|
||||
is assigned after sending metadata (in setup_one_conversion_function).
|
||||
For example in case of 'SELECT ?' you'll get MYSQL_TYPE_STRING both
|
||||
in result set and placeholders metadata, no matter what type you will
|
||||
supply for this placeholder in mysql_stmt_execute.
|
||||
*/
|
||||
enum enum_field_types param_type;
|
||||
/*
|
||||
Offset of placeholder inside statement text. Used to create
|
||||
no-placeholders version of this statement for the binary log.
|
||||
|
@ -475,12 +485,13 @@ public:
|
|||
|
||||
enum Item_result result_type () const { return item_result_type; }
|
||||
enum Type type() const { return item_type; }
|
||||
enum_field_types field_type() const { return MYSQL_TYPE_STRING; }
|
||||
enum_field_types field_type() const { return param_type; }
|
||||
|
||||
double val();
|
||||
longlong val_int();
|
||||
String *val_str(String*);
|
||||
bool get_time(TIME *tm);
|
||||
bool get_date(TIME *tm, uint fuzzydate);
|
||||
int save_in_field(Field *field, bool no_conversions);
|
||||
|
||||
void set_null();
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include "mysql_priv.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;
|
||||
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
bool Protocol::net_store_data(const char *from, uint length)
|
||||
#else
|
||||
|
@ -687,7 +689,7 @@ bool Protocol_simple::store_null()
|
|||
#endif
|
||||
char buff[1];
|
||||
buff[0]= (char)251;
|
||||
return packet->append(buff, sizeof(buff), PACKET_BUFFET_EXTRA_ALLOC);
|
||||
return packet->append(buff, sizeof(buff), PACKET_BUFFER_EXTRA_ALLOC);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -990,7 +992,7 @@ bool Protocol_prep::store_tiny(longlong from)
|
|||
char buff[1];
|
||||
field_pos++;
|
||||
buff[0]= (uchar) from;
|
||||
return packet->append(buff, sizeof(buff), PACKET_BUFFET_EXTRA_ALLOC);
|
||||
return packet->append(buff, sizeof(buff), PACKET_BUFFER_EXTRA_ALLOC);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1002,7 +1004,7 @@ bool Protocol_prep::store_short(longlong from)
|
|||
field_types[field_pos] == MYSQL_TYPE_YEAR);
|
||||
#endif
|
||||
field_pos++;
|
||||
char *to= packet->prep_append(2, PACKET_BUFFET_EXTRA_ALLOC);
|
||||
char *to= packet->prep_append(2, PACKET_BUFFER_EXTRA_ALLOC);
|
||||
if (!to)
|
||||
return 1;
|
||||
int2store(to, (int) from);
|
||||
|
@ -1018,7 +1020,7 @@ bool Protocol_prep::store_long(longlong from)
|
|||
field_types[field_pos] == MYSQL_TYPE_LONG);
|
||||
#endif
|
||||
field_pos++;
|
||||
char *to= packet->prep_append(4, PACKET_BUFFET_EXTRA_ALLOC);
|
||||
char *to= packet->prep_append(4, PACKET_BUFFER_EXTRA_ALLOC);
|
||||
if (!to)
|
||||
return 1;
|
||||
int4store(to, from);
|
||||
|
@ -1033,7 +1035,7 @@ bool Protocol_prep::store_longlong(longlong from, bool unsigned_flag)
|
|||
field_types[field_pos] == MYSQL_TYPE_LONGLONG);
|
||||
#endif
|
||||
field_pos++;
|
||||
char *to= packet->prep_append(8, PACKET_BUFFET_EXTRA_ALLOC);
|
||||
char *to= packet->prep_append(8, PACKET_BUFFER_EXTRA_ALLOC);
|
||||
if (!to)
|
||||
return 1;
|
||||
int8store(to, from);
|
||||
|
@ -1048,7 +1050,7 @@ bool Protocol_prep::store(float from, uint32 decimals, String *buffer)
|
|||
field_types[field_pos] == MYSQL_TYPE_FLOAT);
|
||||
#endif
|
||||
field_pos++;
|
||||
char *to= packet->prep_append(4, PACKET_BUFFET_EXTRA_ALLOC);
|
||||
char *to= packet->prep_append(4, PACKET_BUFFER_EXTRA_ALLOC);
|
||||
if (!to)
|
||||
return 1;
|
||||
float4store(to, from);
|
||||
|
@ -1063,7 +1065,7 @@ bool Protocol_prep::store(double from, uint32 decimals, String *buffer)
|
|||
field_types[field_pos] == MYSQL_TYPE_DOUBLE);
|
||||
#endif
|
||||
field_pos++;
|
||||
char *to= packet->prep_append(8, PACKET_BUFFET_EXTRA_ALLOC);
|
||||
char *to= packet->prep_append(8, PACKET_BUFFER_EXTRA_ALLOC);
|
||||
if (!to)
|
||||
return 1;
|
||||
float8store(to, from);
|
||||
|
@ -1112,7 +1114,7 @@ bool Protocol_prep::store(TIME *tm)
|
|||
else
|
||||
length=0;
|
||||
buff[0]=(char) length; // Length is stored first
|
||||
return packet->append(buff, length+1, PACKET_BUFFET_EXTRA_ALLOC);
|
||||
return packet->append(buff, length+1, PACKET_BUFFER_EXTRA_ALLOC);
|
||||
}
|
||||
|
||||
bool Protocol_prep::store_date(TIME *tm)
|
||||
|
@ -1129,7 +1131,7 @@ bool Protocol_prep::store_time(TIME *tm)
|
|||
DBUG_ASSERT(field_types == 0 ||
|
||||
field_types[field_pos] == MYSQL_TYPE_TIME);
|
||||
#endif
|
||||
char buff[15],*pos;
|
||||
char buff[13], *pos;
|
||||
uint length;
|
||||
field_pos++;
|
||||
pos= buff+1;
|
||||
|
@ -1140,13 +1142,13 @@ bool Protocol_prep::store_time(TIME *tm)
|
|||
pos[7]= (uchar) tm->second;
|
||||
int4store(pos+8, tm->second_part);
|
||||
if (tm->second_part)
|
||||
length=11;
|
||||
length=12;
|
||||
else if (tm->hour || tm->minute || tm->second || tm->day)
|
||||
length=8;
|
||||
else
|
||||
length=0;
|
||||
buff[0]=(char) length; // Length is stored first
|
||||
return packet->append(buff, length+1, PACKET_BUFFET_EXTRA_ALLOC);
|
||||
return packet->append(buff, length+1, PACKET_BUFFER_EXTRA_ALLOC);
|
||||
}
|
||||
|
||||
#ifdef EMBEDDED_LIBRARY
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#pragma interface /* gcc class implementation */
|
||||
#endif
|
||||
|
||||
#define PACKET_BUFFET_EXTRA_ALLOC 1024
|
||||
|
||||
class i_string;
|
||||
class THD;
|
||||
|
|
|
@ -333,19 +333,18 @@ static void set_param_time(Item_param *param, uchar **pos, ulong len)
|
|||
uchar *to= *pos;
|
||||
TIME tm;
|
||||
|
||||
/* TODO: why length is compared with 8 here? */
|
||||
tm.second_part= (length > 8 ) ? (ulong) sint4korr(to+7): 0;
|
||||
|
||||
tm.neg= (bool) to[0];
|
||||
day= (uint) sint4korr(to+1);
|
||||
/*
|
||||
Note, that though ranges of hour, minute and second are not checked
|
||||
here we rely on them being < 256: otherwise
|
||||
we'll get buffer overflow in make_{date,time} functions,
|
||||
which are called when time value is converted to string.
|
||||
*/
|
||||
day= (uint) sint4korr(to+1);
|
||||
tm.hour= (uint) to[5] + day * 24;
|
||||
tm.minute= (uint) to[6];
|
||||
tm.second= (uint) to[7];
|
||||
tm.second_part= (length > 8) ? (ulong) sint4korr(to+8) : 0;
|
||||
if (tm.hour > 838)
|
||||
{
|
||||
/* TODO: add warning 'Data truncated' here */
|
||||
|
@ -354,7 +353,6 @@ static void set_param_time(Item_param *param, uchar **pos, ulong len)
|
|||
tm.second= 59;
|
||||
}
|
||||
tm.day= tm.year= tm.month= 0;
|
||||
tm.neg= (bool)to[0];
|
||||
|
||||
param->set_time(&tm, TIMESTAMP_TIME,
|
||||
MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
|
||||
|
@ -371,8 +369,10 @@ static void set_param_datetime(Item_param *param, uchar **pos, ulong len)
|
|||
uchar *to= *pos;
|
||||
TIME tm;
|
||||
|
||||
tm.second_part= (length > 7 ) ? (ulong) sint4korr(to+7): 0;
|
||||
|
||||
tm.neg= 0;
|
||||
tm.year= (uint) sint2korr(to);
|
||||
tm.month= (uint) to[2];
|
||||
tm.day= (uint) to[3];
|
||||
/*
|
||||
Note, that though ranges of hour, minute and second are not checked
|
||||
here we rely on them being < 256: otherwise
|
||||
|
@ -387,10 +387,7 @@ static void set_param_datetime(Item_param *param, uchar **pos, ulong len)
|
|||
else
|
||||
tm.hour= tm.minute= tm.second= 0;
|
||||
|
||||
tm.year= (uint) sint2korr(to);
|
||||
tm.month= (uint) to[2];
|
||||
tm.day= (uint) to[3];
|
||||
tm.neg= 0;
|
||||
tm.second_part= (length > 7) ? (ulong) sint4korr(to+7) : 0;
|
||||
|
||||
param->set_time(&tm, TIMESTAMP_DATETIME,
|
||||
MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
|
||||
|
@ -585,6 +582,7 @@ static void setup_one_conversion_function(THD *thd, Item_param *param,
|
|||
param->item_result_type= STRING_RESULT;
|
||||
}
|
||||
}
|
||||
param->param_type= (enum enum_field_types) param_type;
|
||||
}
|
||||
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
|
|
|
@ -9802,6 +9802,73 @@ static void test_bug3796()
|
|||
myquery(rc);
|
||||
}
|
||||
|
||||
|
||||
static void test_bug4026()
|
||||
{
|
||||
MYSQL_STMT *stmt;
|
||||
MYSQL_BIND bind[2];
|
||||
MYSQL_TIME time_in, time_out;
|
||||
MYSQL_TIME datetime_in, datetime_out;
|
||||
const char *stmt_text;
|
||||
int rc;
|
||||
|
||||
myheader("test_bug4026");
|
||||
|
||||
/* Check that microseconds are inserted and selected successfully */
|
||||
|
||||
/* Create a statement handle and prepare it with select */
|
||||
stmt= mysql_stmt_init(mysql);
|
||||
stmt_text= "SELECT ?, ?";
|
||||
|
||||
rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
|
||||
check_execute(stmt, rc);
|
||||
|
||||
/* Bind input buffers */
|
||||
bzero(bind, sizeof(bind));
|
||||
bzero(&time_in, sizeof(time_in));
|
||||
bzero(&time_out, sizeof(time_out));
|
||||
bzero(&datetime_in, sizeof(datetime_in));
|
||||
bzero(&datetime_out, sizeof(datetime_out));
|
||||
|
||||
bind[0].buffer_type= MYSQL_TYPE_TIME;
|
||||
bind[0].buffer= (char*) &time_in;
|
||||
bind[1].buffer_type= MYSQL_TYPE_DATETIME;
|
||||
bind[1].buffer= (char*) &datetime_in;
|
||||
|
||||
time_in.hour= 23;
|
||||
time_in.minute= 59;
|
||||
time_in.second= 59;
|
||||
time_in.second_part= 123456;
|
||||
|
||||
datetime_in= time_in;
|
||||
datetime_in.year= 2003;
|
||||
datetime_in.month= 12;
|
||||
datetime_in.day= 31;
|
||||
|
||||
mysql_stmt_bind_param(stmt, bind);
|
||||
|
||||
/* Execute the select statement */
|
||||
rc= mysql_stmt_execute(stmt);
|
||||
check_execute(stmt, rc);
|
||||
|
||||
bind[0].buffer= (char*) &time_out;
|
||||
bind[1].buffer= (char*) &datetime_out;
|
||||
|
||||
mysql_stmt_bind_result(stmt, bind);
|
||||
|
||||
rc= mysql_stmt_fetch(stmt);
|
||||
assert(rc == 0);
|
||||
printf("%d:%d:%d.%lu\n", time_out.hour, time_out.minute, time_out.second,
|
||||
time_out.second_part);
|
||||
printf("%d-%d-%d %d:%d:%d.%lu\n", datetime_out.year, datetime_out.month,
|
||||
datetime_out.day, datetime_out.hour,
|
||||
datetime_out.minute, datetime_out.second,
|
||||
datetime_out.second_part);
|
||||
assert(memcmp(&time_in, &time_out, sizeof(time_in)) == 0);
|
||||
assert(memcmp(&datetime_in, &datetime_out, sizeof(datetime_in)) == 0);
|
||||
mysql_stmt_close(stmt);
|
||||
}
|
||||
|
||||
/*
|
||||
Read and parse arguments and MySQL options from my.cnf
|
||||
*/
|
||||
|
@ -10094,6 +10161,7 @@ int main(int argc, char **argv)
|
|||
(Bug #3686 */
|
||||
test_ps_i18n(); /* test for i18n support in binary protocol */
|
||||
test_bug3796(); /* test for select concat(?, <string>) */
|
||||
test_bug4026(); /* test microseconds precision of time types */
|
||||
/*
|
||||
XXX: PLEASE RUN THIS PROGRAM UNDER VALGRIND AND VERIFY THAT YOUR TEST
|
||||
DOESN'T CONTAIN WARNINGS/ERRORS BEFORE YOU PUSH.
|
||||
|
|
Loading…
Reference in a new issue