summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <konstantin@mysql.com>2004-06-09 03:21:50 +0400
committerunknown <konstantin@mysql.com>2004-06-09 03:21:50 +0400
commit27eda71204700eb6953205baf47d9cbeb4d367c1 (patch)
treeee6932d9f7ccdd66f6ccf84333180de34e7ac2a4 /sql
parent5cc410bb70dca2fad9dd7452ef294e1020186dda (diff)
downloadmariadb-git-27eda71204700eb6953205baf47d9cbeb4d367c1.tar.gz
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. libmysql/libmysql.c: Fix for Bug#4026: - now buffer_length is defined for any buffer type. Network buffer preallocation cleaned up. - added constants for maximum buffer sizes necessary for MYSQL_TYPE_DATE, MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME types. - TIME/DATETIME packing/unpacking functions fixed - now result set metadata is always updated from fields sent to COM_EXECUTE. This is necessary to make 'SELECT ?' queries work without conversions. sql/item.cc: - added implementatoin of Item_param::get_date sql/item.h: - added enum_field_types Item_param::param_type. First step for proper handling of placeholders. - added get_date() implementation to prevent date -> string -> date conversions when MYSQL_TYPE_DATE/DATETIME parameter is used in temporal context. sql/protocol.cc: Fix for Bug#4026: - PACKET_BUFFET_EXTRA_ALLOC -> PACKET_BUFFER_EXTRA_ALLOC. The define itself was moved to .cc as it's used only in protocol.cc - fixed Protocol_prep::store_time() call. sql/protocol.h: - PACKET_BUFFER_EXTRA_ALLOC moved to protocol.cc sql/sql_prepare.cc: Fix for Bug#4026: - MYSQL_TYPE_TIME/DATETIME handling fixed. - added initialization for Item_param::param_type in setup_one_conversion_function tests/client_test.c: Test case for Bug#4026
Diffstat (limited to 'sql')
-rw-r--r--sql/item.cc12
-rw-r--r--sql/item.h13
-rw-r--r--sql/protocol.cc24
-rw-r--r--sql/protocol.h1
-rw-r--r--sql/sql_prepare.cc26
5 files changed, 49 insertions, 27 deletions
diff --git a/sql/item.cc b/sql/item.cc
index 7db1a448e55..d85d70c69ab 100644
--- a/sql/item.cc
+++ b/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) {
diff --git a/sql/item.h b/sql/item.h
index 885a34dce81..e4c134842b9 100644
--- a/sql/item.h
+++ b/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();
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 44fc4eff9ad..7738349c742 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -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
diff --git a/sql/protocol.h b/sql/protocol.h
index 41885ec9f1f..43230983db7 100644
--- a/sql/protocol.h
+++ b/sql/protocol.h
@@ -18,7 +18,6 @@
#pragma interface /* gcc class implementation */
#endif
-#define PACKET_BUFFET_EXTRA_ALLOC 1024
class i_string;
class THD;
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 1713c81a096..ab181e02735 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -332,20 +332,19 @@ 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);
@@ -365,14 +363,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)
{
uint length;
-
+
if ((length= get_param_length(pos, len)) >= 4)
{
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
@@ -386,11 +386,8 @@ 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