summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.org>2016-01-11 17:20:16 +0400
committerAlexander Barkov <bar@mariadb.org>2016-01-11 17:20:16 +0400
commit454589b67f9609a78f00e521fe2ef0994eed4f3f (patch)
tree1d17569e30a61865cc6af35e025fb4e03952efbf /sql
parent250ab81200bf62d02c25144e3da38f7a9d3ced19 (diff)
downloadmariadb-git-454589b67f9609a78f00e521fe2ef0994eed4f3f.tar.gz
MDEV-9393 Split Copy_field::get_copy_func() into virtual methods in Field
Also fixes: MDEV-9391 InnoDB does not produce warnings when doing WHERE int_column=varchar_column MDEV-9337 ALTER from DECIMAL and INT to DATETIME returns a wrong result MDEV-9340 Copying from INT/DOUBLE to ENUM is inconsistent MDEV-9392 Copying from DECIMAL to YEAR is not consistent about warnings
Diffstat (limited to 'sql')
-rw-r--r--sql/field.h110
-rw-r--r--sql/field_conv.cc201
2 files changed, 184 insertions, 127 deletions
diff --git a/sql/field.h b/sql/field.h
index 7daf7da01cb..435ea20825a 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -33,6 +33,7 @@
#include "compat56.h"
class Send_field;
+class Copy_field;
class Protocol;
class Create_field;
class Relay_log_info;
@@ -621,6 +622,11 @@ protected:
val_str(&result);
return to->store(result.ptr(), result.length(), charset());
}
+ static void do_field_int(Copy_field *copy);
+ static void do_field_real(Copy_field *copy);
+ static void do_field_string(Copy_field *copy);
+ static void do_field_temporal(Copy_field *copy);
+ static void do_field_decimal(Copy_field *copy);
public:
static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
{ return alloc_root(mem_root, size); }
@@ -733,6 +739,12 @@ public:
uchar null_bit_arg, utype unireg_check_arg,
const char *field_name_arg);
virtual ~Field() {}
+ /**
+ Convenience definition of a copy function returned by
+ Field::get_copy_func()
+ */
+ typedef void Copy_func(Copy_field*);
+ virtual Copy_func *get_copy_func(const Field *from) const= 0;
/* Store functions returns 1 on overflow and -1 on fatal error */
virtual int store_field(Field *from) { return from->save_in_field(this); }
virtual int save_in_field(Field *to)= 0;
@@ -1265,6 +1277,7 @@ protected:
return (op_result == E_DEC_OVERFLOW);
}
int warn_if_overflow(int op_result);
+ Copy_func *get_identical_copy_func() const;
public:
void set_table_name(String *alias)
{
@@ -1528,6 +1541,10 @@ public:
uint decimals() const { return (uint) dec; }
uint size_of() const { return sizeof(*this); }
bool eq_def(const Field *field) const;
+ Copy_func *get_copy_func(const Field *from) const
+ {
+ return do_field_int;
+ }
int save_in_field(Field *to)
{
return to->store(val_int(), MY_TEST(flags & UNSIGNED_FLAG));
@@ -1678,6 +1695,10 @@ public:
not_fixed(dec_arg >= NOT_FIXED_DEC)
{}
Item_result result_type () const { return REAL_RESULT; }
+ Copy_func *get_copy_func(const Field *from) const
+ {
+ return do_field_real;
+ }
int save_in_field(Field *to) { return to->store(val_real()); }
int store_decimal(const my_decimal *);
int store_time_dec(MYSQL_TIME *ltime, uint dec);
@@ -1703,6 +1724,10 @@ public:
enum_field_types type() const { return MYSQL_TYPE_DECIMAL;}
enum ha_base_keytype key_type() const
{ return zerofill ? HA_KEYTYPE_BINARY : HA_KEYTYPE_NUM; }
+ Copy_func *get_copy_func(const Field *from) const
+ {
+ return eq_def(from) ? get_identical_copy_func() : do_field_string;
+ }
int reset(void);
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(double nr);
@@ -1746,6 +1771,12 @@ public:
enum_field_types type() const { return MYSQL_TYPE_NEWDECIMAL;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
Item_result result_type () const { return DECIMAL_RESULT; }
+ Copy_func *get_copy_func(const Field *from) const
+ {
+ // if (from->real_type() == MYSQL_TYPE_BIT) // QQ: why?
+ // return do_field_int;
+ return do_field_decimal;
+ }
int save_in_field(Field *to)
{
my_decimal buff;
@@ -2092,6 +2123,10 @@ public:
unireg_check_arg, field_name_arg, cs)
{}
enum_field_types type() const { return MYSQL_TYPE_NULL;}
+ Copy_func *get_copy_func(const Field *from) const
+ {
+ return do_field_string;
+ }
int store(const char *to, uint length, CHARSET_INFO *cs)
{ null[0]=1; return 0; }
int store(double nr) { null[0]=1; return 0; }
@@ -2142,6 +2177,7 @@ public:
{
return store(str, length, &my_charset_bin);
}
+ Copy_func *get_copy_func(const Field *from) const;
int save_in_field(Field *to)
{
MYSQL_TIME ltime;
@@ -2413,6 +2449,28 @@ public:
unireg_check_arg, field_name_arg, 1, 1)
{}
enum_field_types type() const { return MYSQL_TYPE_YEAR;}
+ Copy_func *get_copy_func(const Field *from) const
+ {
+ if (eq_def(from))
+ return get_identical_copy_func();
+ switch (from->cmp_type()) {
+ case STRING_RESULT:
+ return do_field_string;
+ case TIME_RESULT:
+ return do_field_temporal;
+ case DECIMAL_RESULT:
+ return do_field_decimal;
+ case REAL_RESULT:
+ return do_field_real;
+ case INT_RESULT:
+ break;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ break;
+ }
+ return do_field_int;
+ }
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr, bool unsigned_val);
@@ -2502,6 +2560,7 @@ protected:
int store_TIME_with_warning(MYSQL_TIME *ltime, const ErrConv *str,
int was_cut, int have_smth_to_conv);
bool check_zero_in_date_with_warn(ulonglong fuzzydate);
+ static void do_field_time(Copy_field *copy);
public:
Field_time(uchar *ptr_arg, uint length_arg, uchar *null_ptr_arg,
uchar null_bit_arg, enum utype unireg_check_arg,
@@ -2511,6 +2570,14 @@ public:
{}
enum_field_types type() const { return MYSQL_TYPE_TIME;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_INT24; }
+ Copy_func *get_copy_func(const Field *from) const
+ {
+ return from->cmp_type() == REAL_RESULT ? do_field_string : // MDEV-9344
+ from->type() == MYSQL_TYPE_YEAR ? do_field_int :
+ from->type() == MYSQL_TYPE_BIT ? do_field_int :
+ eq_def(from) ? get_identical_copy_func() :
+ do_field_time;
+ }
bool memcpy_field_possible(const Field *from) const
{
return real_type() == from->real_type() &&
@@ -2884,6 +2951,7 @@ public:
enum ha_base_keytype key_type() const
{ return binary() ? HA_KEYTYPE_BINARY : HA_KEYTYPE_TEXT; }
bool zero_pack() const { return 0; }
+ Copy_func *get_copy_func(const Field *from) const;
int reset(void)
{
charset()->cset->fill(charset(),(char*) ptr, field_length,
@@ -2980,6 +3048,7 @@ public:
return (uint32) field_length + (field_charset == &my_charset_bin ?
length_bytes : 0);
}
+ Copy_func *get_copy_func(const Field *from) const;
bool memcpy_field_possible(const Field *from) const
{
return Field_str::memcpy_field_possible(from) &&
@@ -3037,7 +3106,9 @@ protected:
The 'value'-object is a cache fronting the storage engine.
*/
String value;
-
+
+ static void do_copy_blob(Copy_field *copy);
+ static void do_conv_blob(Copy_field *copy);
public:
Field_blob(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
@@ -3072,6 +3143,19 @@ public:
enum_field_types type() const { return MYSQL_TYPE_BLOB;}
enum ha_base_keytype key_type() const
{ return binary() ? HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2; }
+ Copy_func *get_copy_func(const Field *from) const
+ {
+ /*
+ TODO: MDEV-9331
+ if (from->type() == MYSQL_TYPE_BIT)
+ return do_field_int;
+ */
+ if (!(from->flags & BLOB_FLAG) || from->charset() != charset())
+ return do_conv_blob;
+ if (from->pack_length() != Field_blob::pack_length())
+ return do_copy_blob;
+ return get_identical_copy_func();
+ }
int store_field(Field *from)
{ // Be sure the value is stored
from->val_str(&value);
@@ -3258,6 +3342,7 @@ uint gis_field_options_read(const uchar *buf, uint buf_len,
class Field_enum :public Field_str {
+ static void do_field_enum(Copy_field *copy_field);
protected:
uint packlength;
public:
@@ -3278,6 +3363,17 @@ public:
enum_field_types type() const { return MYSQL_TYPE_STRING; }
enum Item_result cmp_type () const { return INT_RESULT; }
enum ha_base_keytype key_type() const;
+ Copy_func *get_copy_func(const Field *from) const
+ {
+ if (eq_def(from))
+ return get_identical_copy_func();
+ if (real_type() == MYSQL_TYPE_ENUM &&
+ from->real_type() == MYSQL_TYPE_ENUM)
+ return do_field_enum;
+ if (from->result_type() == STRING_RESULT)
+ return do_field_string;
+ return do_field_int;
+ }
int store_field(Field *from)
{
if (from->real_type() == MYSQL_TYPE_ENUM && from->val_int() == 0)
@@ -3409,6 +3505,10 @@ public:
clr_rec_bits(bit_ptr, bit_ofs, bit_len);
return 0;
}
+ Copy_func *get_copy_func(const Field *from) const
+ {
+ return do_field_int;
+ }
int save_in_field(Field *to) { return to->store(val_int(), true); }
bool memcpy_field_possible(const Field *from) const { return false; }
int store(const char *to, uint length, CHARSET_INFO *charset);
@@ -3702,12 +3802,6 @@ class Send_field :public Sql_alloc {
*/
class Copy_field :public Sql_alloc {
- /**
- Convenience definition of a copy function returned by
- get_copy_func.
- */
- typedef void Copy_func(Copy_field*);
- Copy_func *get_copy_func(const Field *to, const Field *from);
public:
uchar *from_ptr,*to_ptr;
uchar *from_null_ptr,*to_null_ptr;
@@ -3728,7 +3822,7 @@ public:
Note that for VARCHARs, do_copy() will be do_varstring*() which
only copies the length-bytes (1 or 2) + the actual length of the
- text instead of from/to_length bytes. @see get_copy_func()
+ text instead of from/to_length bytes.
*/
uint from_length,to_length;
Field *from_field,*to_field;
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index 21f46bbbedb..ecad05c7530 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -335,12 +335,12 @@ static void do_copy_next_number(Copy_field *copy)
}
-static void do_copy_blob(Copy_field *copy)
+void Field_blob::do_copy_blob(Copy_field *copy)
{
((Field_blob*) copy->to_field)->copy_value(((Field_blob*) copy->from_field));
}
-static void do_conv_blob(Copy_field *copy)
+void Field_blob::do_conv_blob(Copy_field *copy)
{
copy->from_field->val_str(&copy->tmp);
((Field_blob *) copy->to_field)->store(copy->tmp.ptr(),
@@ -362,7 +362,7 @@ static void do_save_blob(Copy_field *copy)
}
-static void do_field_string(Copy_field *copy)
+void Field::do_field_string(Copy_field *copy)
{
char buff[MAX_FIELD_WIDTH];
String res(buff, sizeof(buff), copy->from_field->charset());
@@ -373,7 +373,7 @@ static void do_field_string(Copy_field *copy)
}
-static void do_field_enum(Copy_field *copy)
+void Field_enum::do_field_enum(Copy_field *copy)
{
if (copy->from_field->val_int() == 0)
((Field_enum *) copy->to_field)->store_type((ulonglong) 0);
@@ -397,32 +397,45 @@ static void do_field_varbinary_pre50(Copy_field *copy)
}
-static void do_field_int(Copy_field *copy)
+void Field::do_field_int(Copy_field *copy)
{
longlong value= copy->from_field->val_int();
copy->to_field->store(value,
MY_TEST(copy->from_field->flags & UNSIGNED_FLAG));
}
-static void do_field_real(Copy_field *copy)
+void Field::do_field_real(Copy_field *copy)
{
double value=copy->from_field->val_real();
copy->to_field->store(value);
}
-static void do_field_decimal(Copy_field *copy)
+void Field::do_field_decimal(Copy_field *copy)
{
my_decimal value;
copy->to_field->store_decimal(copy->from_field->val_decimal(&value));
}
-static void do_field_temporal(Copy_field *copy)
+void Field::do_field_temporal(Copy_field *copy)
{
MYSQL_TIME ltime;
- copy->from_field->get_date(&ltime, 0);
- copy->to_field->store_time_dec(&ltime, copy->from_field->decimals());
+ // TODO: we now need to check result
+ if (copy->from_field->get_date(&ltime, 0))
+ copy->to_field->reset();
+ else
+ copy->to_field->store_time_dec(&ltime, copy->from_field->decimals());
+}
+
+
+void Field_time::do_field_time(Copy_field *copy)
+{
+ MYSQL_TIME ltime;
+ if (copy->from_field->get_date(&ltime, TIME_TIME_ONLY))
+ copy->to_field->reset();
+ else
+ copy->to_field->store_time_dec(&ltime, copy->from_field->decimals());
}
@@ -698,122 +711,72 @@ void Copy_field::set(Field *to,Field *from,bool save)
if ((to->flags & BLOB_FLAG) && save)
do_copy2= do_save_blob;
else
- do_copy2= get_copy_func(to,from);
+ do_copy2= to->get_copy_func(from);
if (!do_copy) // Not null
do_copy=do_copy2;
}
-Copy_field::Copy_func *
-Copy_field::get_copy_func(const Field *to, const Field *from)
+Field::Copy_func *Field_temporal::get_copy_func(const Field *from) const
+{
+ /* If types are not 100 % identical then convert trough get_date() */
+ if (from->cmp_type() == REAL_RESULT)
+ return do_field_string; // TODO: MDEV-9344
+ if (from->type() == MYSQL_TYPE_YEAR)
+ return do_field_string; // TODO: MDEV-9343
+ if (from->type() == MYSQL_TYPE_BIT)
+ return do_field_int;
+ if (!eq_def(from) ||
+ (table->in_use->variables.sql_mode &
+ (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE)))
+ return do_field_temporal;
+ return get_identical_copy_func();
+}
+
+
+Field::Copy_func *Field_varstring::get_copy_func(const Field *from) const
+{
+ if (from->type() == MYSQL_TYPE_BIT)
+ return do_field_int;
+ /*
+ Detect copy from pre 5.0 varbinary to varbinary as of 5.0 and
+ use special copy function that removes trailing spaces and thus
+ repairs data.
+ */
+ if (from->type() == MYSQL_TYPE_VAR_STRING && !from->has_charset() &&
+ !Field_varstring::has_charset())
+ return do_field_varbinary_pre50;
+ if (Field_varstring::real_type() != from->real_type() ||
+ Field_varstring::charset() != from->charset() ||
+ length_bytes != ((const Field_varstring*) from)->length_bytes)
+ return do_field_string;
+ return length_bytes == 1 ?
+ (from->charset()->mbmaxlen == 1 ? do_varstring1 : do_varstring1_mb) :
+ (from->charset()->mbmaxlen == 1 ? do_varstring2 : do_varstring2_mb);
+}
+
+
+Field::Copy_func *Field_string::get_copy_func(const Field *from) const
+{
+ if (from->type() == MYSQL_TYPE_BIT)
+ return do_field_int;
+ if (Field_string::real_type() != from->real_type() ||
+ Field_string::charset() != from->charset())
+ return do_field_string;
+ if (Field_string::pack_length() < from->pack_length())
+ return (Field_string::charset()->mbmaxlen == 1 ?
+ do_cut_string : do_cut_string_complex);
+ if (Field_string::pack_length() > from->pack_length())
+ return Field_string::charset() == &my_charset_bin ? do_expand_binary :
+ do_expand_string;
+ return get_identical_copy_func();
+}
+
+
+Field::Copy_func *Field::get_identical_copy_func() const
{
- if (to->flags & BLOB_FLAG)
- {
- if (!(from->flags & BLOB_FLAG) || from->charset() != to->charset())
- return do_conv_blob;
- if (from_length != to_length)
- return do_copy_blob;
- }
- else
- {
- if (to->real_type() == MYSQL_TYPE_BIT ||
- from->real_type() == MYSQL_TYPE_BIT)
- return do_field_int;
- if (to->result_type() == DECIMAL_RESULT)
- return do_field_decimal;
- if (from->cmp_type() == TIME_RESULT)
- {
- /* If types are not 100 % identical then convert trough get_date() */
- if (!to->eq_def(from) ||
- ((to->table->in_use->variables.sql_mode &
- (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE)) &&
- mysql_type_to_time_type(to->type()) != MYSQL_TIMESTAMP_TIME))
- return do_field_temporal;
- /* Do binary copy */
- }
- // Check if identical fields
- if (from->result_type() == STRING_RESULT)
- {
- /*
- Detect copy from pre 5.0 varbinary to varbinary as of 5.0 and
- use special copy function that removes trailing spaces and thus
- repairs data.
- */
- if (from->type() == MYSQL_TYPE_VAR_STRING && !from->has_charset() &&
- to->type() == MYSQL_TYPE_VARCHAR && !to->has_charset())
- return do_field_varbinary_pre50;
-
- if (to->real_type() != from->real_type())
- {
- if (from->real_type() == MYSQL_TYPE_ENUM ||
- from->real_type() == MYSQL_TYPE_SET)
- if (to->result_type() != STRING_RESULT)
- return do_field_int; // Convert SET to number
- return do_field_string;
- }
- if (to->real_type() == MYSQL_TYPE_ENUM ||
- to->real_type() == MYSQL_TYPE_SET)
- {
- if (!to->eq_def(from))
- {
- if (from->real_type() == MYSQL_TYPE_ENUM &&
- to->real_type() == MYSQL_TYPE_ENUM)
- return do_field_enum;
- return do_field_string;
- }
- }
- else if (to->charset() != from->charset())
- return do_field_string;
- else if (to->real_type() == MYSQL_TYPE_VARCHAR)
- {
- if (((Field_varstring*) to)->length_bytes !=
- ((Field_varstring*) from)->length_bytes)
- return do_field_string;
- return (((Field_varstring*) to)->length_bytes == 1 ?
- (from->charset()->mbmaxlen == 1 ? do_varstring1 :
- do_varstring1_mb) :
- (from->charset()->mbmaxlen == 1 ? do_varstring2 :
- do_varstring2_mb));
- }
- else if (to_length < from_length)
- return (from->charset()->mbmaxlen == 1 ?
- do_cut_string : do_cut_string_complex);
- else if (to_length > from_length)
- {
- if (to->charset() == &my_charset_bin)
- return do_expand_binary;
- return do_expand_string;
- }
- }
- else if (to->real_type() != from->real_type() ||
- to_length != from_length)
- {
- if ((to->real_type() == MYSQL_TYPE_ENUM ||
- to->real_type() == MYSQL_TYPE_SET) &&
- from->real_type() == MYSQL_TYPE_NEWDECIMAL)
- return do_field_decimal;
- if (to->real_type() == MYSQL_TYPE_DECIMAL ||
- to->result_type() == STRING_RESULT)
- return do_field_string;
- if (to->result_type() == INT_RESULT)
- return do_field_int;
- return do_field_real;
- }
- else
- {
- if (!to->eq_def(from))
- {
- if (to->real_type() == MYSQL_TYPE_DECIMAL)
- return do_field_string;
- if (to->result_type() == INT_RESULT)
- return do_field_int;
- else
- return do_field_real;
- }
- }
- }
/* Identical field types */
- switch (to_length) {
+ switch (pack_length()) {
case 1: return do_field_1;
case 2: return do_field_2;
case 3: return do_field_3;