Commit 4643854b authored by paul@ice.snake.net's avatar paul@ice.snake.net

Merge paul@bk-internal.mysql.com:/home/bk/mysql-4.1

into ice.snake.net:/Volumes/ice2/MySQL/bk/mysql-4.1
parents 8e723734 1b76aa07
...@@ -22,6 +22,7 @@ bar@bar.mysql.r18.ru ...@@ -22,6 +22,7 @@ bar@bar.mysql.r18.ru
bar@bar.udmsearch.izhnet.ru bar@bar.udmsearch.izhnet.ru
bar@deer.(none) bar@deer.(none)
bar@gw.udmsearch.izhnet.ru bar@gw.udmsearch.izhnet.ru
bar@mysql.com
bell@laptop.sanja.is.com.ua bell@laptop.sanja.is.com.ua
bell@sanja.is.com.ua bell@sanja.is.com.ua
bk@admin.bk bk@admin.bk
......
...@@ -1667,6 +1667,27 @@ static int stmt_read_row_buffered(MYSQL_STMT *stmt, unsigned char **row); ...@@ -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); 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 ****************************/ /**************** Misc utility functions ****************************/
/* /*
...@@ -2030,6 +2051,30 @@ static unsigned int alloc_stmt_fields(MYSQL_STMT *stmt) ...@@ -2030,6 +2051,30 @@ static unsigned int alloc_stmt_fields(MYSQL_STMT *stmt)
return stmt->field_count; 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. 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) ...@@ -2166,7 +2211,7 @@ static void store_param_double(NET *net, MYSQL_BIND *param)
static void store_param_time(NET *net, MYSQL_BIND *param) static void store_param_time(NET *net, MYSQL_BIND *param)
{ {
MYSQL_TIME *tm= (MYSQL_TIME *) param->buffer; MYSQL_TIME *tm= (MYSQL_TIME *) param->buffer;
char buff[15], *pos; char buff[MAX_TIME_REP_LENGTH], *pos;
uint length; uint length;
pos= buff+1; pos= buff+1;
...@@ -2177,19 +2222,19 @@ static void store_param_time(NET *net, MYSQL_BIND *param) ...@@ -2177,19 +2222,19 @@ static void store_param_time(NET *net, MYSQL_BIND *param)
pos[7]= (uchar) tm->second; pos[7]= (uchar) tm->second;
int4store(pos+8, tm->second_part); int4store(pos+8, tm->second_part);
if (tm->second_part) if (tm->second_part)
length= 11; length= 12;
else if (tm->hour || tm->minute || tm->second || tm->day) else if (tm->hour || tm->minute || tm->second || tm->day)
length= 8; length= 8;
else else
length= 0; length= 0;
buff[0]= (char) length++; buff[0]= (char) length++;
memcpy((char *)net->write_pos, buff, length); memcpy((char *)net->write_pos, buff, length);
net->write_pos+= length; net->write_pos+= length;
} }
static void net_store_datetime(NET *net, MYSQL_TIME *tm) static void net_store_datetime(NET *net, MYSQL_TIME *tm)
{ {
char buff[12], *pos; char buff[MAX_DATETIME_REP_LENGTH], *pos;
uint length; uint length;
pos= buff+1; pos= buff+1;
...@@ -2280,7 +2325,7 @@ static my_bool store_param(MYSQL_STMT *stmt, MYSQL_BIND *param) ...@@ -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 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 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); set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate);
DBUG_RETURN(1); DBUG_RETURN(1);
...@@ -2557,16 +2602,37 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt) ...@@ -2557,16 +2602,37 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt)
*/ */
if (mysql->methods->stmt_execute(stmt)) if (mysql->methods->stmt_execute(stmt))
DBUG_RETURN(1); DBUG_RETURN(1);
if (!stmt->field_count && mysql->field_count) if (mysql->field_count)
{ {
/* /* Server has sent result set metadata */
This is 'SHOW'/'EXPLAIN'-like query. Current implementation of if (stmt->field_count == 0)
prepared statements can't send result set metadata for this queries {
on prepare stage. Read it now. /*
*/ This is 'SHOW'/'EXPLAIN'-like query. Current implementation of
alloc_stmt_fields(stmt); 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; stmt->state= MYSQL_STMT_EXECUTE_DONE;
if (stmt->field_count) if (stmt->field_count)
{ {
...@@ -2693,15 +2759,17 @@ my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND * bind) ...@@ -2693,15 +2759,17 @@ my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND * bind)
param->store_param_func= store_param_double; param->store_param_func= store_param_double;
break; break;
case MYSQL_TYPE_TIME: case MYSQL_TYPE_TIME:
/* Buffer length ignored for DATE, TIME and DATETIME */
param->store_param_func= store_param_time; param->store_param_func= store_param_time;
param->buffer_length= MAX_TIME_REP_LENGTH;
break; break;
case MYSQL_TYPE_DATE: case MYSQL_TYPE_DATE:
param->store_param_func= store_param_date; param->store_param_func= store_param_date;
param->buffer_length= MAX_DATE_REP_LENGTH;
break; break;
case MYSQL_TYPE_DATETIME: case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_TIMESTAMP: case MYSQL_TYPE_TIMESTAMP:
param->store_param_func= store_param_datetime; param->store_param_func= store_param_datetime;
param->buffer_length= MAX_DATETIME_REP_LENGTH;
break; break;
case MYSQL_TYPE_TINY_BLOB: case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_MEDIUM_BLOB:
...@@ -2859,17 +2927,17 @@ static uint read_binary_time(MYSQL_TIME *tm, uchar **pos) ...@@ -2859,17 +2927,17 @@ static uint read_binary_time(MYSQL_TIME *tm, uchar **pos)
set_zero_time(tm); set_zero_time(tm);
return 0; return 0;
} }
to= *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->day= (ulong) sint4korr(to+1);
tm->hour= (uint) to[5]; tm->hour= (uint) to[5];
tm->minute= (uint) to[6]; tm->minute= (uint) to[6];
tm->second= (uint) to[7]; tm->second= (uint) to[7];
tm->second_part= (length > 8) ? (ulong) sint4korr(to+8) : 0;
tm->year= tm->month= 0; tm->year= tm->month= 0;
tm->neg= (bool)to[0];
return length; return length;
} }
...@@ -2878,16 +2946,20 @@ static uint read_binary_datetime(MYSQL_TIME *tm, uchar **pos) ...@@ -2878,16 +2946,20 @@ static uint read_binary_datetime(MYSQL_TIME *tm, uchar **pos)
{ {
uchar *to; uchar *to;
uint length; uint length;
if (!(length= net_field_length(pos))) if (!(length= net_field_length(pos)))
{ {
set_zero_time(tm); set_zero_time(tm);
return 0; return 0;
} }
to= *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) if (length > 4)
{ {
tm->hour= (uint) to[4]; tm->hour= (uint) to[4];
...@@ -2896,11 +2968,7 @@ static uint read_binary_datetime(MYSQL_TIME *tm, uchar **pos) ...@@ -2896,11 +2968,7 @@ static uint read_binary_datetime(MYSQL_TIME *tm, uchar **pos)
} }
else else
tm->hour= tm->minute= tm->second= 0; tm->hour= tm->minute= tm->second= 0;
tm->second_part= (length > 7) ? (ulong) sint4korr(to+7) : 0;
tm->year= (uint) sint2korr(to);
tm->month= (uint) to[2];
tm->day= (uint) to[3];
tm->neg= 0;
return length; return length;
} }
...@@ -3159,7 +3227,7 @@ static void send_data_time(MYSQL_BIND *param, MYSQL_TIME ltime, ...@@ -3159,7 +3227,7 @@ static void send_data_time(MYSQL_BIND *param, MYSQL_TIME ltime,
} }
} }
} }
/* Fetch data to buffers */ /* Fetch data to buffers */
......
...@@ -982,8 +982,9 @@ static my_bool init_uca_charsets() ...@@ -982,8 +982,9 @@ static my_bool init_uca_charsets()
{ {
my_tailoring *t; my_tailoring *t;
CHARSET_INFO cs= my_charset_ucs2_general_uca; CHARSET_INFO cs= my_charset_ucs2_general_uca;
cs.state= MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONTEXT;
char name[64]; char name[64];
cs.state= MY_CS_STRNXFRM|MY_CS_UNICODE|MY_CS_NONTEXT;
for (t= tailoring; t->tailoring; t++) for (t= tailoring; t->tailoring; t++)
{ {
cs.number= 128 + t->number; cs.number= 128 + t->number;
......
...@@ -629,6 +629,7 @@ Item_param::Item_param(unsigned pos_in_query_arg) : ...@@ -629,6 +629,7 @@ Item_param::Item_param(unsigned pos_in_query_arg) :
state(NO_VALUE), state(NO_VALUE),
item_result_type(STRING_RESULT), item_result_type(STRING_RESULT),
item_type(STRING_ITEM), item_type(STRING_ITEM),
param_type(MYSQL_TYPE_STRING),
pos_in_query(pos_in_query_arg), pos_in_query(pos_in_query_arg),
set_param_func(default_set_param_func) set_param_func(default_set_param_func)
{ {
...@@ -870,6 +871,17 @@ bool Item_param::get_time(TIME *res) ...@@ -870,6 +871,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() double Item_param::val()
{ {
switch (state) { switch (state) {
......
...@@ -465,6 +465,16 @@ public: ...@@ -465,6 +465,16 @@ public:
/* Cached values for virtual methods to save us one switch. */ /* Cached values for virtual methods to save us one switch. */
enum Item_result item_result_type; enum Item_result item_result_type;
enum Type item_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 Offset of placeholder inside statement text. Used to create
no-placeholders version of this statement for the binary log. no-placeholders version of this statement for the binary log.
...@@ -475,12 +485,13 @@ public: ...@@ -475,12 +485,13 @@ public:
enum Item_result result_type () const { return item_result_type; } enum Item_result result_type () const { return item_result_type; }
enum Type type() const { return item_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(); double val();
longlong val_int(); longlong val_int();
String *val_str(String*); String *val_str(String*);
bool get_time(TIME *tm); bool get_time(TIME *tm);
bool get_date(TIME *tm, uint fuzzydate);
int save_in_field(Field *field, bool no_conversions); int save_in_field(Field *field, bool no_conversions);
void set_null(); void set_null();
......
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
#include "mysql_priv.h" #include "mysql_priv.h"
#include <stdarg.h> #include <stdarg.h>
static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
bool Protocol::net_store_data(const char *from, uint length) bool Protocol::net_store_data(const char *from, uint length)
#else #else
...@@ -687,7 +689,7 @@ bool Protocol_simple::store_null() ...@@ -687,7 +689,7 @@ bool Protocol_simple::store_null()
#endif #endif
char buff[1]; char buff[1];
buff[0]= (char)251; 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 #endif
...@@ -990,7 +992,7 @@ bool Protocol_prep::store_tiny(longlong from) ...@@ -990,7 +992,7 @@ bool Protocol_prep::store_tiny(longlong from)
char buff[1]; char buff[1];
field_pos++; field_pos++;
buff[0]= (uchar) from; 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) ...@@ -1002,7 +1004,7 @@ bool Protocol_prep::store_short(longlong from)
field_types[field_pos] == MYSQL_TYPE_YEAR); field_types[field_pos] == MYSQL_TYPE_YEAR);
#endif #endif
field_pos++; field_pos++;
char *to= packet->prep_append(2, PACKET_BUFFET_EXTRA_ALLOC); char *to= packet->prep_append(2, PACKET_BUFFER_EXTRA_ALLOC);
if (!to) if (!to)
return 1; return 1;
int2store(to, (int) from); int2store(to, (int) from);
...@@ -1018,7 +1020,7 @@ bool Protocol_prep::store_long(longlong from) ...@@ -1018,7 +1020,7 @@ bool Protocol_prep::store_long(longlong from)
field_types[field_pos] == MYSQL_TYPE_LONG); field_types[field_pos] == MYSQL_TYPE_LONG);
#endif #endif
field_pos++; field_pos++;
char *to= packet->prep_append(4, PACKET_BUFFET_EXTRA_ALLOC); char *to= packet->prep_append(4, PACKET_BUFFER_EXTRA_ALLOC);
if (!to) if (!to)
return 1; return 1;
int4store(to, from); int4store(to, from);
...@@ -1033,7 +1035,7 @@ bool Protocol_prep::store_longlong(longlong from, bool unsigned_flag) ...@@ -1033,7 +1035,7 @@ bool Protocol_prep::store_longlong(longlong from, bool unsigned_flag)
field_types[field_pos] == MYSQL_TYPE_LONGLONG); field_types[field_pos] == MYSQL_TYPE_LONGLONG);
#endif #endif
field_pos++; field_pos++;
char *to= packet->prep_append(8, PACKET_BUFFET_EXTRA_ALLOC); char *to= packet->prep_append(8, PACKET_BUFFER_EXTRA_ALLOC);
if (!to) if (!to)
return 1; return 1;
int8store(to, from); int8store(to, from);
...@@ -1048,7 +1050,7 @@ bool Protocol_prep::store(float from, uint32 decimals, String *buffer) ...@@ -1048,7 +1050,7 @@ bool Protocol_prep::store(float from, uint32 decimals, String *buffer)
field_types[field_pos] == MYSQL_TYPE_FLOAT); field_types[field_pos] == MYSQL_TYPE_FLOAT);
#endif #endif
field_pos++; field_pos++;
char *to= packet->prep_append(4, PACKET_BUFFET_EXTRA_ALLOC); char *to= packet->prep_append(4, PACKET_BUFFER_EXTRA_ALLOC);
if (!to) if (!to)
return 1; return 1;
float4store(to, from); float4store(to, from);
...@@ -1063,7 +1065,7 @@ bool Protocol_prep::store(double from, uint32 decimals, String *buffer) ...@@ -1063,7 +1065,7 @@ bool Protocol_prep::store(double from, uint32 decimals, String *buffer)
field_types[field_pos] == MYSQL_TYPE_DOUBLE); field_types[field_pos] == MYSQL_TYPE_DOUBLE);
#endif #endif
field_pos++; field_pos++;
char *to= packet->prep_append(8, PACKET_BUFFET_EXTRA_ALLOC); char *to= packet->prep_append(8, PACKET_BUFFER_EXTRA_ALLOC);
if (!to) if (!to)
return 1; return 1;
float8store(to, from); float8store(to, from);
...@@ -1112,7 +1114,7 @@ bool Protocol_prep::store(TIME *tm) ...@@ -1112,7 +1114,7 @@ bool Protocol_prep::store(TIME *tm)
else else
length=0; length=0;
buff[0]=(char) length; // Length is stored first 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) bool Protocol_prep::store_date(TIME *tm)
...@@ -1129,7 +1131,7 @@ bool Protocol_prep::store_time(TIME *tm) ...@@ -1129,7 +1131,7 @@ bool Protocol_prep::store_time(TIME *tm)
DBUG_ASSERT(field_types == 0 || DBUG_ASSERT(field_types == 0 ||
field_types[field_pos] == MYSQL_TYPE_TIME); field_types[field_pos] == MYSQL_TYPE_TIME);
#endif #endif
char buff[15],*pos; char buff[13], *pos;
uint length; uint length;
field_pos++; field_pos++;
pos= buff+1; pos= buff+1;
...@@ -1140,13 +1142,13 @@ bool Protocol_prep::store_time(TIME *tm) ...@@ -1140,13 +1142,13 @@ bool Protocol_prep::store_time(TIME *tm)
pos[7]= (uchar) tm->second; pos[7]= (uchar) tm->second;
int4store(pos+8, tm->second_part); int4store(pos+8, tm->second_part);
if (tm->second_part) if (tm->second_part)
length=11; length=12;
else if (tm->hour || tm->minute || tm->second || tm->day) else if (tm->hour || tm->minute || tm->second || tm->day)
length=8; length=8;
else else
length=0; length=0;
buff[0]=(char) length; // Length is stored first 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 #ifdef EMBEDDED_LIBRARY
......
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
#pragma interface /* gcc class implementation */ #pragma interface /* gcc class implementation */
#endif #endif
#define PACKET_BUFFET_EXTRA_ALLOC 1024
class i_string; class i_string;
class THD; class THD;
......
...@@ -339,20 +339,19 @@ static void set_param_time(Item_param *param, uchar **pos, ulong len) ...@@ -339,20 +339,19 @@ static void set_param_time(Item_param *param, uchar **pos, ulong len)
{ {
uchar *to= *pos; uchar *to= *pos;
TIME tm; 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 Note, that though ranges of hour, minute and second are not checked
here we rely on them being < 256: otherwise here we rely on them being < 256: otherwise
we'll get buffer overflow in make_{date,time} functions, we'll get buffer overflow in make_{date,time} functions,
which are called when time value is converted to string. which are called when time value is converted to string.
*/ */
day= (uint) sint4korr(to+1);
tm.hour= (uint) to[5] + day * 24; tm.hour= (uint) to[5] + day * 24;
tm.minute= (uint) to[6]; tm.minute= (uint) to[6];
tm.second= (uint) to[7]; tm.second= (uint) to[7];
tm.second_part= (length > 8) ? (ulong) sint4korr(to+8) : 0;
if (tm.hour > 838) if (tm.hour > 838)
{ {
/* TODO: add warning 'Data truncated' here */ /* TODO: add warning 'Data truncated' here */
...@@ -361,7 +360,6 @@ static void set_param_time(Item_param *param, uchar **pos, ulong len) ...@@ -361,7 +360,6 @@ static void set_param_time(Item_param *param, uchar **pos, ulong len)
tm.second= 59; tm.second= 59;
} }
tm.day= tm.year= tm.month= 0; tm.day= tm.year= tm.month= 0;
tm.neg= (bool)to[0];
param->set_time(&tm, TIMESTAMP_TIME, param->set_time(&tm, TIMESTAMP_TIME,
MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN); MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
...@@ -372,14 +370,16 @@ static void set_param_time(Item_param *param, uchar **pos, ulong len) ...@@ -372,14 +370,16 @@ static void set_param_time(Item_param *param, uchar **pos, ulong len)
static void set_param_datetime(Item_param *param, uchar **pos, ulong len) static void set_param_datetime(Item_param *param, uchar **pos, ulong len)
{ {
uint length; uint length;
if ((length= get_param_length(pos, len)) >= 4) if ((length= get_param_length(pos, len)) >= 4)
{ {
uchar *to= *pos; uchar *to= *pos;
TIME tm; 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 Note, that though ranges of hour, minute and second are not checked
here we rely on them being < 256: otherwise here we rely on them being < 256: otherwise
...@@ -393,11 +393,8 @@ static void set_param_datetime(Item_param *param, uchar **pos, ulong len) ...@@ -393,11 +393,8 @@ static void set_param_datetime(Item_param *param, uchar **pos, ulong len)
} }
else else
tm.hour= tm.minute= tm.second= 0; tm.hour= tm.minute= tm.second= 0;
tm.year= (uint) sint2korr(to); tm.second_part= (length > 7) ? (ulong) sint4korr(to+7) : 0;
tm.month= (uint) to[2];
tm.day= (uint) to[3];
tm.neg= 0;
param->set_time(&tm, TIMESTAMP_DATETIME, param->set_time(&tm, TIMESTAMP_DATETIME,
MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN); MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
...@@ -592,6 +589,7 @@ static void setup_one_conversion_function(THD *thd, Item_param *param, ...@@ -592,6 +589,7 @@ static void setup_one_conversion_function(THD *thd, Item_param *param,
param->item_result_type= STRING_RESULT; param->item_result_type= STRING_RESULT;
} }
} }
param->param_type= (enum enum_field_types) param_type;
} }
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
......
...@@ -9802,6 +9802,73 @@ static void test_bug3796() ...@@ -9802,6 +9802,73 @@ static void test_bug3796()
myquery(rc); 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 Read and parse arguments and MySQL options from my.cnf
*/ */
...@@ -10094,6 +10161,7 @@ int main(int argc, char **argv) ...@@ -10094,6 +10161,7 @@ int main(int argc, char **argv)
(Bug #3686 */ (Bug #3686 */
test_ps_i18n(); /* test for i18n support in binary protocol */ test_ps_i18n(); /* test for i18n support in binary protocol */
test_bug3796(); /* test for select concat(?, <string>) */ 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 XXX: PLEASE RUN THIS PROGRAM UNDER VALGRIND AND VERIFY THAT YOUR TEST
DOESN'T CONTAIN WARNINGS/ERRORS BEFORE YOU PUSH. DOESN'T CONTAIN WARNINGS/ERRORS BEFORE YOU PUSH.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment