summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/CMakeLists.txt2
-rw-r--r--sql/field.cc124
-rw-r--r--sql/field.h56
-rw-r--r--sql/filesort.cc12
-rw-r--r--sql/handler.h2
-rw-r--r--sql/item.cc11
-rw-r--r--sql/item_cmpfunc.cc44
-rw-r--r--sql/item_create.cc139
-rw-r--r--sql/item_func.cc71
-rw-r--r--sql/item_func.h10
-rw-r--r--sql/item_inetfunc.cc830
-rw-r--r--sql/item_inetfunc.h244
-rw-r--r--sql/item_strfunc.cc48
-rw-r--r--sql/item_strfunc.h15
-rw-r--r--sql/item_timefunc.cc10
-rw-r--r--sql/item_xmlfunc.cc2
-rw-r--r--sql/log_event.cc2
-rw-r--r--sql/log_event.h2
-rw-r--r--sql/multi_range_read.cc8
-rw-r--r--sql/mysqld.cc10
-rw-r--r--sql/opt_range.cc11
-rw-r--r--sql/opt_subselect.cc1
-rw-r--r--sql/password.c4
-rw-r--r--sql/rpl_gtid.cc2
-rw-r--r--sql/rpl_utility.cc2
-rw-r--r--sql/share/errmsg-utf8.txt4
-rw-r--r--sql/slave.cc2
-rw-r--r--sql/sql_acl.cc13
-rw-r--r--sql/sql_connect.cc2
-rw-r--r--sql/sql_derived.cc17
-rw-r--r--sql/sql_error.h11
-rw-r--r--sql/sql_join_cache.cc36
-rw-r--r--sql/sql_join_cache.h15
-rw-r--r--sql/sql_load.cc64
-rw-r--r--sql/sql_parse.cc8
-rw-r--r--sql/sql_prepare.cc2
-rw-r--r--sql/sql_priv.h3
-rw-r--r--sql/sql_select.cc99
-rw-r--r--sql/sql_select.h24
-rw-r--r--sql/sql_show.cc67
-rw-r--r--sql/sql_string.cc36
-rw-r--r--sql/sql_string.h3
-rw-r--r--sql/sql_table.cc108
-rw-r--r--sql/sql_time.cc24
-rw-r--r--sql/sql_time.h3
-rw-r--r--sql/sql_truncate.cc52
-rw-r--r--sql/sql_truncate.h10
-rw-r--r--sql/sql_update.cc7
-rw-r--r--sql/sql_yacc.yy6
-rw-r--r--sql/sys_vars.cc4
-rw-r--r--sql/table.cc5
-rw-r--r--sql/table.h2
-rw-r--r--sql/tztime.cc2
53 files changed, 1895 insertions, 396 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index 598462d1bba..d25ed87e1fa 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -99,7 +99,7 @@ SET (SQL_SOURCE
sql_profile.cc event_parse_data.cc sql_alter.cc
sql_signal.cc rpl_handler.cc mdl.cc sql_admin.cc
transaction.cc sys_vars.cc sql_truncate.cc datadict.cc
- sql_reload.cc sql_cmd.h
+ sql_reload.cc sql_cmd.h item_inetfunc.cc
# added in MariaDB:
sql_explain.h sql_explain.cc
sql_lifo_buffer.h sql_join_cache.h sql_join_cache.cc
diff --git a/sql/field.cc b/sql/field.cc
index 68617d0204e..103a8920d7e 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1965,8 +1965,8 @@ Field *Field::new_field(MEM_ROOT *root, TABLE *new_table,
Field *Field::new_key_field(MEM_ROOT *root, TABLE *new_table,
- uchar *new_ptr, uchar *new_null_ptr,
- uint new_null_bit)
+ uchar *new_ptr, uint32 length,
+ uchar *new_null_ptr, uint new_null_bit)
{
Field *tmp;
if ((tmp= new_field(root, new_table, table == new_table)))
@@ -4706,7 +4706,7 @@ int Field_timestamp::store(longlong nr, bool unsigned_val)
{
MYSQL_TIME l_time;
int error;
- ErrConvInteger str(nr);
+ ErrConvInteger str(nr, unsigned_val);
THD *thd= get_thd();
/* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */
@@ -5210,7 +5210,7 @@ int Field_temporal_with_date::store(longlong nr, bool unsigned_val)
MYSQL_TIME ltime;
longlong tmp;
THD *thd= get_thd();
- ErrConvInteger str(nr);
+ ErrConvInteger str(nr, unsigned_val);
tmp= number_to_datetime(nr, 0, &ltime, sql_mode_for_dates(thd), &error);
@@ -5316,12 +5316,41 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs)
}
+/**
+ subtract a given number of days from DATETIME, return TIME
+
+ optimized version of calc_time_diff()
+
+ @note it might generate TIME values outside of the valid TIME range!
+*/
+static void calc_datetime_days_diff(MYSQL_TIME *ltime, long days)
+{
+ long daydiff= calc_daynr(ltime->year, ltime->month, ltime->day) - days;
+ ltime->year= ltime->month= 0;
+ if (daydiff >=0 )
+ ltime->day= daydiff;
+ else
+ {
+ longlong timediff= ((((daydiff * 24LL +
+ ltime->hour) * 60LL +
+ ltime->minute) * 60LL +
+ ltime->second) * 1000000LL +
+ ltime->second_part);
+ unpack_time(timediff, ltime);
+ }
+ ltime->time_type= MYSQL_TIMESTAMP_TIME;
+}
+
+
int Field_time::store_time_dec(MYSQL_TIME *ltime, uint dec)
{
MYSQL_TIME l_time= *ltime;
ErrConvTime str(ltime);
int was_cut= 0;
+ if (curdays && l_time.time_type != MYSQL_TIMESTAMP_TIME)
+ calc_datetime_days_diff(&l_time, curdays);
+
int have_smth_to_conv= !check_time_range(&l_time, decimals(), &was_cut);
return store_TIME_with_warning(&l_time, &str, was_cut, have_smth_to_conv);
}
@@ -5335,7 +5364,7 @@ int Field_time::store(double nr)
bool neg= nr < 0;
if (neg)
nr= -nr;
- int have_smth_to_conv= !number_to_time(neg, (longlong)nr,
+ int have_smth_to_conv= !number_to_time(neg, (ulonglong) nr,
(ulong)((nr - floor(nr)) * TIME_SECOND_PART_FACTOR),
&ltime, &was_cut);
@@ -5346,15 +5375,40 @@ int Field_time::store(double nr)
int Field_time::store(longlong nr, bool unsigned_val)
{
MYSQL_TIME ltime;
- ErrConvInteger str(nr);
+ ErrConvInteger str(nr, unsigned_val);
int was_cut;
- int have_smth_to_conv= !number_to_time(nr < 0, nr < 0 ? -nr : nr,
+ if (nr < 0 && unsigned_val)
+ nr= 99991231235959LL + 1;
+ int have_smth_to_conv= !number_to_time(nr < 0,
+ (ulonglong) (nr < 0 ? -nr : nr),
0, &ltime, &was_cut);
return store_TIME_with_warning(&ltime, &str, was_cut, have_smth_to_conv);
}
-
-
+
+
+void Field_time::set_curdays(THD *thd)
+{
+ MYSQL_TIME ltime;
+ set_current_date(thd, &ltime);
+ curdays= calc_daynr(ltime.year, ltime.month, ltime.day);
+}
+
+
+Field *Field_time::new_key_field(MEM_ROOT *root, TABLE *new_table,
+ uchar *new_ptr, uint32 length,
+ uchar *new_null_ptr, uint new_null_bit)
+{
+ THD *thd= get_thd();
+ Field_time *res=
+ (Field_time*) Field::new_key_field(root, new_table, new_ptr, length,
+ new_null_ptr, new_null_bit);
+ if (!(thd->variables.old_behavior & OLD_MODE_ZERO_DATE_TIME_CAST) && res)
+ res->set_curdays(thd);
+ return res;
+}
+
+
double Field_time::val_real(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
@@ -5705,7 +5759,8 @@ bool Field_year::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
int tmp= (int) ptr[0];
if (tmp || field_length != 4)
tmp+= 1900;
- return int_to_datetime_with_warn(tmp * 10000, ltime, fuzzydate, field_name);
+ return int_to_datetime_with_warn(false, tmp * 10000,
+ ltime, fuzzydate, field_name);
}
@@ -7200,17 +7255,14 @@ Field *Field_varstring::new_field(MEM_ROOT *root, TABLE *new_table,
}
-Field *Field_varstring::new_key_field(MEM_ROOT *root,
- TABLE *new_table,
- uchar *new_ptr, uchar *new_null_ptr,
- uint new_null_bit)
+Field *Field_varstring::new_key_field(MEM_ROOT *root, TABLE *new_table,
+ uchar *new_ptr, uint32 length,
+ uchar *new_null_ptr, uint new_null_bit)
{
Field_varstring *res;
- if ((res= (Field_varstring*) Field::new_key_field(root,
- new_table,
- new_ptr,
- new_null_ptr,
- new_null_bit)))
+ if ((res= (Field_varstring*) Field::new_key_field(root, new_table,
+ new_ptr, length,
+ new_null_ptr, new_null_bit)))
{
/* Keys length prefixes are always packed with 2 bytes */
res->length_bytes= 2;
@@ -7218,7 +7270,6 @@ Field *Field_varstring::new_key_field(MEM_ROOT *root,
return res;
}
-
uint Field_varstring::is_equal(Create_field *new_field)
{
if (new_field->sql_type == real_type() &&
@@ -7312,8 +7363,7 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
If content of the 'from'-address is cached in the 'value'-object
it is possible that the content needs a character conversion.
*/
- uint32 dummy_offset;
- if (!String::needs_conversion(length, cs, field_charset, &dummy_offset))
+ if (!String::needs_conversion_on_storage(length, cs, field_charset))
{
Field_blob::store_length(length);
bmove(ptr + packlength, &from, sizeof(char*));
@@ -7576,6 +7626,18 @@ int Field_blob::key_cmp(const uchar *a,const uchar *b)
}
+Field *Field_blob::new_key_field(MEM_ROOT *root, TABLE *new_table,
+ uchar *new_ptr, uint32 length,
+ uchar *new_null_ptr, uint new_null_bit)
+{
+ Field_varstring *res= new (root) Field_varstring(new_ptr, length, 2,
+ new_null_ptr, new_null_bit, Field::NONE,
+ field_name, table->s, charset());
+ res->init(new_table);
+ return res;
+}
+
+
/**
Save the field metadata for blob fields.
@@ -7885,12 +7947,11 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
int err= 0;
- uint32 not_used;
char buff[STRING_BUFFER_USUAL_SIZE];
String tmpstr(buff,sizeof(buff), &my_charset_bin);
/* Convert character set if necessary */
- if (String::needs_conversion(length, cs, field_charset, &not_used))
+ if (String::needs_conversion_on_storage(length, cs, field_charset))
{
uint dummy_errors;
tmpstr.copy(from, length, cs, field_charset, &dummy_errors);
@@ -8067,12 +8128,11 @@ int Field_set::store(const char *from,uint length,CHARSET_INFO *cs)
int err= 0;
char *not_used;
uint not_used2;
- uint32 not_used_offset;
char buff[STRING_BUFFER_USUAL_SIZE];
String tmpstr(buff,sizeof(buff), &my_charset_bin);
/* Convert character set if necessary */
- if (String::needs_conversion(length, cs, field_charset, &not_used_offset))
+ if (String::needs_conversion_on_storage(length, cs, field_charset))
{
uint dummy_errors;
tmpstr.copy(from, length, cs, field_charset, &dummy_errors);
@@ -8425,15 +8485,13 @@ Field_bit::do_last_null_byte() const
}
-Field *Field_bit::new_key_field(MEM_ROOT *root,
- TABLE *new_table,
- uchar *new_ptr, uchar *new_null_ptr,
- uint new_null_bit)
+Field *Field_bit::new_key_field(MEM_ROOT *root, TABLE *new_table,
+ uchar *new_ptr, uint32 length,
+ uchar *new_null_ptr, uint new_null_bit)
{
Field_bit *res;
- if ((res= (Field_bit*) Field::new_key_field(root, new_table,
- new_ptr, new_null_ptr,
- new_null_bit)))
+ if ((res= (Field_bit*) Field::new_key_field(root, new_table, new_ptr, length,
+ new_null_ptr, new_null_bit)))
{
/* Move bits normally stored in null_pointer to new_ptr */
res->bit_ptr= new_ptr;
diff --git a/sql/field.h b/sql/field.h
index cbd9175f26c..b5f332f5edc 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -94,6 +94,31 @@ inline uint get_set_pack_length(int elements)
/**
+ Tests if field type is temporal and has date part,
+ i.e. represents DATE, DATETIME or TIMESTAMP types in SQL.
+
+ @param type Field type, as returned by field->type().
+ @retval true If field type is temporal type with date part.
+ @retval false If field type is not temporal type with date part.
+*/
+inline bool is_temporal_type_with_date(enum_field_types type)
+{
+ switch (type)
+ {
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_TIMESTAMP:
+ return true;
+ case MYSQL_TYPE_DATETIME2:
+ case MYSQL_TYPE_TIMESTAMP2:
+ DBUG_ASSERT(0); // field->real_type() should not get to here.
+ default:
+ return false;
+ }
+}
+
+
+/**
Recognizer for concrete data type (called real_type for some reason),
returning true if it is one of the TIMESTAMP types.
*/
@@ -228,9 +253,13 @@ class Field
Field(const Item &); /* Prevent use of these */
void operator=(Field &);
public:
+ static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
+ { return alloc_root(mem_root, size); }
static void *operator new(size_t size) throw ()
{ return sql_alloc(size); }
static void operator delete(void *ptr_arg, size_t size) { TRASH(ptr_arg, size); }
+ static void operator delete(void *ptr, MEM_ROOT *mem_root)
+ { DBUG_ASSERT(0); }
uchar *ptr; // Position to field in record
/**
@@ -684,8 +713,8 @@ public:
virtual Field *new_field(MEM_ROOT *root, TABLE *new_table,
bool keep_type);
virtual Field *new_key_field(MEM_ROOT *root, TABLE *new_table,
- uchar *new_ptr, uchar *new_null_ptr,
- uint new_null_bit);
+ uchar *new_ptr, uint32 length,
+ uchar *new_null_ptr, uint new_null_bit);
Field *clone(MEM_ROOT *mem_root, TABLE *new_table);
Field *clone(MEM_ROOT *mem_root, TABLE *new_table, my_ptrdiff_t diff,
bool stat_flag= FALSE);
@@ -1823,6 +1852,12 @@ public:
class Field_time :public Field_temporal {
+ /*
+ when this Field_time instance is used for storing values for index lookups
+ (see class store_key, Field::new_key_field(), etc), the following
+ might be set to TO_DAYS(CURDATE()). See also Field_time::store_time_dec()
+ */
+ long curdays;
protected:
virtual void store_TIME(MYSQL_TIME *ltime);
int store_TIME_with_warning(MYSQL_TIME *ltime, const ErrConv *str,
@@ -1832,7 +1867,7 @@ public:
uchar null_bit_arg, enum utype unireg_check_arg,
const char *field_name_arg)
:Field_temporal(ptr_arg, length_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg)
+ unireg_check_arg, field_name_arg), curdays(0)
{}
enum_field_types type() const { return MYSQL_TYPE_TIME;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_INT24; }
@@ -1851,6 +1886,10 @@ public:
uint32 pack_length() const { return 3; }
void sql_type(String &str) const;
uint size_of() const { return sizeof(*this); }
+ void set_curdays(THD *thd);
+ Field *new_key_field(MEM_ROOT *root, TABLE *new_table,
+ uchar *new_ptr, uint32 length,
+ uchar *new_null_ptr, uint new_null_bit);
};
@@ -2298,8 +2337,8 @@ public:
{ return charset() == &my_charset_bin ? FALSE : TRUE; }
Field *new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type);
Field *new_key_field(MEM_ROOT *root, TABLE *new_table,
- uchar *new_ptr, uchar *new_null_ptr,
- uint new_null_bit);
+ uchar *new_ptr, uint32 length,
+ uchar *new_null_ptr, uint new_null_bit);
uint is_equal(Create_field *new_field);
void hash(ulong *nr, ulong *nr2);
uint length_size() { return length_bytes; }
@@ -2432,6 +2471,9 @@ public:
}
uint get_key_image(uchar *buff,uint length, imagetype type);
void set_key_image(const uchar *buff,uint length);
+ Field *new_key_field(MEM_ROOT *root, TABLE *new_table,
+ uchar *new_ptr, uint32 length,
+ uchar *new_null_ptr, uint new_null_bit);
void sql_type(String &str) const;
inline bool copy()
{
@@ -2702,8 +2744,8 @@ public:
virtual void set_default();
Field *new_key_field(MEM_ROOT *root, TABLE *new_table,
- uchar *new_ptr, uchar *new_null_ptr,
- uint new_null_bit);
+ uchar *new_ptr, uint32 length,
+ uchar *new_null_ptr, uint new_null_bit);
void set_bit_ptr(uchar *bit_ptr_arg, uchar bit_ofs_arg)
{
bit_ptr= bit_ptr_arg;
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 0d554df6e18..5ca6be2a2f4 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -166,6 +166,8 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
TABLE_LIST *tab= table->pos_in_table_list;
Item_subselect *subselect= tab ? tab->containing_subselect() : 0;
+ *found_rows= HA_POS_ERROR;
+
MYSQL_FILESORT_START(table->s->db.str, table->s->table_name.str);
DEBUG_SYNC(thd, "filesort_start");
@@ -686,7 +688,8 @@ static ha_rows find_all_keys(Sort_param *param, SQL_SELECT *select,
ref_pos= ref_buff;
quick_select=select && select->quick;
record=0;
- *found_rows= 0;
+ if (pq) // don't count unless pq is used
+ *found_rows= 0;
flag= ((file->ha_table_flags() & HA_REC_NOT_IN_SEQ) || quick_select);
if (flag)
ref_pos= &file->ref[0];
@@ -806,9 +809,14 @@ static ha_rows find_all_keys(Sort_param *param, SQL_SELECT *select,
if (write_record)
{
- (*found_rows)++;
if (pq)
{
+ /*
+ only count rows when pq is used - otherwise there might be
+ other filters *after* the filesort, we don't know the final row
+ count here
+ */
+ (*found_rows)++;
pq->push(ref_pos);
idx= pq->num_elements();
}
diff --git a/sql/handler.h b/sql/handler.h
index 53e8997acbe..d5a371027f6 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -1618,7 +1618,7 @@ struct HA_CREATE_INFO
For ALTER TABLE defaults to ROW_TYPE_NOT_USED (means "keep the current").
Can be changed either explicitly by the parser.
- If nothing speficied inherits the value of the original table (if present).
+ If nothing specified inherits the value of the original table (if present).
*/
enum row_type row_type;
enum ha_choice transactional;
diff --git a/sql/item.cc b/sql/item.cc
index 2c963322eb6..21baf779781 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -1352,6 +1352,7 @@ bool Item::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
case INT_RESULT:
{
longlong value= val_int();
+ bool neg= !unsigned_flag && value < 0;
if (field_type() == MYSQL_TYPE_YEAR)
{
if (max_length == 2)
@@ -1363,7 +1364,8 @@ bool Item::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
}
value*= 10000; /* make it YYYYMMHH */
}
- if (null_value || int_to_datetime_with_warn(value, ltime, fuzzydate,
+ if (null_value || int_to_datetime_with_warn(neg, neg ? -value : value,
+ ltime, fuzzydate,
field_name_or_null()))
goto err;
break;
@@ -8848,7 +8850,7 @@ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item)
*/
if (field->cmp_type() == TIME_RESULT)
{
- MYSQL_TIME field_time, item_time;
+ MYSQL_TIME field_time, item_time, item_time2, *item_time_cmp= &item_time;
if (field->type() == MYSQL_TYPE_TIME)
{
field->get_time(&field_time);
@@ -8858,8 +8860,11 @@ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item)
{
field->get_date(&field_time, TIME_INVALID_DATES);
item->get_date(&item_time, TIME_INVALID_DATES);
+ if (item_time.time_type == MYSQL_TIMESTAMP_TIME)
+ if (time_to_datetime(thd, &item_time, item_time_cmp= &item_time2))
+ return 1;
}
- return my_time_compare(&field_time, &item_time);
+ return my_time_compare(&field_time, item_time_cmp);
}
if (res_type == STRING_RESULT)
{
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index f142c51db4d..289668f24ca 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -900,9 +900,11 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg,
{
MYSQL_TIME ltime;
uint fuzzydate= TIME_FUZZY_DATES | TIME_INVALID_DATES;
- if (f_type == MYSQL_TYPE_TIME)
- fuzzydate|= TIME_TIME_ONLY;
- if (item->get_date(&ltime, fuzzydate))
+ if ((item->field_type() == MYSQL_TYPE_TIME &&
+ is_temporal_type_with_date(warn_item->field_type())) ?
+ item->get_date_with_conversion(&ltime, fuzzydate) :
+ item->get_date(&ltime, fuzzydate |
+ (f_type == MYSQL_TYPE_TIME ? TIME_TIME_ONLY : 0)))
value= 0; /* invalid date */
else
value= pack_time(&ltime);
@@ -2559,9 +2561,9 @@ Item_func_ifnull::str_op(String *str)
bool Item_func_ifnull::date_op(MYSQL_TIME *ltime, uint fuzzydate)
{
DBUG_ASSERT(fixed == 1);
- if (!args[0]->get_date(ltime, fuzzydate & ~TIME_FUZZY_DATES))
+ if (!args[0]->get_date_with_conversion(ltime, fuzzydate & ~TIME_FUZZY_DATES))
return (null_value= false);
- if (!args[1]->get_date(ltime, fuzzydate & ~TIME_FUZZY_DATES))
+ if (!args[1]->get_date_with_conversion(ltime, fuzzydate & ~TIME_FUZZY_DATES))
return (null_value= false);
bzero((char*) ltime,sizeof(*ltime));
return null_value= !(fuzzydate & TIME_FUZZY_DATES);
@@ -2752,7 +2754,7 @@ bool Item_func_if::date_op(MYSQL_TIME *ltime, uint fuzzydate)
{
DBUG_ASSERT(fixed == 1);
Item *arg= args[0]->val_bool() ? args[1] : args[2];
- return (null_value= arg->get_date(ltime, fuzzydate));
+ return (null_value= arg->get_date_with_conversion(ltime, fuzzydate));
}
@@ -2997,7 +2999,7 @@ bool Item_func_case::date_op(MYSQL_TIME *ltime, uint fuzzydate)
Item *item= find_item(&dummy_str);
if (!item)
return (null_value= true);
- return (null_value= item->get_date(ltime, fuzzydate));
+ return (null_value= item->get_date_with_conversion(ltime, fuzzydate));
}
@@ -3315,7 +3317,8 @@ bool Item_func_coalesce::date_op(MYSQL_TIME *ltime,uint fuzzydate)
null_value= 0;
for (uint i= 0; i < arg_count; i++)
{
- bool res= args[i]->get_date(ltime, fuzzydate & ~TIME_FUZZY_DATES);
+ bool res= args[i]->get_date_with_conversion(ltime,
+ fuzzydate & ~TIME_FUZZY_DATES);
if (!args[i]->null_value)
return res;
}
@@ -4896,21 +4899,20 @@ longlong Item_func_like::val_int()
Item_func::optimize_type Item_func_like::select_optimize() const
{
- if (args[1]->const_item() && !args[1]->is_expensive())
- {
- String* res2= args[1]->val_str((String *)&cmp.value2);
- const char *ptr2;
+ if (!args[1]->const_item() || args[1]->is_expensive())
+ return OPTIMIZE_NONE;
- if (!res2 || !(ptr2= res2->ptr()))
- return OPTIMIZE_NONE;
+ String* res2= args[1]->val_str((String *)&cmp.value2);
+ if (!res2)
+ return OPTIMIZE_NONE;
- if (*ptr2 != wild_many)
- {
- if (args[0]->result_type() != STRING_RESULT || *ptr2 != wild_one)
- return OPTIMIZE_OP;
- }
- }
- return OPTIMIZE_NONE;
+ if (!res2->length()) // Can optimize empty wildcard: column LIKE ''
+ return OPTIMIZE_OP;
+
+ DBUG_ASSERT(res2->ptr());
+ char first= res2->ptr()[0];
+ return (first == wild_many || first == wild_one) ?
+ OPTIMIZE_NONE : OPTIMIZE_OP;
}
diff --git a/sql/item_create.cc b/sql/item_create.cc
index a3e0dc6012b..193c7deb207 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -32,6 +32,7 @@
#include "set_var.h"
#include "sp_head.h"
#include "sp.h"
+#include "item_inetfunc.h"
#include "sql_time.h"
/*
@@ -1343,6 +1344,84 @@ protected:
};
+class Create_func_inet6_aton : public Create_func_arg1
+{
+public:
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
+
+ static Create_func_inet6_aton s_singleton;
+
+protected:
+ Create_func_inet6_aton() {}
+ virtual ~Create_func_inet6_aton() {}
+};
+
+
+class Create_func_inet6_ntoa : public Create_func_arg1
+{
+public:
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
+
+ static Create_func_inet6_ntoa s_singleton;
+
+protected:
+ Create_func_inet6_ntoa() {}
+ virtual ~Create_func_inet6_ntoa() {}
+};
+
+
+class Create_func_is_ipv4 : public Create_func_arg1
+{
+public:
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
+
+ static Create_func_is_ipv4 s_singleton;
+
+protected:
+ Create_func_is_ipv4() {}
+ virtual ~Create_func_is_ipv4() {}
+};
+
+
+class Create_func_is_ipv6 : public Create_func_arg1
+{
+public:
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
+
+ static Create_func_is_ipv6 s_singleton;
+
+protected:
+ Create_func_is_ipv6() {}
+ virtual ~Create_func_is_ipv6() {}
+};
+
+
+class Create_func_is_ipv4_compat : public Create_func_arg1
+{
+public:
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
+
+ static Create_func_is_ipv4_compat s_singleton;
+
+protected:
+ Create_func_is_ipv4_compat() {}
+ virtual ~Create_func_is_ipv4_compat() {}
+};
+
+
+class Create_func_is_ipv4_mapped : public Create_func_arg1
+{
+public:
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
+
+ static Create_func_is_ipv4_mapped s_singleton;
+
+protected:
+ Create_func_is_ipv4_mapped() {}
+ virtual ~Create_func_is_ipv4_mapped() {}
+};
+
+
class Create_func_instr : public Create_func_arg2
{
public:
@@ -4139,6 +4218,24 @@ Create_func_inet_ntoa::create_1_arg(THD *thd, Item *arg1)
}
+Create_func_inet6_aton Create_func_inet6_aton::s_singleton;
+
+Item*
+Create_func_inet6_aton::create_1_arg(THD *thd, Item *arg1)
+{
+ return new (thd->mem_root) Item_func_inet6_aton(arg1);
+}
+
+
+Create_func_inet6_ntoa Create_func_inet6_ntoa::s_singleton;
+
+Item*
+Create_func_inet6_ntoa::create_1_arg(THD *thd, Item *arg1)
+{
+ return new (thd->mem_root) Item_func_inet6_ntoa(arg1);
+}
+
+
Create_func_inet_aton Create_func_inet_aton::s_singleton;
Item*
@@ -4148,6 +4245,42 @@ Create_func_inet_aton::create_1_arg(THD *thd, Item *arg1)
}
+Create_func_is_ipv4 Create_func_is_ipv4::s_singleton;
+
+Item*
+Create_func_is_ipv4::create_1_arg(THD *thd, Item *arg1)
+{
+ return new (thd->mem_root) Item_func_is_ipv4(arg1);
+}
+
+
+Create_func_is_ipv6 Create_func_is_ipv6::s_singleton;
+
+Item*
+Create_func_is_ipv6::create_1_arg(THD *thd, Item *arg1)
+{
+ return new (thd->mem_root) Item_func_is_ipv6(arg1);
+}
+
+
+Create_func_is_ipv4_compat Create_func_is_ipv4_compat::s_singleton;
+
+Item*
+Create_func_is_ipv4_compat::create_1_arg(THD *thd, Item *arg1)
+{
+ return new (thd->mem_root) Item_func_is_ipv4_compat(arg1);
+}
+
+
+Create_func_is_ipv4_mapped Create_func_is_ipv4_mapped::s_singleton;
+
+Item*
+Create_func_is_ipv4_mapped::create_1_arg(THD *thd, Item *arg1)
+{
+ return new (thd->mem_root) Item_func_is_ipv4_mapped(arg1);
+}
+
+
Create_func_instr Create_func_instr::s_singleton;
Item*
@@ -5585,6 +5718,12 @@ static Native_func_registry func_array[] =
{ { C_STRING_WITH_LEN("IFNULL") }, BUILDER(Create_func_ifnull)},
{ { C_STRING_WITH_LEN("INET_ATON") }, BUILDER(Create_func_inet_aton)},
{ { C_STRING_WITH_LEN("INET_NTOA") }, BUILDER(Create_func_inet_ntoa)},
+ { { C_STRING_WITH_LEN("INET6_ATON") }, BUILDER(Create_func_inet6_aton)},
+ { { C_STRING_WITH_LEN("INET6_NTOA") }, BUILDER(Create_func_inet6_ntoa)},
+ { { C_STRING_WITH_LEN("IS_IPV4") }, BUILDER(Create_func_is_ipv4)},
+ { { C_STRING_WITH_LEN("IS_IPV6") }, BUILDER(Create_func_is_ipv6)},
+ { { C_STRING_WITH_LEN("IS_IPV4_COMPAT") }, BUILDER(Create_func_is_ipv4_compat)},
+ { { C_STRING_WITH_LEN("IS_IPV4_MAPPED") }, BUILDER(Create_func_is_ipv4_mapped)},
{ { C_STRING_WITH_LEN("INSTR") }, BUILDER(Create_func_instr)},
{ { C_STRING_WITH_LEN("INTERIORRINGN") }, GEOM_BUILDER(Create_func_interiorringn)},
{ { C_STRING_WITH_LEN("INTERSECTS") }, GEOM_BUILDER(Create_func_mbr_intersects)},
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 572c9fdde60..11110dddeb8 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2009, 2013, Monty Program Ab.
+/* Copyright (c) 2000, 2014, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2014, SkySQL Ab.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -1116,7 +1116,9 @@ bool Item_func_hybrid_result_type::get_date(MYSQL_TIME *ltime,
case INT_RESULT:
{
longlong value= int_op();
- if (null_value || int_to_datetime_with_warn(value, ltime, fuzzydate,
+ bool neg= !unsigned_flag && value < 0;
+ if (null_value || int_to_datetime_with_warn(neg, neg ? -value : value,
+ ltime, fuzzydate,
field_name_or_null()))
goto err;
break;
@@ -1961,9 +1963,11 @@ void Item_func_int_div::fix_length_and_dec()
{
Item_result argtype= args[0]->result_type();
/* use precision ony for the data type it is applicable for and valid */
- max_length=args[0]->max_length -
- (argtype == DECIMAL_RESULT || argtype == INT_RESULT ?
- args[0]->decimals : 0);
+ uint32 char_length= args[0]->max_char_length() -
+ (argtype == DECIMAL_RESULT || argtype == INT_RESULT ?
+ args[0]->decimals : 0);
+ fix_char_length(char_length > MY_INT64_NUM_DECIMAL_DIGITS ?
+ MY_INT64_NUM_DECIMAL_DIGITS : char_length);
maybe_null=1;
unsigned_flag=args[0]->unsigned_flag | args[1]->unsigned_flag;
}
@@ -6110,61 +6114,6 @@ void Item_func_get_system_var::cleanup()
}
-longlong Item_func_inet_aton::val_int()
-{
- DBUG_ASSERT(fixed == 1);
- uint byte_result = 0;
- ulonglong result = 0; // We are ready for 64 bit addresses
- const char *p,* end;
- char c = '.'; // we mark c to indicate invalid IP in case length is 0
- char buff[36];
- int dot_count= 0;
-
- String *s, tmp(buff, sizeof(buff), &my_charset_latin1);
- if (!(s = args[0]->val_str_ascii(&tmp))) // If null value
- goto err;
- null_value=0;
-
- end= (p = s->ptr()) + s->length();
- while (p < end)
- {
- c = *p++;
- int digit = (int) (c - '0');
- if (digit >= 0 && digit <= 9)
- {
- if ((byte_result = byte_result * 10 + digit) > 255)
- goto err; // Wrong address
- }
- else if (c == '.')
- {
- dot_count++;
- result= (result << 8) + (ulonglong) byte_result;
- byte_result = 0;
- }
- else
- goto err; // Invalid character
- }
- if (c != '.') // IP number can't end on '.'
- {
- /*
- Handle short-forms addresses according to standard. Examples:
- 127 -> 0.0.0.127
- 127.1 -> 127.0.0.1
- 127.2.1 -> 127.2.0.1
- */
- switch (dot_count) {
- case 1: result<<= 8; /* Fall through */
- case 2: result<<= 8; /* Fall through */
- }
- return (result << 8) + (ulonglong) byte_result;
- }
-
-err:
- null_value=1;
- return 0;
-}
-
-
void Item_func_match::init_search(bool no_order)
{
DBUG_ENTER("Item_func_match::init_search");
diff --git a/sql/item_func.h b/sql/item_func.h
index 69abecc5f39..1696898812d 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -1871,16 +1871,6 @@ public:
};
-class Item_func_inet_aton : public Item_int_func
-{
-public:
- Item_func_inet_aton(Item *a) :Item_int_func(a) {}
- longlong val_int();
- const char *func_name() const { return "inet_aton"; }
- void fix_length_and_dec() { decimals= 0; max_length= 21; maybe_null= 1; unsigned_flag= 1;}
-};
-
-
/* for fulltext search */
class Item_func_match :public Item_real_func
diff --git a/sql/item_inetfunc.cc b/sql/item_inetfunc.cc
new file mode 100644
index 00000000000..627ef728a2e
--- /dev/null
+++ b/sql/item_inetfunc.cc
@@ -0,0 +1,830 @@
+/* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2014 MariaDB Foundation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+#include "item_inetfunc.h"
+
+#include "my_net.h"
+
+///////////////////////////////////////////////////////////////////////////
+
+static const int IN_ADDR_SIZE= sizeof (in_addr);
+static const int IN6_ADDR_SIZE= sizeof (in6_addr);
+static const int IN6_ADDR_NUM_WORDS= IN6_ADDR_SIZE / 2;
+
+static const char HEX_DIGITS[]= "0123456789abcdef";
+
+///////////////////////////////////////////////////////////////////////////
+
+longlong Item_func_inet_aton::val_int()
+{
+ DBUG_ASSERT(fixed);
+
+ uint byte_result= 0;
+ ulonglong result= 0; // We are ready for 64 bit addresses
+ const char *p,* end;
+ char c= '.'; // we mark c to indicate invalid IP in case length is 0
+ int dot_count= 0;
+
+ StringBuffer<36> tmp;
+ String *s= args[0]->val_str_ascii(&tmp);
+
+ if (!s) // If null value
+ goto err;
+
+ null_value= 0;
+
+ end= (p = s->ptr()) + s->length();
+ while (p < end)
+ {
+ c= *p++;
+ int digit= (int) (c - '0');
+ if (digit >= 0 && digit <= 9)
+ {
+ if ((byte_result= byte_result * 10 + digit) > 255)
+ goto err; // Wrong address
+ }
+ else if (c == '.')
+ {
+ dot_count++;
+ result= (result << 8) + (ulonglong) byte_result;
+ byte_result= 0;
+ }
+ else
+ goto err; // Invalid character
+ }
+ if (c != '.') // IP number can't end on '.'
+ {
+ /*
+ Attempt to support short forms of IP-addresses. It's however pretty
+ basic one comparing to the BSD support.
+ Examples:
+ 127 -> 0.0.0.127
+ 127.255 -> 127.0.0.255
+ 127.256 -> NULL (should have been 127.0.1.0)
+ 127.2.1 -> 127.2.0.1
+ */
+ switch (dot_count) {
+ case 1: result<<= 8; /* Fall through */
+ case 2: result<<= 8; /* Fall through */
+ }
+ return (result << 8) + (ulonglong) byte_result;
+ }
+
+err:
+ null_value=1;
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+String* Item_func_inet_ntoa::val_str(String* str)
+{
+ DBUG_ASSERT(fixed);
+
+ ulonglong n= (ulonglong) args[0]->val_int();
+
+ /*
+ We do not know if args[0] is NULL until we have called
+ some val function on it if args[0] is not a constant!
+
+ Also return null if n > 255.255.255.255
+ */
+ if ((null_value= (args[0]->null_value || n > 0xffffffff)))
+ return 0; // Null value
+
+ str->set_charset(collation.collation);
+ str->length(0);
+
+ uchar buf[8];
+ int4store(buf, n);
+
+ /* Now we can assume little endian. */
+
+ char num[4];
+ num[3]= '.';
+
+ for (uchar *p= buf + 4; p-- > buf;)
+ {
+ uint c= *p;
+ uint n1, n2; // Try to avoid divisions
+ n1= c / 100; // 100 digits
+ c-= n1 * 100;
+ n2= c / 10; // 10 digits
+ c-= n2 * 10; // last digit
+ num[0]= (char) n1 + '0';
+ num[1]= (char) n2 + '0';
+ num[2]= (char) c + '0';
+ uint length= (n1 ? 4 : n2 ? 3 : 2); // Remove pre-zero
+ uint dot_length= (p <= buf) ? 1 : 0;
+ (void) str->append(num + 4 - length, length - dot_length,
+ &my_charset_latin1);
+ }
+
+ return str;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+ Check the function argument, handle errors properly.
+
+ @return The function value.
+*/
+
+longlong Item_func_inet_bool_base::val_int()
+{
+ DBUG_ASSERT(fixed);
+
+ if (args[0]->result_type() != STRING_RESULT) // String argument expected
+ return 0;
+
+ String buffer;
+ String *arg_str= args[0]->val_str(&buffer);
+
+ if (!arg_str) // Out-of memory happened. The error has been reported.
+ return 0; // Or: the underlying field is NULL
+
+ return calc_value(arg_str) ? 1 : 0;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+ Check the function argument, handle errors properly.
+
+ @param [out] buffer Buffer for string operations.
+
+ @return The function value.
+*/
+
+String *Item_func_inet_str_base::val_str_ascii(String *buffer)
+{
+ DBUG_ASSERT(fixed);
+
+ if (args[0]->result_type() != STRING_RESULT) // String argument expected
+ {
+ null_value= true;
+ return NULL;
+ }
+
+ String *arg_str= args[0]->val_str(buffer);
+ if (!arg_str) // Out-of memory happened. The error has been reported.
+ { // Or: the underlying field is NULL
+ null_value= true;
+ return NULL;
+ }
+
+ null_value= !calc_value(arg_str, buffer);
+
+ return null_value ? NULL : buffer;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+ Tries to convert given string to binary IPv4-address representation.
+ This is a portable alternative to inet_pton(AF_INET).
+
+ @param str String to convert.
+ @param str_len String length.
+ @param[out] ipv4_address Buffer to store IPv4-address.
+
+ @return Completion status.
+ @retval false Given string does not represent an IPv4-address.
+ @retval true The string has been converted sucessfully.
+
+ @note The problem with inet_pton() is that it treats leading zeros in
+ IPv4-part differently on different platforms.
+*/
+
+static bool str_to_ipv4(const char *str, int str_length, in_addr *ipv4_address)
+{
+ if (str_length < 7)
+ {
+ DBUG_PRINT("error", ("str_to_ipv4(%.*s): "
+ "invalid IPv4 address: too short.",
+ str_length, str));
+ return false;
+ }
+
+ if (str_length > 15)
+ {
+ DBUG_PRINT("error", ("str_to_ipv4(%.*s): "
+ "invalid IPv4 address: too long.",
+ str_length, str));
+ return false;
+ }
+
+ unsigned char *ipv4_bytes= (unsigned char *) ipv4_address;
+ const char *p= str;
+ int byte_value= 0;
+ int chars_in_group= 0;
+ int dot_count= 0;
+ char c= 0;
+
+ while (((p - str) < str_length) && *p)
+ {
+ c= *p++;
+
+ if (my_isdigit(&my_charset_latin1, c))
+ {
+ ++chars_in_group;
+
+ if (chars_in_group > 3)
+ {
+ DBUG_PRINT("error", ("str_to_ipv4(%.*s): invalid IPv4 address: "
+ "too many characters in a group.",
+ str_length, str));
+ return false;
+ }
+
+ byte_value= byte_value * 10 + (c - '0');
+
+ if (byte_value > 255)
+ {
+ DBUG_PRINT("error", ("str_to_ipv4(%.*s): invalid IPv4 address: "
+ "invalid byte value.",
+ str_length, str));
+ return false;
+ }
+ }
+ else if (c == '.')
+ {
+ if (chars_in_group == 0)
+ {
+ DBUG_PRINT("error", ("str_to_ipv4(%.*s): invalid IPv4 address: "
+ "too few characters in a group.",
+ str_length, str));
+ return false;
+ }
+
+ ipv4_bytes[dot_count]= (unsigned char) byte_value;
+
+ ++dot_count;
+ byte_value= 0;
+ chars_in_group= 0;
+
+ if (dot_count > 3)
+ {
+ DBUG_PRINT("error", ("str_to_ipv4(%.*s): invalid IPv4 address: "
+ "too many dots.", str_length, str));
+ return false;
+ }
+ }
+ else
+ {
+ DBUG_PRINT("error", ("str_to_ipv4(%.*s): invalid IPv4 address: "
+ "invalid character at pos %d.",
+ str_length, str, (int) (p - str)));
+ return false;
+ }
+ }
+
+ if (c == '.')
+ {
+ DBUG_PRINT("error", ("str_to_ipv4(%.*s): invalid IPv4 address: "
+ "ending at '.'.", str_length, str));
+ return false;
+ }
+
+ if (dot_count != 3)
+ {
+ DBUG_PRINT("error", ("str_to_ipv4(%.*s): invalid IPv4 address: "
+ "too few groups.",
+ str_length, str));
+ return false;
+ }
+
+ ipv4_bytes[3]= (unsigned char) byte_value;
+
+ DBUG_PRINT("info", ("str_to_ipv4(%.*s): valid IPv4 address: %d.%d.%d.%d",
+ str_length, str,
+ ipv4_bytes[0], ipv4_bytes[1],
+ ipv4_bytes[2], ipv4_bytes[3]));
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+ Tries to convert given string to binary IPv6-address representation.
+ This is a portable alternative to inet_pton(AF_INET6).
+
+ @param str String to convert.
+ @param str_len String length.
+ @param[out] ipv6_address Buffer to store IPv6-address.
+
+ @return Completion status.
+ @retval false Given string does not represent an IPv6-address.
+ @retval true The string has been converted sucessfully.
+
+ @note The problem with inet_pton() is that it treats leading zeros in
+ IPv4-part differently on different platforms.
+*/
+
+static bool str_to_ipv6(const char *str, int str_length, in6_addr *ipv6_address)
+{
+ if (str_length < 2)
+ {
+ DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: too short.",
+ str_length, str));
+ return false;
+ }
+
+ if (str_length > 8 * 4 + 7)
+ {
+ DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: too long.",
+ str_length, str));
+ return false;
+ }
+
+ memset(ipv6_address, 0, IN6_ADDR_SIZE);
+
+ const char *p= str;
+
+ if (*p == ':')
+ {
+ ++p;
+
+ if (*p != ':')
+ {
+ DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: "
+ "can not start with ':x'.", str_length, str));
+ return false;
+ }
+ }
+
+ char *ipv6_bytes= (char *) ipv6_address;
+ char *ipv6_bytes_end= ipv6_bytes + IN6_ADDR_SIZE;
+ char *dst= ipv6_bytes;
+ char *gap_ptr= NULL;
+ const char *group_start_ptr= p;
+ int chars_in_group= 0;
+ int group_value= 0;
+
+ while (((p - str) < str_length) && *p)
+ {
+ char c= *p++;
+
+ if (c == ':')
+ {
+ group_start_ptr= p;
+
+ if (!chars_in_group)
+ {
+ if (gap_ptr)
+ {
+ DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: "
+ "too many gaps(::).", str_length, str));
+ return false;
+ }
+
+ gap_ptr= dst;
+ continue;
+ }
+
+ if (!*p || ((p - str) >= str_length))
+ {
+ DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: "
+ "ending at ':'.", str_length, str));
+ return false;
+ }
+
+ if (dst + 2 > ipv6_bytes_end)
+ {
+ DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: "
+ "too many groups (1).", str_length, str));
+ return false;
+ }
+
+ dst[0]= (unsigned char) (group_value >> 8) & 0xff;
+ dst[1]= (unsigned char) group_value & 0xff;
+ dst += 2;
+
+ chars_in_group= 0;
+ group_value= 0;
+ }
+ else if (c == '.')
+ {
+ if (dst + IN_ADDR_SIZE > ipv6_bytes_end)
+ {
+ DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: "
+ "unexpected IPv4-part.", str_length, str));
+ return false;
+ }
+
+ if (!str_to_ipv4(group_start_ptr,
+ str + str_length - group_start_ptr,
+ (in_addr *) dst))
+ {
+ DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: "
+ "invalid IPv4-part.", str_length, str));
+ return false;
+ }
+
+ dst += IN_ADDR_SIZE;
+ chars_in_group= 0;
+
+ break;
+ }
+ else
+ {
+ const char *hdp= strchr(HEX_DIGITS, my_tolower(&my_charset_latin1, c));
+
+ if (!hdp)
+ {
+ DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: "
+ "invalid character at pos %d.",
+ str_length, str, (int) (p - str)));
+ return false;
+ }
+
+ if (chars_in_group >= 4)
+ {
+ DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: "
+ "too many digits in group.",
+ str_length, str));
+ return false;
+ }
+
+ group_value <<= 4;
+ group_value |= hdp - HEX_DIGITS;
+
+ DBUG_ASSERT(group_value <= 0xffff);
+
+ ++chars_in_group;
+ }
+ }
+
+ if (chars_in_group > 0)
+ {
+ if (dst + 2 > ipv6_bytes_end)
+ {
+ DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: "
+ "too many groups (2).", str_length, str));
+ return false;
+ }
+
+ dst[0]= (unsigned char) (group_value >> 8) & 0xff;
+ dst[1]= (unsigned char) group_value & 0xff;
+ dst += 2;
+ }
+
+ if (gap_ptr)
+ {
+ if (dst == ipv6_bytes_end)
+ {
+ DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: "
+ "no room for a gap (::).", str_length, str));
+ return false;
+ }
+
+ int bytes_to_move= dst - gap_ptr;
+
+ for (int i= 1; i <= bytes_to_move; ++i)
+ {
+ ipv6_bytes_end[-i]= gap_ptr[bytes_to_move - i];
+ gap_ptr[bytes_to_move - i]= 0;
+ }
+
+ dst= ipv6_bytes_end;
+ }
+
+ if (dst < ipv6_bytes_end)
+ {
+ DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: "
+ "too few groups.", str_length, str));
+ return false;
+ }
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+ Converts IPv4-binary-address to a string. This function is a portable
+ alternative to inet_ntop(AF_INET).
+
+ @param[in] ipv4 IPv4-address data (byte array)
+ @param[out] str A buffer to store string representation of IPv4-address.
+ It must be at least of INET_ADDRSTRLEN.
+
+ @note The problem with inet_ntop() is that it is available starting from
+ Windows Vista, but the minimum supported version is Windows 2000.
+*/
+
+static void ipv4_to_str(const in_addr *ipv4, char *str)
+{
+ const unsigned char *ipv4_bytes= (const unsigned char *) ipv4;
+
+ sprintf(str, "%d.%d.%d.%d",
+ ipv4_bytes[0], ipv4_bytes[1], ipv4_bytes[2], ipv4_bytes[3]);
+}
+///////////////////////////////////////////////////////////////////////////
+
+/**
+ Converts IPv6-binary-address to a string. This function is a portable
+ alternative to inet_ntop(AF_INET6).
+
+ @param[in] ipv6 IPv6-address data (byte array)
+ @param[out] str A buffer to store string representation of IPv6-address.
+ It must be at least of INET6_ADDRSTRLEN.
+
+ @note The problem with inet_ntop() is that it is available starting from
+ Windows Vista, but out the minimum supported version is Windows 2000.
+*/
+
+static void ipv6_to_str(const in6_addr *ipv6, char *str)
+{
+ struct Region
+ {
+ int pos;
+ int length;
+ };
+
+ const unsigned char *ipv6_bytes= (const unsigned char *) ipv6;
+
+ // 1. Translate IPv6-address bytes to words.
+ // We can't just cast to short, because it's not guaranteed
+ // that sizeof (short) == 2. So, we have to make a copy.
+
+ uint16 ipv6_words[IN6_ADDR_NUM_WORDS];
+
+ for (int i= 0; i < IN6_ADDR_NUM_WORDS; ++i)
+ ipv6_words[i]= (ipv6_bytes[2 * i] << 8) + ipv6_bytes[2 * i + 1];
+
+ // 2. Find "the gap" -- longest sequence of zeros in IPv6-address.
+
+ Region gap= { -1, -1 };
+
+ {
+ Region rg= { -1, -1 };
+
+ for (int i = 0; i < IN6_ADDR_NUM_WORDS; ++i)
+ {
+ if (ipv6_words[i] != 0)
+ {
+ if (rg.pos >= 0)
+ {
+ if (rg.length > gap.length)
+ gap= rg;
+
+ rg.pos= -1;
+ rg.length= -1;
+ }
+ }
+ else
+ {
+ if (rg.pos >= 0)
+ {
+ ++rg.length;
+ }
+ else
+ {
+ rg.pos= i;
+ rg.length= 1;
+ }
+ }
+ }
+
+ if (rg.pos >= 0)
+ {
+ if (rg.length > gap.length)
+ gap= rg;
+ }
+ }
+
+ // 3. Convert binary data to string.
+
+ char *p= str;
+
+ for (int i = 0; i < IN6_ADDR_NUM_WORDS; ++i)
+ {
+ if (i == gap.pos)
+ {
+ // We're at the gap position. We should put trailing ':' and jump to
+ // the end of the gap.
+
+ if (i == 0)
+ {
+ // The gap starts from the beginning of the data -- leading ':'
+ // should be put additionally.
+
+ *p= ':';
+ ++p;
+ }
+
+ *p= ':';
+ ++p;
+
+ i += gap.length - 1;
+ }
+ else if (i == 6 && gap.pos == 0 &&
+ (gap.length == 6 || // IPv4-compatible
+ (gap.length == 5 && ipv6_words[5] == 0xffff) // IPv4-mapped
+ ))
+ {
+ // The data represents either IPv4-compatible or IPv4-mapped address.
+ // The IPv6-part (zeros or zeros + ffff) has been already put into
+ // the string (str). Now it's time to dump IPv4-part.
+
+ ipv4_to_str((const in_addr *) (ipv6_bytes + 12), p);
+ return;
+ }
+ else
+ {
+ // Usual IPv6-address-field. Print it out using lower-case
+ // hex-letters without leading zeros (recommended IPv6-format).
+ //
+ // If it is not the last field, append closing ':'.
+
+ p += sprintf(p, "%x", ipv6_words[i]);
+
+ if (i != IN6_ADDR_NUM_WORDS - 1)
+ {
+ *p= ':';
+ ++p;
+ }
+ }
+ }
+
+ *p= 0;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+ Converts IP-address-string to IP-address-data.
+
+ @param arg IP-address-string.
+ @param [out] buffer Buffer to store IP-address-data.
+
+ @return Completion status.
+ @retval false Given string does not represent an IP-address.
+ @retval true The string has been converted sucessfully.
+*/
+
+bool Item_func_inet6_aton::calc_value(String *arg, String *buffer)
+{
+ // ipv4-string -> varbinary(4)
+ // ipv6-string -> varbinary(16)
+
+ in_addr ipv4_address;
+ in6_addr ipv6_address;
+
+ if (str_to_ipv4(arg->ptr(), arg->length(), &ipv4_address))
+ {
+ buffer->length(0);
+ buffer->append((char *) &ipv4_address, sizeof (in_addr), &my_charset_bin);
+
+ return true;
+ }
+
+ if (str_to_ipv6(arg->ptr(), arg->length(), &ipv6_address))
+ {
+ buffer->length(0);
+ buffer->append((char *) &ipv6_address, sizeof (in6_addr), &my_charset_bin);
+
+ return true;
+ }
+
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+ Converts IP-address-data to IP-address-string.
+
+ @param arg IP-address-data.
+ @param [out] buffer Buffer to store IP-address-string.
+
+ @return Completion status.
+ @retval false The argument does not correspond to IP-address.
+ @retval true The string has been converted sucessfully.
+*/
+
+bool Item_func_inet6_ntoa::calc_value(String *arg, String *buffer)
+{
+ if (arg->charset() != &my_charset_bin)
+ return false;
+
+ if ((int) arg->length() == IN_ADDR_SIZE)
+ {
+ char str[INET_ADDRSTRLEN];
+
+ ipv4_to_str((const in_addr *) arg->ptr(), str);
+
+ buffer->length(0);
+ buffer->append(str, (uint32) strlen(str), &my_charset_latin1);
+
+ return true;
+ }
+ else if ((int) arg->length() == IN6_ADDR_SIZE)
+ {
+ char str[INET6_ADDRSTRLEN];
+
+ ipv6_to_str((const in6_addr *) arg->ptr(), str);
+
+ buffer->length(0);
+ buffer->append(str, (uint32) strlen(str), &my_charset_latin1);
+
+ return true;
+ }
+
+ DBUG_PRINT("info",
+ ("INET6_NTOA(): varbinary(4) or varbinary(16) expected."));
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+ Checks if the passed string represents an IPv4-address.
+
+ @param arg The string to check.
+
+ @return Check status.
+ @retval false The passed string does not represent an IPv4-address.
+ @retval true The passed string represents an IPv4-address.
+*/
+
+bool Item_func_is_ipv4::calc_value(const String *arg)
+{
+ in_addr ipv4_address;
+
+ return str_to_ipv4(arg->ptr(), arg->length(), &ipv4_address);
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+ Checks if the passed string represents an IPv6-address.
+
+ @param arg The string to check.
+
+ @return Check status.
+ @retval false The passed string does not represent an IPv6-address.
+ @retval true The passed string represents an IPv6-address.
+*/
+
+bool Item_func_is_ipv6::calc_value(const String *arg)
+{
+ in6_addr ipv6_address;
+
+ return str_to_ipv6(arg->ptr(), arg->length(), &ipv6_address);
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+ Checks if the passed IPv6-address is an IPv4-compat IPv6-address.
+
+ @param arg The IPv6-address to check.
+
+ @return Check status.
+ @retval false The passed IPv6-address is not an IPv4-compatible IPv6-address.
+ @retval true The passed IPv6-address is an IPv4-compatible IPv6-address.
+*/
+
+bool Item_func_is_ipv4_compat::calc_value(const String *arg)
+{
+ if ((int) arg->length() != IN6_ADDR_SIZE || arg->charset() != &my_charset_bin)
+ return false;
+
+ return IN6_IS_ADDR_V4COMPAT((struct in6_addr *) arg->ptr());
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+ Checks if the passed IPv6-address is an IPv4-mapped IPv6-address.
+
+ @param arg The IPv6-address to check.
+
+ @return Check status.
+ @retval false The passed IPv6-address is not an IPv4-mapped IPv6-address.
+ @retval true The passed IPv6-address is an IPv4-mapped IPv6-address.
+*/
+
+bool Item_func_is_ipv4_mapped::calc_value(const String *arg)
+{
+ if ((int) arg->length() != IN6_ADDR_SIZE || arg->charset() != &my_charset_bin)
+ return false;
+
+ return IN6_IS_ADDR_V4MAPPED((struct in6_addr *) arg->ptr());
+}
diff --git a/sql/item_inetfunc.h b/sql/item_inetfunc.h
new file mode 100644
index 00000000000..3a85d367ff1
--- /dev/null
+++ b/sql/item_inetfunc.h
@@ -0,0 +1,244 @@
+#ifndef ITEM_INETFUNC_INCLUDED
+#define ITEM_INETFUNC_INCLUDED
+
+/* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2014 MariaDB Foundation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+
+#include "item.h"
+
+/*************************************************************************
+ Item_func_inet_aton implements INET_ATON() SQL-function.
+*************************************************************************/
+
+class Item_func_inet_aton : public Item_int_func
+{
+public:
+ Item_func_inet_aton(Item *a) :Item_int_func(a) {}
+ longlong val_int();
+ const char *func_name() const { return "inet_aton"; }
+ void fix_length_and_dec()
+ {
+ decimals= 0;
+ max_length= 21;
+ maybe_null= 1;
+ unsigned_flag= 1;
+ }
+};
+
+
+/*************************************************************************
+ Item_func_inet_ntoa implements INET_NTOA() SQL-function.
+*************************************************************************/
+
+class Item_func_inet_ntoa : public Item_str_func
+{
+public:
+ Item_func_inet_ntoa(Item *a)
+ : Item_str_func(a)
+ { }
+ String* val_str(String* str);
+ const char *func_name() const { return "inet_ntoa"; }
+ void fix_length_and_dec()
+ {
+ decimals= 0;
+ fix_length_and_charset(3 * 8 + 7, default_charset());
+ maybe_null= 1;
+ }
+};
+
+
+/*************************************************************************
+ Item_func_inet_bool_base implements common code for INET6/IP-related
+ functions returning boolean value.
+*************************************************************************/
+
+class Item_func_inet_bool_base : public Item_bool_func
+{
+public:
+ inline Item_func_inet_bool_base(Item *ip_addr)
+ : Item_bool_func(ip_addr)
+ {
+ null_value= false;
+ }
+
+public:
+ virtual longlong val_int();
+
+protected:
+ virtual bool calc_value(const String *arg) = 0;
+};
+
+
+/*************************************************************************
+ Item_func_inet_str_base implements common code for INET6/IP-related
+ functions returning string value.
+*************************************************************************/
+
+class Item_func_inet_str_base : public Item_str_ascii_func
+{
+public:
+ inline Item_func_inet_str_base(Item *arg)
+ : Item_str_ascii_func(arg)
+ { }
+
+public:
+ virtual String *val_str_ascii(String *buffer);
+
+protected:
+ virtual bool calc_value(String *arg, String *buffer) = 0;
+};
+
+
+/*************************************************************************
+ Item_func_inet6_aton implements INET6_ATON() SQL-function.
+*************************************************************************/
+
+class Item_func_inet6_aton : public Item_func_inet_str_base
+{
+public:
+ inline Item_func_inet6_aton(Item *ip_addr)
+ : Item_func_inet_str_base(ip_addr)
+ { }
+
+public:
+ virtual const char *func_name() const
+ { return "inet6_aton"; }
+
+ virtual void fix_length_and_dec()
+ {
+ decimals= 0;
+ fix_length_and_charset(16, &my_charset_bin);
+ maybe_null= 1;
+ }
+
+protected:
+ virtual bool calc_value(String *arg, String *buffer);
+};
+
+
+/*************************************************************************
+ Item_func_inet6_ntoa implements INET6_NTOA() SQL-function.
+*************************************************************************/
+
+class Item_func_inet6_ntoa : public Item_func_inet_str_base
+{
+public:
+ inline Item_func_inet6_ntoa(Item *ip_addr)
+ : Item_func_inet_str_base(ip_addr)
+ { }
+
+public:
+ virtual const char *func_name() const
+ { return "inet6_ntoa"; }
+
+ virtual void fix_length_and_dec()
+ {
+ decimals= 0;
+
+ // max length: IPv6-address -- 16 bytes
+ // 16 bytes / 2 bytes per group == 8 groups => 7 delimiter
+ // 4 symbols per group
+ fix_length_and_charset(8 * 4 + 7, default_charset());
+
+ maybe_null= 1;
+ }
+
+protected:
+ virtual bool calc_value(String *arg, String *buffer);
+};
+
+
+/*************************************************************************
+ Item_func_is_ipv4 implements IS_IPV4() SQL-function.
+*************************************************************************/
+
+class Item_func_is_ipv4 : public Item_func_inet_bool_base
+{
+public:
+ inline Item_func_is_ipv4(Item *ip_addr)
+ : Item_func_inet_bool_base(ip_addr)
+ { }
+
+public:
+ virtual const char *func_name() const
+ { return "is_ipv4"; }
+
+protected:
+ virtual bool calc_value(const String *arg);
+};
+
+
+/*************************************************************************
+ Item_func_is_ipv6 implements IS_IPV6() SQL-function.
+*************************************************************************/
+
+class Item_func_is_ipv6 : public Item_func_inet_bool_base
+{
+public:
+ inline Item_func_is_ipv6(Item *ip_addr)
+ : Item_func_inet_bool_base(ip_addr)
+ { }
+
+public:
+ virtual const char *func_name() const
+ { return "is_ipv6"; }
+
+protected:
+ virtual bool calc_value(const String *arg);
+};
+
+
+/*************************************************************************
+ Item_func_is_ipv4_compat implements IS_IPV4_COMPAT() SQL-function.
+*************************************************************************/
+
+class Item_func_is_ipv4_compat : public Item_func_inet_bool_base
+{
+public:
+ inline Item_func_is_ipv4_compat(Item *ip_addr)
+ : Item_func_inet_bool_base(ip_addr)
+ { }
+
+public:
+ virtual const char *func_name() const
+ { return "is_ipv4_compat"; }
+
+protected:
+ virtual bool calc_value(const String *arg);
+};
+
+
+/*************************************************************************
+ Item_func_is_ipv4_mapped implements IS_IPV4_MAPPED() SQL-function.
+*************************************************************************/
+
+class Item_func_is_ipv4_mapped : public Item_func_inet_bool_base
+{
+public:
+ inline Item_func_is_ipv4_mapped(Item *ip_addr)
+ : Item_func_inet_bool_base(ip_addr)
+ { }
+
+public:
+ virtual const char *func_name() const
+ { return "is_ipv4_mapped"; }
+
+protected:
+ virtual bool calc_value(const String *arg);
+};
+
+#endif // ITEM_INETFUNC_INCLUDED
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 100d54133dd..ec6ab0f3040 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -3861,48 +3861,6 @@ void Item_func_export_set::fix_length_and_dec()
fix_char_length(length * 64 + sep_length * 63);
}
-String* Item_func_inet_ntoa::val_str(String* str)
-{
- DBUG_ASSERT(fixed == 1);
- uchar buf[8], *p;
- ulonglong n = (ulonglong) args[0]->val_int();
- char num[4];
-
- /*
- We do not know if args[0] is NULL until we have called
- some val function on it if args[0] is not a constant!
-
- Also return null if n > 255.255.255.255
- */
- if ((null_value= (args[0]->null_value || n > 0xffffffff)))
- return 0; // Null value
-
- str->set_charset(collation.collation);
- str->length(0);
- int4store(buf,n);
-
- /* Now we can assume little endian. */
-
- num[3]='.';
- for (p=buf+4 ; p-- > buf ; )
- {
- uint c = *p;
- uint n1,n2; // Try to avoid divisions
- n1= c / 100; // 100 digits
- c-= n1*100;
- n2= c / 10; // 10 digits
- c-=n2*10; // last digit
- num[0]=(char) n1+'0';
- num[1]=(char) n2+'0';
- num[2]=(char) c+'0';
- uint length= (n1 ? 4 : n2 ? 3 : 2); // Remove pre-zero
- uint dot_length= (p <= buf) ? 1 : 0;
- (void) str->append(num + 4 - length, length - dot_length,
- &my_charset_latin1);
- }
- return str;
-}
-
#define get_esc_bit(mask, num) (1 & (*((mask) + ((num) >> 3))) >> ((num) & 7))
@@ -5098,8 +5056,10 @@ bool Item_dyncol_get::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
case DYN_COL_UINT:
if (signed_value || val.x.ulong_value <= LONGLONG_MAX)
{
- if (int_to_datetime_with_warn(val.x.ulong_value, ltime, fuzzy_date,
- 0 /* TODO */))
+ bool neg= val.x.ulong_value > LONGLONG_MAX;
+ if (int_to_datetime_with_warn(neg, neg ? -val.x.ulong_value :
+ val.x.ulong_value,
+ ltime, fuzzy_date, 0 /* TODO */))
goto null;
return 0;
}
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index ff8a916d200..f3d5c064423 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -880,21 +880,6 @@ class Item_func_export_set: public Item_str_func
const char *func_name() const { return "export_set"; }
};
-class Item_func_inet_ntoa : public Item_str_func
-{
-public:
- Item_func_inet_ntoa(Item *a) :Item_str_func(a)
- {
- }
- String* val_str(String* str);
- const char *func_name() const { return "inet_ntoa"; }
- void fix_length_and_dec()
- {
- decimals= 0;
- fix_length_and_charset(3 * 8 + 7, default_charset());
- maybe_null= 1;
- }
-};
class Item_func_quote :public Item_str_func
{
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 0aaeb3d55db..5fddad56028 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -1298,6 +1298,16 @@ bool get_interval_value(Item *args,interval_type int_type, INTERVAL *interval)
if (!(val= args->val_decimal(&decimal_value)))
return true;
interval->neg= my_decimal2seconds(val, &second, &second_part);
+ if (second == LONGLONG_MAX)
+ {
+ ErrConvDecimal err(val);
+ push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_TRUNCATED_WRONG_VALUE,
+ ER(ER_TRUNCATED_WRONG_VALUE), "DECIMAL",
+ err.ptr());
+ return true;
+ }
+
interval->second= second;
interval->second_part= second_part;
return false;
diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc
index 30db7e635e2..759b929ff82 100644
--- a/sql/item_xmlfunc.cc
+++ b/sql/item_xmlfunc.cc
@@ -2899,7 +2899,7 @@ bool Item_func_xml_update::collect_result(String *str,
str->length(0);
str->set_charset(collation.collation);
return
- /* Put the XML part preceeding the replaced piece */
+ /* Put the XML part preceding the replaced piece */
str->append(xml.raw()->ptr(), cut->beg - xml.raw()->ptr() - offs) ||
/* Put the replacement */
str->append(replace->ptr(), replace->length()) ||
diff --git a/sql/log_event.cc b/sql/log_event.cc
index c8b394e8290..4edd41fdb2e 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -4101,7 +4101,7 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi,
if ((error= rows_event_stmt_cleanup(rgi, thd)))
{
const_cast<Relay_log_info*>(rli)->report(ERROR_LEVEL, error,
- "Error in cleaning up after an event preceeding the commit; "
+ "Error in cleaning up after an event preceding the commit; "
"the group log file/position: %s %s",
const_cast<Relay_log_info*>(rli)->group_master_log_name,
llstr(const_cast<Relay_log_info*>(rli)->group_master_log_pos,
diff --git a/sql/log_event.h b/sql/log_event.h
index 020af59ae81..2091d968558 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -2004,7 +2004,7 @@ public:
bool is_valid() const { return query != 0; }
/*
- Returns number of bytes additionaly written to post header by derived
+ Returns number of bytes additionally written to post header by derived
events (so far it is only Execute_load_query event).
*/
virtual ulong get_post_header_size_for_derived() { return 0; }
diff --git a/sql/multi_range_read.cc b/sql/multi_range_read.cc
index 0c35ac5b029..b63db9ecea2 100644
--- a/sql/multi_range_read.cc
+++ b/sql/multi_range_read.cc
@@ -1341,8 +1341,14 @@ int Key_value_records_iterator::get_next(range_id_t *range_info)
}
handler *h= owner->file;
+ uchar *lookup_key;
+ if (owner->keypar.use_key_pointers)
+ memcpy(&lookup_key, identical_key_it.read_ptr1, sizeof(void*));
+ else
+ lookup_key= identical_key_it.read_ptr1;
+
if ((res= h->ha_index_next_same(h->get_table()->record[0],
- identical_key_it.read_ptr1,
+ lookup_key,
owner->keypar.key_tuple_length)))
{
/* It's either HA_ERR_END_OF_FILE or some other error */
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index b523769677e..3ba38ac6ec2 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -2174,6 +2174,7 @@ void clean_up(bool print_message)
free_global_table_stats();
free_global_index_stats();
delete_dynamic(&all_options);
+ free_all_rpl_filters();
#ifdef HAVE_REPLICATION
end_slave_list();
#endif
@@ -2216,6 +2217,13 @@ void clean_up(bool print_message)
mysql_mutex_unlock(&LOCK_thread_count);
free_list(opt_plugin_load_list_ptr);
+
+ if (THR_THD)
+ (void) pthread_key_delete(THR_THD);
+
+ if (THR_MALLOC)
+ (void) pthread_key_delete(THR_MALLOC);
+
/*
The following lines may never be executed as the main thread may have
killed us
@@ -7886,7 +7894,7 @@ struct my_option my_long_options[]=
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"plugin-load-add", OPT_PLUGIN_LOAD_ADD,
"Optional semicolon-separated list of plugins to load. This option adds "
- "to the list speficied by --plugin-load in an incremental way. "
+ "to the list specified by --plugin-load in an incremental way. "
"It can be specified many times, adding more plugins every time.",
0, 0, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index bfba74cf587..fc2aa75e604 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -8291,6 +8291,17 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
if (field->cmp_type() == STRING_RESULT && value->cmp_type() != STRING_RESULT)
goto end;
err= value->save_in_field_no_warnings(field, 1);
+ if (err == 2 && field->cmp_type() == STRING_RESULT)
+ {
+ if (type == Item_func::EQ_FUNC)
+ {
+ tree= new (alloc) SEL_ARG(field, 0, 0);
+ tree->type= SEL_ARG::IMPOSSIBLE;
+ }
+ else
+ tree= NULL; /* Cannot infer anything */
+ goto end;
+ }
if (err > 0)
{
if (field->cmp_type() != value->result_type())
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index e00083c4b8b..6e65b5ea177 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -4120,6 +4120,7 @@ SJ_TMP_TABLE::create_sj_weedout_tmp_table(THD *thd)
{
if (!(key_field= field->new_key_field(thd->mem_root, table,
group_buff,
+ key_part_info->length,
field->null_ptr,
field->null_bit)))
goto err;
diff --git a/sql/password.c b/sql/password.c
index 7a3d8aafde3..37d06136d80 100644
--- a/sql/password.c
+++ b/sql/password.c
@@ -442,7 +442,7 @@ void make_scrambled_password(char *to, const char *password)
/*
Produce an obscure octet sequence from password and random
- string, recieved from the server. This sequence corresponds to the
+ string, received from the server. This sequence corresponds to the
password, but password can not be easily restored from it. The sequence
is then sent to the server for validation. Trailing zero is not stored
in the buf as it is not needed.
@@ -476,7 +476,7 @@ scramble(char *to, const char *message, const char *password)
/*
Check that scrambled message corresponds to the password; the function
- is used by server to check that recieved reply is authentic.
+ is used by server to check that received reply is authentic.
This function does not check lengths of given strings: message must be
null-terminated, reply and hash_stage2 must be at least SHA1_HASH_SIZE
long (if not, something fishy is going on).
diff --git a/sql/rpl_gtid.cc b/sql/rpl_gtid.cc
index 17c3b15c902..105bdad6f97 100644
--- a/sql/rpl_gtid.cc
+++ b/sql/rpl_gtid.cc
@@ -326,7 +326,9 @@ rpl_slave_state::update(uint32 domain_id, uint32 server_id, uint64 sub_id,
{
if (rgi->gtid_ignore_duplicate_state==rpl_group_info::GTID_DUPLICATE_OWNER)
{
+#ifndef DBUG_OFF
Relay_log_info *rli= rgi->rli;
+#endif
uint32 count= elem->owner_count;
DBUG_ASSERT(count > 0);
DBUG_ASSERT(elem->owner_rli == rli);
diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc
index fcb6a849fb1..05227a29775 100644
--- a/sql/rpl_utility.cc
+++ b/sql/rpl_utility.cc
@@ -1229,7 +1229,7 @@ bool Deferred_log_events::execute(rpl_group_info *rgi)
void Deferred_log_events::rewind()
{
/*
- Reset preceeding Query log event events which execution was
+ Reset preceding Query log event events which execution was
deferred because of slave side filtering.
*/
if (!is_empty())
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index ed7976e2abd..c36bdf3869f 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -5196,8 +5196,8 @@ ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER
ER_VIEW_NO_EXPLAIN
eng "EXPLAIN/SHOW can not be issued; lacking privileges for underlying table"
ger "EXPLAIN/SHOW kann nicht verlangt werden. Rechte für zugrunde liegende Tabelle fehlen"
- rus "EXPLAIN/SHOW не может быть выполненно; недостаточно прав на такблицы запроса"
- ukr "EXPLAIN/SHOW не може бути віконано; немає прав на тиблиці запиту"
+ rus "EXPLAIN/SHOW не может быть выполнено; недостаточно прав на таблицы запроса"
+ ukr "EXPLAIN/SHOW не може бути виконано; немає прав на таблиці запиту"
ER_FRM_UNKNOWN_TYPE
eng "File '%-.192s' has unknown type '%-.64s' in its header"
ger "Datei '%-.192s' hat unbekannten Typ '%-.64s' im Header"
diff --git a/sql/slave.cc b/sql/slave.cc
index 7e6162c88b4..54a32f320c0 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -4436,7 +4436,7 @@ pthread_handler_t handle_slave_sql(void *arg)
/*
binlog_annotate_row_events must be TRUE only after an Annotate_rows event
- has been recieved and only till the last corresponding rbr event has been
+ has been received and only till the last corresponding rbr event has been
applied. In all other cases it must be FALSE.
*/
thd->variables.binlog_annotate_row_events= 0;
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 4ea0692fa0e..b643f0689e2 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -877,7 +877,6 @@ static char *fix_plugin_ptr(char *name)
*/
static bool fix_user_plugin_ptr(ACL_USER *user)
{
- user->salt_len= 0;
if (my_strcasecmp(system_charset_info, user->plugin.str,
native_password_plugin_name.str) == 0)
user->plugin= native_password_plugin_name;
@@ -888,7 +887,8 @@ static bool fix_user_plugin_ptr(ACL_USER *user)
else
return true;
- set_user_salt(user, user->auth_string.str, user->auth_string.length);
+ if (user->auth_string.length)
+ set_user_salt(user, user->auth_string.str, user->auth_string.length);
return false;
}
@@ -1259,7 +1259,11 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
{
user.plugin.str= tmpstr;
user.plugin.length= strlen(user.plugin.str);
- if (user.auth_string.length)
+ user.auth_string.str=
+ safe_str(get_field(&acl_memroot, table->field[next_field++]));
+ user.auth_string.length= strlen(user.auth_string.str);
+
+ if (user.auth_string.length && password_len)
{
sql_print_warning("'user' entry '%s@%s' has both a password "
"and an authentication plugin specified. The "
@@ -1267,9 +1271,6 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
safe_str(user.user.str),
safe_str(user.host.hostname));
}
- user.auth_string.str=
- safe_str(get_field(&acl_memroot, table->field[next_field++]));
- user.auth_string.length= strlen(user.auth_string.str);
fix_user_plugin_ptr(&user);
}
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
index bea331fe8ee..91b3281e231 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -718,7 +718,7 @@ static void update_global_user_stats_with_user(THD *thd,
user_stats->cpu_time+= (thd->status_var.cpu_time -
thd->org_status_var.cpu_time);
/*
- This is handle specially as bytes_recieved is incremented BEFORE
+ This is handle specially as bytes_received is incremented BEFORE
org_status_var is copied.
*/
user_stats->bytes_received+= (thd->org_status_var.bytes_received-
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index c2941d55dcb..a910ed6290f 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -392,17 +392,13 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived)
if (parent_lex->get_free_table_map(&map, &tablenr))
{
/* There is no enough table bits, fall back to materialization. */
- derived->change_refs_to_fields();
- derived->set_materialized_derived();
- goto exit_merge;
+ goto unconditional_materialization;
}
if (dt_select->leaf_tables.elements + tablenr > MAX_TABLES)
{
/* There is no enough table bits, fall back to materialization. */
- derived->change_refs_to_fields();
- derived->set_materialized_derived();
- goto exit_merge;
+ goto unconditional_materialization;
}
if (dt_select->options & OPTION_SCHEMA_TABLE)
@@ -473,6 +469,15 @@ exit_merge:
if (arena)
thd->restore_active_arena(arena, &backup);
DBUG_RETURN(res);
+
+unconditional_materialization:
+ derived->change_refs_to_fields();
+ derived->set_materialized_derived();
+ if (!derived->table || !derived->table->created)
+ res= mysql_derived_create(thd, lex, derived);
+ if (!res)
+ res= mysql_derived_fill(thd, lex, derived);
+ goto exit_merge;
}
diff --git a/sql/sql_error.h b/sql/sql_error.h
index 14338ee041d..a993e9203c9 100644
--- a/sql/sql_error.h
+++ b/sql/sql_error.h
@@ -575,11 +575,16 @@ public:
class ErrConvInteger : public ErrConv
{
- longlong num;
+ longlong m_value;
+ bool m_unsigned;
public:
- ErrConvInteger(longlong num_arg) : ErrConv(), num(num_arg) {}
+ ErrConvInteger(longlong num_arg, bool unsigned_flag= false) :
+ ErrConv(), m_value(num_arg), m_unsigned(unsigned_flag) {}
const char *ptr() const
- { return llstr(num, err_buffer); }
+ {
+ return m_unsigned ? ullstr(m_value, err_buffer) :
+ llstr(m_value, err_buffer);
+ }
};
class ErrConvDouble: public ErrConv
diff --git a/sql/sql_join_cache.cc b/sql/sql_join_cache.cc
index abd23c344c2..cab9628837c 100644
--- a/sql/sql_join_cache.cc
+++ b/sql/sql_join_cache.cc
@@ -929,6 +929,9 @@ int JOIN_CACHE::alloc_buffer()
join->shrink_join_buffers(join_tab, curr_buff_space_sz,
join_buff_space_limit))))
goto fail;
+
+ if (for_explain_only)
+ return 0;
for (ulong buff_size_decr= (buff_size-min_buff_size)/4 + 1; ; )
{
@@ -1023,6 +1026,7 @@ int JOIN_CACHE::realloc_buffer()
SYNOPSIS
init()
+ for_explain join buffer is initialized for explain only
DESCRIPTION
The function initializes the join cache structure. It supposed to be called
@@ -1044,10 +1048,12 @@ int JOIN_CACHE::realloc_buffer()
1 otherwise
*/
-int JOIN_CACHE::init()
+int JOIN_CACHE::init(bool for_explain)
{
DBUG_ENTER("JOIN_CACHE::init");
+ for_explain_only= for_explain;
+
calc_record_fields();
collect_info_on_key_args();
@@ -2632,6 +2638,7 @@ void JOIN_CACHE_BKAH::save_explain_data(struct st_explain_bka_type *explain)
SYNOPSIS
init()
+ for_explain join buffer is initialized for explain only
DESCRIPTION
The function initializes the cache structure with a hash table in it.
@@ -2651,7 +2658,7 @@ void JOIN_CACHE_BKAH::save_explain_data(struct st_explain_bka_type *explain)
1 otherwise
*/
-int JOIN_CACHE_HASHED::init()
+int JOIN_CACHE_HASHED::init(bool for_explain)
{
int rc= 0;
TABLE_REF *ref= &join_tab->ref;
@@ -2663,8 +2670,8 @@ int JOIN_CACHE_HASHED::init()
key_length= ref->key_length;
- if ((rc= JOIN_CACHE::init()))
- DBUG_RETURN (rc);
+ if ((rc= JOIN_CACHE::init(for_explain)) || for_explain)
+ DBUG_RETURN (rc);
if (!(key_buff= (uchar*) sql_alloc(key_length)))
DBUG_RETURN(1);
@@ -3572,6 +3579,7 @@ void JOIN_CACHE_BNL::read_next_candidate_for_match(uchar *rec_ptr)
SYNOPSIS
init
+ for_explain join buffer is initialized for explain only
DESCRIPTION
The function initializes the cache structure. It is supposed to be called
@@ -3586,14 +3594,14 @@ void JOIN_CACHE_BNL::read_next_candidate_for_match(uchar *rec_ptr)
1 otherwise
*/
-int JOIN_CACHE_BNL::init()
+int JOIN_CACHE_BNL::init(bool for_explain)
{
DBUG_ENTER("JOIN_CACHE_BNL::init");
if (!(join_tab_scan= new JOIN_TAB_SCAN(join, join_tab)))
DBUG_RETURN(1);
- DBUG_RETURN(JOIN_CACHE::init());
+ DBUG_RETURN(JOIN_CACHE::init(for_explain));
}
@@ -3758,6 +3766,7 @@ void JOIN_CACHE_BNLH::read_next_candidate_for_match(uchar *rec_ptr)
SYNOPSIS
init
+ for_explain join buffer is initialized for explain only
DESCRIPTION
The function initializes the cache structure. It is supposed to be called
@@ -3772,14 +3781,14 @@ void JOIN_CACHE_BNLH::read_next_candidate_for_match(uchar *rec_ptr)
1 otherwise
*/
-int JOIN_CACHE_BNLH::init()
+int JOIN_CACHE_BNLH::init(bool for_explain)
{
DBUG_ENTER("JOIN_CACHE_BNLH::init");
if (!(join_tab_scan= new JOIN_TAB_SCAN(join, join_tab)))
DBUG_RETURN(1);
- DBUG_RETURN(JOIN_CACHE_HASHED::init());
+ DBUG_RETURN(JOIN_CACHE_HASHED::init(for_explain));
}
@@ -4176,6 +4185,8 @@ Initialize the BKA join cache
SYNOPSIS
init
+ for_explain join buffer is initialized for explain only
+
DESCRIPTION
The function initializes the cache structure. It is supposed to be called
@@ -4190,7 +4201,7 @@ RETURN VALUE
1 otherwise
*/
-int JOIN_CACHE_BKA::init()
+int JOIN_CACHE_BKA::init(bool for_explain)
{
int res;
bool check_only_first_match= join_tab->check_only_first_match();
@@ -4209,7 +4220,7 @@ if (!(join_tab_scan= jsm= new JOIN_TAB_SCAN_MRR(join, join_tab,
mrr_mode, rs_funcs)))
DBUG_RETURN(1);
-if ((res= JOIN_CACHE::init()))
+if ((res= JOIN_CACHE::init(for_explain)))
DBUG_RETURN(res);
if (use_emb_key)
@@ -4570,6 +4581,7 @@ if (no_association &&
SYNOPSIS
init
+ for_explain join buffer is initialized for explain only
DESCRIPTION
The function initializes the cache structure. It is supposed to be called
@@ -4584,7 +4596,7 @@ if (no_association &&
1 otherwise
*/
-int JOIN_CACHE_BKAH::init()
+int JOIN_CACHE_BKAH::init(bool for_explain)
{
bool check_only_first_match= join_tab->check_only_first_match();
@@ -4603,7 +4615,7 @@ int JOIN_CACHE_BKAH::init()
mrr_mode, rs_funcs)))
DBUG_RETURN(1);
- DBUG_RETURN(JOIN_CACHE_HASHED::init());
+ DBUG_RETURN(JOIN_CACHE_HASHED::init(for_explain));
}
diff --git a/sql/sql_join_cache.h b/sql/sql_join_cache.h
index 568cc91ecf7..a3e69f92e34 100644
--- a/sql/sql_join_cache.h
+++ b/sql/sql_join_cache.h
@@ -99,6 +99,9 @@ private:
/* Size of the offset of a field within a record in the cache */
uint size_of_fld_ofs;
+ /* This structure is used only for explain, not for execution */
+ bool for_explain_only;
+
protected:
/* 3 functions below actually do not use the hidden parameter 'this' */
@@ -595,7 +598,7 @@ public:
JOIN_CACHE *next_cache;
/* Shall initialize the join cache structure */
- virtual int init();
+ virtual int init(bool for_explain);
/* Get the current size of the cache join buffer */
size_t get_join_buffer_size() { return buff_size; }
@@ -991,7 +994,7 @@ protected:
public:
/* Initialize a hashed join cache */
- int init();
+ int init(bool for_explain);
/* Reset the buffer of a hashed join cache for reading/writing */
void reset(bool for_writing);
@@ -1127,7 +1130,7 @@ public:
:JOIN_CACHE(j, tab, prev) {}
/* Initialize the BNL cache */
- int init();
+ int init(bool for_explain);
enum Join_algorithm get_join_alg() { return BNL_JOIN_ALG; }
@@ -1194,7 +1197,7 @@ public:
: JOIN_CACHE_HASHED(j, tab, prev) {}
/* Initialize the BNLH cache */
- int init();
+ int init(bool for_explain);
enum Join_algorithm get_join_alg() { return BNLH_JOIN_ALG; }
@@ -1325,7 +1328,7 @@ public:
uchar **get_curr_association_ptr() { return &curr_association; }
/* Initialize the BKA cache */
- int init();
+ int init(bool for_explain);
enum Join_algorithm get_join_alg() { return BKA_JOIN_ALG; }
@@ -1421,7 +1424,7 @@ public:
uchar **get_curr_association_ptr() { return &curr_matching_chain; }
/* Initialize the BKAH cache */
- int init();
+ int init(bool for_explain);
enum Join_algorithm get_join_alg() { return BKAH_JOIN_ALG; }
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index bdf26ec0292..534a8fa5484 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -1,6 +1,6 @@
/*
- Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2010, 2013, Monty Progrm Ab
+ Copyright (c) 2000, 2014, Oracle and/or its affiliates.
+ Copyright (c) 2010, 2014, SkySQL Ab.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -58,13 +58,17 @@ XML_TAG::XML_TAG(int l, String f, String v)
}
+#define GET (stack_pos != stack ? *--stack_pos : my_b_get(&cache))
+#define PUSH(A) *(stack_pos++)=(A)
+
class READ_INFO {
File file;
uchar *buffer, /* Buffer for read text */
*end_of_buff; /* Data in bufferts ends here */
uint buff_length, /* Length of buffert */
max_length; /* Max length of row */
- char *field_term_ptr,*line_term_ptr,*line_start_ptr,*line_start_end;
+ const uchar *field_term_ptr,*line_term_ptr;
+ const char *line_start_ptr,*line_start_end;
uint field_term_length,line_term_length,enclosed_length;
int field_term_char,line_term_char,enclosed_char,escape_char;
int *stack,*stack_pos;
@@ -88,7 +92,7 @@ public:
int read_fixed_length(void);
int next_line(void);
char unescape(char chr);
- int terminator(char *ptr,uint length);
+ int terminator(const uchar *ptr, uint length);
bool find_start_of_fields();
/* load xml */
List<XML_TAG> taglist;
@@ -114,6 +118,15 @@ public:
either the table or THD value
*/
void set_io_cache_arg(void* arg) { cache.arg = arg; }
+
+ /**
+ skip all data till the eof.
+ */
+ void skip_data_till_eof()
+ {
+ while (GET != my_b_EOF)
+ ;
+ }
};
static int read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
@@ -531,8 +544,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
if (error)
{
if (read_file_from_client)
- while (!read_info.next_line())
- ;
+ read_info.skip_data_till_eof();
#ifndef EMBEDDED_LIBRARY
if (mysql_bin_log.is_open())
@@ -1337,10 +1349,18 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs,
found_end_of_line(false), eof(false), need_end_io_cache(false),
error(false), line_cuted(false), found_null(false), read_charset(cs)
{
- field_term_ptr=(char*) field_term.ptr();
+ /*
+ Field and line terminators must be interpreted as sequence of unsigned char.
+ Otherwise, non-ascii terminators will be negative on some platforms,
+ and positive on others (depending on the implementation of char).
+ */
+ field_term_ptr=
+ static_cast<const uchar*>(static_cast<const void*>(field_term.ptr()));
field_term_length= field_term.length();
- line_term_ptr=(char*) line_term.ptr();
+ line_term_ptr=
+ static_cast<const uchar*>(static_cast<const void*>(line_term.ptr()));
line_term_length= line_term.length();
+
level= 0; /* for load xml */
if (line_start.length() == 0)
{
@@ -1349,7 +1369,7 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs,
}
else
{
- line_start_ptr=(char*) line_start.ptr();
+ line_start_ptr= line_start.ptr();
line_start_end=line_start_ptr+line_start.length();
start_of_line= 1;
}
@@ -1358,12 +1378,12 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs,
!memcmp(field_term_ptr,line_term_ptr,field_term_length))
{
line_term_length=0;
- line_term_ptr=(char*) "";
+ line_term_ptr= NULL;
}
enclosed_char= (enclosed_length=enclosed_par.length()) ?
(uchar) enclosed_par[0] : INT_MAX;
- field_term_char= field_term_length ? (uchar) field_term_ptr[0] : INT_MAX;
- line_term_char= line_term_length ? (uchar) line_term_ptr[0] : INT_MAX;
+ field_term_char= field_term_length ? field_term_ptr[0] : INT_MAX;
+ line_term_char= line_term_length ? line_term_ptr[0] : INT_MAX;
/* Set of a stack for unget if long terminators */
uint length= MY_MAX(cs->mbmaxlen, MY_MAX(field_term_length, line_term_length)) + 1;
@@ -1418,11 +1438,7 @@ READ_INFO::~READ_INFO()
}
-#define GET (stack_pos != stack ? *--stack_pos : my_b_get(&cache))
-#define PUSH(A) *(stack_pos++)=(A)
-
-
-inline int READ_INFO::terminator(char *ptr,uint length)
+inline int READ_INFO::terminator(const uchar *ptr,uint length)
{
int chr=0; // Keep gcc happy
uint i;
@@ -1437,7 +1453,7 @@ inline int READ_INFO::terminator(char *ptr,uint length)
return 1;
PUSH(chr);
while (i-- > 1)
- PUSH((uchar) *--ptr);
+ PUSH(*--ptr);
return 0;
}
@@ -1569,7 +1585,7 @@ int READ_INFO::read_field()
if (my_mbcharlen(read_charset, chr) > 1 &&
to + my_mbcharlen(read_charset, chr) <= end_of_buff)
{
- uchar* p= (uchar*) to;
+ uchar* p= to;
int ml, i;
*to++ = chr;
@@ -1594,7 +1610,7 @@ int READ_INFO::read_field()
(const char *)to))
continue;
for (i= 0; i < ml; i++)
- PUSH((uchar) *--to);
+ PUSH(*--to);
chr= GET;
}
#endif
@@ -1743,7 +1759,7 @@ bool READ_INFO::find_start_of_fields()
return 1;
}
} while ((char) chr != line_start_ptr[0]);
- for (char *ptr=line_start_ptr+1 ; ptr != line_start_end ; ptr++)
+ for (const char *ptr=line_start_ptr+1 ; ptr != line_start_end ; ptr++)
{
chr=GET; // Eof will be checked later
if ((char) chr != *ptr)
@@ -1751,7 +1767,7 @@ bool READ_INFO::find_start_of_fields()
PUSH(chr);
while (--ptr != line_start_ptr)
{ // Restart with next char
- PUSH((uchar) *ptr);
+ PUSH( *ptr);
}
goto try_again;
}
@@ -1947,7 +1963,7 @@ int READ_INFO::read_xml()
// row tag should be in ROWS IDENTIFIED BY '<row>' - stored in line_term
if((tag.length() == line_term_length -2) &&
- (strncmp(tag.c_ptr_safe(), line_term_ptr + 1, tag.length()) == 0))
+ (memcmp(tag.ptr(), line_term_ptr + 1, tag.length()) == 0))
{
DBUG_PRINT("read_xml", ("start-of-row: %i %s %s",
level,tag.c_ptr_safe(), line_term_ptr));
@@ -2009,7 +2025,7 @@ int READ_INFO::read_xml()
}
if((tag.length() == line_term_length -2) &&
- (strncmp(tag.c_ptr_safe(), line_term_ptr + 1, tag.length()) == 0))
+ (memcmp(tag.ptr(), line_term_ptr + 1, tag.length()) == 0))
{
DBUG_PRINT("read_xml", ("found end-of-row %i %s",
level, tag.c_ptr_safe()));
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 21463afa1b3..4e19d648cfa 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -4880,6 +4880,10 @@ end_with_restore_list:
goto create_sp_error;
}
+ if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str,
+ NULL, NULL, 0, 0))
+ goto create_sp_error;
+
/*
Check that a database directory with this name
exists. Design note: This won't work on virtual databases
@@ -4891,10 +4895,6 @@ end_with_restore_list:
goto create_sp_error;
}
- if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str,
- NULL, NULL, 0, 0))
- goto create_sp_error;
-
name= lex->sphead->name(&namelen);
#ifdef HAVE_DLOPEN
if (lex->sphead->m_type == TYPE_ENUM_FUNCTION)
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 3456a7b381f..8a6de8b6693 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -74,7 +74,7 @@ When one supplies long data for a placeholder:
- Server gets the long data in pieces with command type
'COM_STMT_SEND_LONG_DATA'.
- - The packet recieved will have the format as:
+ - The packet received will have the format as:
[COM_STMT_SEND_LONG_DATA:1][STMT_ID:4][parameter_number:2][data]
- data from the packet is appended to the long data value buffer for this
placeholder.
diff --git a/sql/sql_priv.h b/sql/sql_priv.h
index 0676fca8fdc..5dc19181e9b 100644
--- a/sql/sql_priv.h
+++ b/sql/sql_priv.h
@@ -253,7 +253,8 @@ template <class T> bool valid_buffer_range(T jump,
OPTIMIZER_SWITCH_SUBQUERY_CACHE | \
OPTIMIZER_SWITCH_SEMIJOIN | \
OPTIMIZER_SWITCH_FIRSTMATCH | \
- OPTIMIZER_SWITCH_LOOSE_SCAN )
+ OPTIMIZER_SWITCH_LOOSE_SCAN | \
+ OPTIMIZER_SWITCH_EXISTS_TO_IN)
/*
Replication uses 8 bytes to store SQL_MODE in the binary log. The day you
use strictly more than 64 bits by adding one more define above, you should
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index b97cedb5b05..2e4227ed8a0 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1248,7 +1248,8 @@ TODO: make view to decide if it is possible to write to WHERE directly or make S
part of the nested outer join, and we can't do partition pruning
(TODO: check if this limitation can be lifted)
*/
- if (!tbl->embedding)
+ if (!tbl->embedding ||
+ (tbl->embedding && tbl->embedding->sj_on_expr))
{
Item *prune_cond= tbl->on_expr? tbl->on_expr : conds;
tbl->table->all_partitions_pruned_away= prune_partitions(thd,
@@ -3074,8 +3075,7 @@ void JOIN::exec_inner()
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
error= do_select(curr_join, curr_fields_list, NULL, procedure);
thd->limit_found_rows= curr_join->send_records;
- if (curr_join->order && curr_join->sortorder &&
- curr_join->select_options & OPTION_FOUND_ROWS)
+ if (curr_join->order && curr_join->filesort_found_rows)
{
/* Use info provided by filesort. */
DBUG_ASSERT(curr_join->table_count > curr_join->const_tables);
@@ -7367,6 +7367,7 @@ double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s,
Go through the "keypart{N}=..." equalities and find those that were
already taken into account in table->cond_selectivity.
*/
+ keyuse= pos->key;
while (keyuse->table == table && keyuse->key == key)
{
if (!(keyuse->used_tables & (rem_tables | table->map)))
@@ -7435,21 +7436,28 @@ double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s,
If the field f from the table is equal to a field from one the
earlier joined tables then the selectivity of the range conditions
over the field f must be discounted.
- */
- for (Field **f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
+
+ We need to discount selectivity only if we're using ref-based
+ access method (and have sel!=1).
+ If we use ALL/range/index_merge, then sel==1, and no need to discount.
+ */
+ if (pos->key != NULL)
{
- if (!bitmap_is_set(read_set, field->field_index) ||
- !field->next_equal_field)
- continue;
- for (Field *next_field= field->next_equal_field;
- next_field != field;
- next_field= next_field->next_equal_field)
+ for (Field **f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
{
- if (!(next_field->table->map & rem_tables) && next_field->table != table)
- {
- if (field->cond_selectivity > 0)
- sel/= field->cond_selectivity;
- break;
+ if (!bitmap_is_set(read_set, field->field_index) ||
+ !field->next_equal_field)
+ continue;
+ for (Field *next_field= field->next_equal_field;
+ next_field != field;
+ next_field= next_field->next_equal_field)
+ {
+ if (!(next_field->table->map & rem_tables) && next_field->table != table)
+ {
+ if (field->cond_selectivity > 0)
+ sel/= field->cond_selectivity;
+ break;
+ }
}
}
}
@@ -10541,7 +10549,7 @@ uint check_join_cache_usage(JOIN_TAB *tab,
if (cache_level == 1)
prev_cache= 0;
if ((tab->cache= new JOIN_CACHE_BNL(join, tab, prev_cache)) &&
- ((options & SELECT_DESCRIBE) || !tab->cache->init()))
+ !tab->cache->init(options & SELECT_DESCRIBE))
{
tab->icp_other_tables_ok= FALSE;
return (2 - MY_TEST(!prev_cache));
@@ -10576,7 +10584,7 @@ uint check_join_cache_usage(JOIN_TAB *tab,
if (cache_level == 3)
prev_cache= 0;
if ((tab->cache= new JOIN_CACHE_BNLH(join, tab, prev_cache)) &&
- ((options & SELECT_DESCRIBE) || !tab->cache->init()))
+ !tab->cache->init(options & SELECT_DESCRIBE))
{
tab->icp_other_tables_ok= FALSE;
return (4 - MY_TEST(!prev_cache));
@@ -10597,7 +10605,7 @@ uint check_join_cache_usage(JOIN_TAB *tab,
if (cache_level == 5)
prev_cache= 0;
if ((tab->cache= new JOIN_CACHE_BKA(join, tab, flags, prev_cache)) &&
- ((options & SELECT_DESCRIBE) || !tab->cache->init()))
+ !tab->cache->init(options & SELECT_DESCRIBE))
return (6 - MY_TEST(!prev_cache));
goto no_join_cache;
}
@@ -10606,7 +10614,7 @@ uint check_join_cache_usage(JOIN_TAB *tab,
if (cache_level == 7)
prev_cache= 0;
if ((tab->cache= new JOIN_CACHE_BKAH(join, tab, flags, prev_cache)) &&
- ((options & SELECT_DESCRIBE) || !tab->cache->init()))
+ !tab->cache->init(options & SELECT_DESCRIBE))
{
tab->idx_cond_fact_out= FALSE;
return (8 - MY_TEST(!prev_cache));
@@ -11018,20 +11026,25 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after)
else if (!table->covering_keys.is_clear_all() &&
!(tab->select && tab->select->quick))
{ // Only read index tree
+ if (tab->loosescan_match_tab)
+ tab->index= tab->loosescan_key;
+ else
+ {
#ifdef BAD_OPTIMIZATION
- /*
- It has turned out that the below change, while speeding things
- up for disk-bound loads, slows them down for cases when the data
- is in disk cache (see BUG#35850):
- See bug #26447: "Using the clustered index for a table scan
- is always faster than using a secondary index".
- */
- if (table->s->primary_key != MAX_KEY &&
- table->file->primary_key_is_clustered())
- tab->index= table->s->primary_key;
- else
+ /*
+ It has turned out that the below change, while speeding things
+ up for disk-bound loads, slows them down for cases when the data
+ is in disk cache (see BUG#35850):
+ See bug #26447: "Using the clustered index for a table scan
+ is always faster than using a secondary index".
+ */
+ if (table->s->primary_key != MAX_KEY &&
+ table->file->primary_key_is_clustered())
+ tab->index= table->s->primary_key;
+ else
#endif
- tab->index=find_shortest_key(table, & table->covering_keys);
+ tab->index=find_shortest_key(table, & table->covering_keys);
+ }
tab->read_first_record= join_read_first;
/* Read with index_first / index_next */
tab->type= tab->type == JT_ALL ? JT_NEXT : JT_HASH_NEXT;
@@ -16191,6 +16204,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
if (!(cur_group->field= field->new_key_field(thd->mem_root,table,
group_buff +
MY_TEST(maybe_null),
+ key_part_info->length,
field->null_ptr,
field->null_bit)))
goto err; /* purecov: inspected */
@@ -18702,7 +18716,7 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
records are read. Because of optimization in some cases it can
provide only select_limit_cnt+1 records.
*/
- if (join->order && join->sortorder &&
+ if (join->order && join->filesort_found_rows &&
join->select_options & OPTION_FOUND_ROWS)
{
DBUG_PRINT("info", ("filesort NESTED_LOOP_QUERY_LIMIT"));
@@ -18724,8 +18738,8 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
/* Join over all rows in table; Return number of found rows */
TABLE *table=jt->table;
- if (table->sort.record_pointers ||
- (table->sort.io_cache && my_b_inited(table->sort.io_cache)))
+ join->select_options ^= OPTION_FOUND_ROWS;
+ if (join->filesort_found_rows)
{
/* Using filesort */
join->send_records= table->sort.found_records;
@@ -20556,7 +20570,11 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
select, filesort_limit, 0,
&examined_rows, &found_rows);
table->sort.found_records= filesort_retval;
- tab->records= found_rows; // For SQL_CALC_ROWS
+ if (found_rows != HA_POS_ERROR)
+ {
+ tab->records= found_rows; // For SQL_CALC_ROWS
+ join->filesort_found_rows= true;
+ }
if (quick_created)
{
@@ -21094,7 +21112,7 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
Item *view_ref= NULL;
/*
If we have found field not by its alias in select list but by its
- original field name, we should additionaly check if we have conflict
+ original field name, we should additionally check if we have conflict
for this name (in case if we would perform lookup in all tables).
*/
if (resolution == RESOLVED_BEHIND_ALIAS && !order_item->fixed &&
@@ -22117,7 +22135,7 @@ change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array,
We are replacing the argument of Item_func_set_user_var after its value
has been read. The argument's null_value should be set by now, so we
must set it explicitly for the replacement argument since the null_value
- may be read without any preceeding call to val_*().
+ may be read without any preceding call to val_*().
*/
new_field->update_null_value();
List<Item> list;
@@ -24905,7 +24923,8 @@ uint get_index_for_order(ORDER *order, TABLE *table, SQL_SELECT *select,
switch (test_if_order_by_key(order, table, select->quick->index,
&used_key_parts)) {
case 1: // desired order
- *need_sort= FALSE;
+ *need_sort= FALSE;
+ *scanned_limit= MY_MIN(limit, select->quick->records);
return select->quick->index;
case 0: // unacceptable order
*need_sort= TRUE;
@@ -24918,7 +24937,7 @@ uint get_index_for_order(ORDER *order, TABLE *table, SQL_SELECT *select,
{
select->set_quick(reverse_quick);
*need_sort= FALSE;
- *scanned_limit= select->quick->records;
+ *scanned_limit= MY_MIN(limit, select->quick->records);
return select->quick->index;
}
else
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 271199e3d51..dc86825e8e9 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -1119,6 +1119,12 @@ public:
restore_no_rows_in_result() in ::reinit()
*/
bool no_rows_in_result_called;
+
+ /**
+ This is set if SQL_CALC_ROWS was calculated by filesort()
+ and should be taken from the appropriate JOIN_TAB
+ */
+ bool filesort_found_rows;
/**
Copy of this JOIN to be used with temporary tables.
@@ -1335,6 +1341,7 @@ public:
emb_sjm_nest= NULL;
sjm_lookup_tables= 0;
+ filesort_found_rows= false;
exec_saved_explain= false;
/*
The following is needed because JOIN::cleanup(true) may be called for
@@ -1541,21 +1548,8 @@ public:
store_key(THD *thd, Field *field_arg, uchar *ptr, uchar *null, uint length)
:null_key(0), null_ptr(null), err(0)
{
- if (field_arg->type() == MYSQL_TYPE_BLOB
- || field_arg->type() == MYSQL_TYPE_GEOMETRY)
- {
- /*
- Key segments are always packed with a 2 byte length prefix.
- See mi_rkey for details.
- */
- to_field= new Field_varstring(ptr, length, 2, null, 1,
- Field::NONE, field_arg->field_name,
- field_arg->table->s, field_arg->charset());
- to_field->init(field_arg->table);
- }
- else
- to_field=field_arg->new_key_field(thd->mem_root, field_arg->table,
- ptr, null, 1);
+ to_field=field_arg->new_key_field(thd->mem_root, field_arg->table,
+ ptr, length, null, 1);
}
store_key(store_key &arg)
:Sql_alloc(), null_key(arg.null_key), to_field(arg.to_field),
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 205697e4466..026b767d5a3 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2009, 2013, Monty Program Ab
+/* Copyright (c) 2000, 2014, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2014, SkySQL Ab.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -125,12 +125,41 @@ append_algorithm(TABLE_LIST *table, String *buff);
static COND * make_cond_for_info_schema(COND *cond, TABLE_LIST *table);
+/**
+ Condition pushdown used for INFORMATION_SCHEMA / SHOW queries.
+ This structure is to implement an optimization when
+ accessing data dictionary data in the INFORMATION_SCHEMA
+ or SHOW commands.
+ When the query contain a TABLE_SCHEMA or TABLE_NAME clause,
+ narrow the search for data based on the constraints given.
+*/
typedef struct st_lookup_field_values
{
- LEX_STRING db_value, table_value;
- bool wild_db_value, wild_table_value;
+ /**
+ Value of a TABLE_SCHEMA clause.
+ Note that this value length may exceed @c NAME_LEN.
+ @sa wild_db_value
+ */
+ LEX_STRING db_value;
+ /**
+ Value of a TABLE_NAME clause.
+ Note that this value length may exceed @c NAME_LEN.
+ @sa wild_table_value
+ */
+ LEX_STRING table_value;
+ /**
+ True when @c db_value is a LIKE clause,
+ false when @c db_value is an '=' clause.
+ */
+ bool wild_db_value;
+ /**
+ True when @c table_value is a LIKE clause,
+ false when @c table_value is an '=' clause.
+ */
+ bool wild_table_value;
} LOOKUP_FIELD_VALUES;
+
bool get_lookup_field_values(THD *, COND *, TABLE_LIST *, LOOKUP_FIELD_VALUES *);
/***************************************************************************
@@ -3901,14 +3930,22 @@ int make_db_list(THD *thd, Dynamic_array<LEX_STRING*> *files,
/*
- If we have db lookup vaule we just add it to list and
+ If we have db lookup value we just add it to list and
exit from the function.
We don't do this for database names longer than the maximum
- path length.
+ name length.
*/
- if (lookup_field_vals->db_value.str &&
- lookup_field_vals->db_value.length < FN_REFLEN)
+ if (lookup_field_vals->db_value.str)
{
+ if (lookup_field_vals->db_value.length > NAME_LEN)
+ {
+ /*
+ Impossible value for a database name,
+ found in a WHERE DATABASE_NAME = 'xxx' clause.
+ */
+ return 0;
+ }
+
if (is_infoschema_db(lookup_field_vals->db_value.str,
lookup_field_vals->db_value.length))
{
@@ -4041,6 +4078,14 @@ make_table_name_list(THD *thd, Dynamic_array<LEX_STRING*> *table_names,
if (!lookup_field_vals->wild_table_value &&
lookup_field_vals->table_value.str)
{
+ if (lookup_field_vals->table_value.length > NAME_LEN)
+ {
+ /*
+ Impossible value for a table name,
+ found in a WHERE TABLE_NAME = 'xxx' clause.
+ */
+ return 0;
+ }
if (db_name == &INFORMATION_SCHEMA_NAME)
{
LEX_STRING *name;
@@ -4485,6 +4530,9 @@ static int fill_schema_table_from_frm(THD *thd, TABLE_LIST *tables,
bzero((char*) &table_list, sizeof(TABLE_LIST));
bzero((char*) &tbl, sizeof(TABLE));
+ DBUG_ASSERT(db_name->length <= NAME_LEN);
+ DBUG_ASSERT(table_name->length <= NAME_LEN);
+
if (lower_case_table_names)
{
/*
@@ -4792,6 +4840,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
for (size_t i=0; i < db_names.elements(); i++)
{
LEX_STRING *db_name= db_names.at(i);
+ DBUG_ASSERT(db_name->length <= NAME_LEN);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (!(check_access(thd, SELECT_ACL, db_name->str,
&thd->col_access, NULL, 0, 1) ||
@@ -4811,6 +4860,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
for (size_t i=0; i < table_names.elements(); i++)
{
LEX_STRING *table_name= table_names.at(i);
+ DBUG_ASSERT(table_name->length <= NAME_LEN);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (!(thd->col_access & TABLE_ACLS))
@@ -4950,6 +5000,7 @@ int fill_schema_schemata(THD *thd, TABLE_LIST *tables, COND *cond)
for (size_t i=0; i < db_names.elements(); i++)
{
LEX_STRING *db_name= db_names.at(i);
+ DBUG_ASSERT(db_name->length <= NAME_LEN);
if (db_name == &INFORMATION_SCHEMA_NAME)
{
if (store_schema_shemata(thd, table, db_name,
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index bcc811e426d..f8348cfb30e 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -231,6 +231,42 @@ bool String::needs_conversion(uint32 arg_length,
/*
+ Checks that the source string can just be copied to the destination string
+ without conversion.
+ Unlike needs_conversion it will require conversion on incoming binary data
+ to ensure the data are verified for vailidity first.
+
+ @param arg_length Length of string to copy.
+ @param from_cs Character set to copy from
+ @param to_cs Character set to copy to
+
+ @return conversion needed
+*/
+bool String::needs_conversion_on_storage(uint32 arg_length,
+ CHARSET_INFO *cs_from,
+ CHARSET_INFO *cs_to)
+{
+ uint32 offset;
+ return (needs_conversion(arg_length, cs_from, cs_to, &offset) ||
+ /* force conversion when storing a binary string */
+ (cs_from == &my_charset_bin &&
+ /* into a non-binary destination */
+ cs_to != &my_charset_bin &&
+ /* and any of the following is true :*/
+ (
+ /* it's a variable length encoding */
+ cs_to->mbminlen != cs_to->mbmaxlen ||
+ /* longer than 2 bytes : neither 1 byte nor ucs2 */
+ cs_to->mbminlen > 2 ||
+ /* and is not a multiple of the char byte size */
+ 0 != (arg_length % cs_to->mbmaxlen)
+ )
+ )
+ );
+}
+
+
+/*
Copy a multi-byte character sets with adding leading zeros.
SYNOPSIS
diff --git a/sql/sql_string.h b/sql/sql_string.h
index bc9e7f11bd6..95c82518f9e 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -343,6 +343,9 @@ public:
static bool needs_conversion(uint32 arg_length,
CHARSET_INFO *cs_from, CHARSET_INFO *cs_to,
uint32 *offset);
+ static bool needs_conversion_on_storage(uint32 arg_length,
+ CHARSET_INFO *cs_from,
+ CHARSET_INFO *cs_to);
bool copy_aligned(const char *s, uint32 arg_length, uint32 offset,
CHARSET_INFO *cs);
bool set_or_copy_aligned(const char *s, uint32 arg_length, CHARSET_INFO *cs);
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index d9702472221..a8e17cf3276 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -5728,21 +5728,35 @@ handle_if_exists_options(THD *thd, TABLE *table, Alter_info *alter_info)
{
if (my_strcasecmp(system_charset_info,
sql_field->field_name, (*f_ptr)->field_name) == 0)
+ goto drop_create_field;
+ }
+ {
+ /*
+ If in the ADD list there is a field with the same name,
+ remove the sql_field from the list.
+ */
+ List_iterator<Create_field> chk_it(alter_info->create_list);
+ Create_field *chk_field;
+ while ((chk_field= chk_it++) && chk_field != sql_field)
{
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
- ER_DUP_FIELDNAME, ER(ER_DUP_FIELDNAME),
- sql_field->field_name);
- it.remove();
- if (alter_info->create_list.is_empty())
- {
- alter_info->flags&= ~Alter_info::ALTER_ADD_COLUMN;
- if (alter_info->key_list.is_empty())
- alter_info->flags&= ~(Alter_info::ALTER_ADD_INDEX |
- Alter_info::ADD_FOREIGN_KEY);
- }
- break;
+ if (my_strcasecmp(system_charset_info,
+ sql_field->field_name, chk_field->field_name) == 0)
+ goto drop_create_field;
}
}
+ continue;
+drop_create_field:
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_DUP_FIELDNAME, ER(ER_DUP_FIELDNAME),
+ sql_field->field_name);
+ it.remove();
+ if (alter_info->create_list.is_empty())
+ {
+ alter_info->flags&= ~Alter_info::ALTER_ADD_COLUMN;
+ if (alter_info->key_list.is_empty())
+ alter_info->flags&= ~(Alter_info::ALTER_ADD_INDEX |
+ Alter_info::ADD_FOREIGN_KEY);
+ }
}
}
@@ -5842,6 +5856,26 @@ handle_if_exists_options(THD *thd, TABLE *table, Alter_info *alter_info)
}
}
}
+
+ if (!remove_drop)
+ {
+ /*
+ Check if the name appears twice in the DROP list.
+ */
+ List_iterator<Alter_drop> chk_it(alter_info->drop_list);
+ Alter_drop *chk_drop;
+ while ((chk_drop= chk_it++) && chk_drop != drop)
+ {
+ if (drop->type == chk_drop->type &&
+ my_strcasecmp(system_charset_info,
+ drop->name, chk_drop->name) == 0)
+ {
+ remove_drop= TRUE;
+ break;
+ }
+ }
+ }
+
if (remove_drop)
{
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
@@ -5862,7 +5896,6 @@ handle_if_exists_options(THD *thd, TABLE *table, Alter_info *alter_info)
Key *key;
List_iterator<Key> key_it(alter_info->key_list);
uint n_key;
- bool remove_key;
const char *keyname;
while ((key=key_it++))
{
@@ -5879,7 +5912,6 @@ handle_if_exists_options(THD *thd, TABLE *table, Alter_info *alter_info)
if (keyname == NULL)
continue;
}
- remove_key= FALSE;
if (key->type != Key::FOREIGN_KEY)
{
for (n_key=0; n_key < table->s->keys; n_key++)
@@ -5887,8 +5919,7 @@ handle_if_exists_options(THD *thd, TABLE *table, Alter_info *alter_info)
if (my_strcasecmp(system_charset_info,
keyname, table->key_info[n_key].name) == 0)
{
- remove_key= TRUE;
- break;
+ goto remove_key;
}
}
}
@@ -5902,25 +5933,44 @@ handle_if_exists_options(THD *thd, TABLE *table, Alter_info *alter_info)
{
if (my_strcasecmp(system_charset_info, f_key->foreign_id->str,
key->name.str) == 0)
- remove_key= TRUE;
- break;
+ goto remove_key;
}
}
- if (remove_key)
+
{
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
- ER_DUP_KEYNAME, ER(ER_DUP_KEYNAME), keyname);
- key_it.remove();
- if (key->type == Key::FOREIGN_KEY)
+ Key *chk_key;
+ List_iterator<Key> chk_it(alter_info->key_list);
+ const char *chkname;
+ while ((chk_key=chk_it++) && chk_key != key)
{
- /* ADD FOREIGN KEY appends two items. */
- key_it.remove();
+ if ((chkname= chk_key->name.str) == NULL)
+ {
+ List_iterator<Key_part_spec> part_it(chk_key->columns);
+ Key_part_spec *kp;
+ if ((kp= part_it++))
+ chkname= kp->field_name.str;
+ if (keyname == NULL)
+ continue;
+ }
+ if (key->type == chk_key->type &&
+ my_strcasecmp(system_charset_info, keyname, chkname) == 0)
+ goto remove_key;
}
- if (alter_info->key_list.is_empty())
- alter_info->flags&= ~(Alter_info::ALTER_ADD_INDEX |
- Alter_info::ADD_FOREIGN_KEY);
- break;
}
+ continue;
+
+remove_key:
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_DUP_KEYNAME, ER(ER_DUP_KEYNAME), keyname);
+ key_it.remove();
+ if (key->type == Key::FOREIGN_KEY)
+ {
+ /* ADD FOREIGN KEY appends two items. */
+ key_it.remove();
+ }
+ if (alter_info->key_list.is_empty())
+ alter_info->flags&= ~(Alter_info::ALTER_ADD_INDEX |
+ Alter_info::ADD_FOREIGN_KEY);
}
}
diff --git a/sql/sql_time.cc b/sql/sql_time.cc
index c8a2c2daf85..cc824298bc5 100644
--- a/sql/sql_time.cc
+++ b/sql/sql_time.cc
@@ -358,20 +358,30 @@ static bool number_to_time_with_warn(bool neg, ulonglong nr, ulong sec_part,
int was_cut;
longlong res;
enum_field_types f_type;
+ bool have_warnings;
if (fuzzydate & TIME_TIME_ONLY)
{
fuzzydate= TIME_TIME_ONLY; // clear other flags
f_type= MYSQL_TYPE_TIME;
res= number_to_time(neg, nr, sec_part, ltime, &was_cut);
+ have_warnings= MYSQL_TIME_WARN_HAVE_WARNINGS(was_cut);
}
else
{
f_type= MYSQL_TYPE_DATETIME;
- res= neg ? -1 : number_to_datetime(nr, sec_part, ltime, fuzzydate, &was_cut);
+ if (neg)
+ {
+ res= -1;
+ }
+ else
+ {
+ res= number_to_datetime(nr, sec_part, ltime, fuzzydate, &was_cut);
+ have_warnings= was_cut && (fuzzydate & TIME_NO_ZERO_IN_DATE);
+ }
}
- if (res < 0 || (was_cut && (fuzzydate & TIME_NO_ZERO_IN_DATE)))
+ if (res < 0 || have_warnings)
{
make_truncated_value_warning(current_thd,
Sql_condition::WARN_LEVEL_WARN, str,
@@ -414,12 +424,11 @@ bool decimal_to_datetime_with_warn(const my_decimal *value, MYSQL_TIME *ltime,
}
-bool int_to_datetime_with_warn(longlong value, MYSQL_TIME *ltime,
+bool int_to_datetime_with_warn(bool neg, ulonglong value, MYSQL_TIME *ltime,
ulonglong fuzzydate, const char *field_name)
{
- const ErrConvInteger str(value);
- bool neg= value < 0;
- return number_to_time_with_warn(neg, neg ? -value : value, 0, ltime,
+ const ErrConvInteger str(neg ? -value : value, !neg);
+ return number_to_time_with_warn(neg, value, 0, ltime,
fuzzydate, &str, field_name);
}
@@ -1250,8 +1259,7 @@ mix_date_and_time(MYSQL_TIME *to, const MYSQL_TIME *from)
/**
Get current date in DATE format
*/
-static void
-set_current_date(THD *thd, MYSQL_TIME *to)
+void set_current_date(THD *thd, MYSQL_TIME *to)
{
thd->variables.time_zone->gmt_sec_to_TIME(to, thd->query_start());
thd->time_zone_used= 1;
diff --git a/sql/sql_time.h b/sql/sql_time.h
index 5a468ef0649..dc8e4668e1e 100644
--- a/sql/sql_time.h
+++ b/sql/sql_time.h
@@ -33,6 +33,7 @@ typedef struct st_known_date_time_format KNOWN_DATE_TIME_FORMAT;
ulong convert_period_to_month(ulong period);
ulong convert_month_to_period(ulong month);
+void set_current_date(THD *thd, MYSQL_TIME *to);
bool time_to_datetime(MYSQL_TIME *ltime);
void time_to_daytime_interval(MYSQL_TIME *l_time);
bool get_date_from_daynr(long daynr,uint *year, uint *month, uint *day);
@@ -46,7 +47,7 @@ bool double_to_datetime_with_warn(double value, MYSQL_TIME *ltime,
bool decimal_to_datetime_with_warn(const my_decimal *value, MYSQL_TIME *ltime,
ulonglong fuzzydate,
const char *name);
-bool int_to_datetime_with_warn(longlong value, MYSQL_TIME *ltime,
+bool int_to_datetime_with_warn(bool neg, ulonglong value, MYSQL_TIME *ltime,
ulonglong fuzzydate,
const char *name);
diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc
index c7981ae36d5..e8286707563 100644
--- a/sql/sql_truncate.cc
+++ b/sql/sql_truncate.cc
@@ -1,4 +1,5 @@
-/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2010, 2014, Oracle and/or its affiliates.
+ Copyright (c) 2013, 2014, SkySQL Ab.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -184,12 +185,19 @@ fk_truncate_illegal_if_parent(THD *thd, TABLE *table)
@param table_ref Table list element for the table to be truncated.
@param is_tmp_table True if element refers to a temp table.
- @retval 0 Success.
- @retval > 0 Error code.
+ @retval TRUNCATE_OK Truncate was successful and statement can be safely
+ binlogged.
+ @retval TRUNCATE_FAILED_BUT_BINLOG Truncate failed but still go ahead with
+ binlogging as in case of non transactional tables
+ partial truncation is possible.
+
+ @retval TRUNCATE_FAILED_SKIP_BINLOG Truncate was not successful hence donot
+ binlong the statement.
*/
-int Sql_cmd_truncate_table::handler_truncate(THD *thd, TABLE_LIST *table_ref,
- bool is_tmp_table)
+enum Sql_cmd_truncate_table::truncate_result
+Sql_cmd_truncate_table::handler_truncate(THD *thd, TABLE_LIST *table_ref,
+ bool is_tmp_table)
{
int error= 0;
uint flags= 0;
@@ -229,16 +237,30 @@ int Sql_cmd_truncate_table::handler_truncate(THD *thd, TABLE_LIST *table_ref,
/* Open the table as it will handle some required preparations. */
if (open_and_lock_tables(thd, table_ref, FALSE, flags))
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUNCATE_FAILED_SKIP_BINLOG);
/* Whether to truncate regardless of foreign keys. */
if (! (thd->variables.option_bits & OPTION_NO_FOREIGN_KEY_CHECKS))
- error= fk_truncate_illegal_if_parent(thd, table_ref->table);
+ if (fk_truncate_illegal_if_parent(thd, table_ref->table))
+ DBUG_RETURN(TRUNCATE_FAILED_SKIP_BINLOG);
- if (!error && (error= table_ref->table->file->ha_truncate()))
+ error= table_ref->table->file->ha_truncate();
+ if (error)
+ {
table_ref->table->file->print_error(error, MYF(0));
-
- DBUG_RETURN(error);
+ /*
+ If truncate method is not implemented then we don't binlog the
+ statement. If truncation has failed in a transactional engine then also we
+ donot binlog the statment. Only in non transactional engine we binlog
+ inspite of errors.
+ */
+ if (error == HA_ERR_WRONG_COMMAND ||
+ table_ref->table->file->has_transactions())
+ DBUG_RETURN(TRUNCATE_FAILED_SKIP_BINLOG);
+ else
+ DBUG_RETURN(TRUNCATE_FAILED_BUT_BINLOG);
+ }
+ DBUG_RETURN(TRUNCATE_OK);
}
@@ -491,10 +513,14 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref)
/*
All effects of a TRUNCATE TABLE operation are committed even if
- truncation fails. Thus, the query must be written to the binary
- log. The only exception is a unimplemented truncate method.
+ truncation fails in the case of non transactional tables. Thus, the
+ query must be written to the binary log. The only exception is a
+ unimplemented truncate method.
*/
- binlog_stmt= !error || error != HA_ERR_WRONG_COMMAND;
+ if (error == TRUNCATE_OK || error == TRUNCATE_FAILED_BUT_BINLOG)
+ binlog_stmt= true;
+ else
+ binlog_stmt= false;
}
/*
diff --git a/sql/sql_truncate.h b/sql/sql_truncate.h
index 061c561b8ea..b8525fd6abb 100644
--- a/sql/sql_truncate.h
+++ b/sql/sql_truncate.h
@@ -1,6 +1,6 @@
#ifndef SQL_TRUNCATE_INCLUDED
#define SQL_TRUNCATE_INCLUDED
-/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -50,11 +50,17 @@ public:
}
protected:
+ enum truncate_result{
+ TRUNCATE_OK=0,
+ TRUNCATE_FAILED_BUT_BINLOG,
+ TRUNCATE_FAILED_SKIP_BINLOG
+ };
+
/** Handle locking a base table for truncate. */
bool lock_table(THD *, TABLE_LIST *, bool *);
/** Truncate table via the handler method. */
- int handler_truncate(THD *, TABLE_LIST *, bool);
+ enum truncate_result handler_truncate(THD *, TABLE_LIST *, bool);
/**
Optimized delete of all rows by doing a full regenerate of the table.
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index f3a1ec18aaf..f437bef15dd 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -1070,6 +1070,13 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
thd->lex->allow_sum_func= 0;
+ /*
+ We do not call DT_MERGE_FOR_INSERT because it has no sense for simple
+ (not multi-) update
+ */
+ if (mysql_handle_derived(thd->lex, DT_PREPARE))
+ DBUG_RETURN(TRUE);
+
if (setup_tables_and_check_access(thd, &select_lex->context,
&select_lex->top_join_list,
table_list,
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 9ea72676b13..d6b3fa41c78 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -14535,7 +14535,7 @@ opt_var_ident_type:
| SESSION_SYM '.' { $$=OPT_SESSION; }
;
-// Option values with preceeding option_type.
+// Option values with preceding option_type.
option_value_following_option_type:
internal_variable_name equal set_expr_or_default
{
@@ -14551,7 +14551,7 @@ option_value_following_option_type:
{
/*
Not in trigger assigning value to new row,
- and option_type preceeding local variable is illegal.
+ and option_type preceding local variable is illegal.
*/
my_parse_error(ER(ER_SYNTAX_ERROR));
MYSQL_YYABORT;
@@ -14559,7 +14559,7 @@ option_value_following_option_type:
}
;
-// Option values without preceeding option_type.
+// Option values without preceding option_type.
option_value_no_option_type:
internal_variable_name equal set_expr_or_default
{
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index d9b43f4d5b6..d5939473cf2 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -77,7 +77,7 @@ static Sys_var_mybool Sys_pfs_enabled(
"performance_schema",
"Enable the performance schema.",
PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_enabled),
- CMD_LINE(OPT_ARG), DEFAULT(TRUE));
+ CMD_LINE(OPT_ARG), DEFAULT(FALSE));
static Sys_var_long Sys_pfs_events_waits_history_long_size(
"performance_schema_events_waits_history_long_size",
@@ -4929,7 +4929,7 @@ static Sys_var_mybool Sys_binlog_annotate_row_events(
#ifdef HAVE_REPLICATION
static Sys_var_mybool Sys_replicate_annotate_row_events(
"replicate_annotate_row_events",
- "Tells the slave to write annotate rows events recieved from the master "
+ "Tells the slave to write annotate rows events received from the master "
"to its own binary log. Ignored if log_slave_updates is not set",
READ_ONLY GLOBAL_VAR(opt_replicate_annotate_row_events),
CMD_LINE(OPT_ARG), DEFAULT(0));
diff --git a/sql/table.cc b/sql/table.cc
index 44320a4d644..6b3e0bcc4b7 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -5054,6 +5054,10 @@ void TABLE_LIST::set_check_merged()
void TABLE_LIST::set_check_materialized()
{
+ DBUG_ENTER("TABLE_LIST::set_check_materialized");
+ SELECT_LEX_UNIT *derived= this->derived;
+ if (view)
+ derived= &view->unit;
DBUG_ASSERT(derived);
if (!derived->first_select()->exclude_from_table_unique_test)
derived->set_unique_exclude();
@@ -5066,6 +5070,7 @@ void TABLE_LIST::set_check_materialized()
derived->first_select()->first_inner_unit()->first_select()->
exclude_from_table_unique_test);
}
+ DBUG_VOID_RETURN;
}
TABLE *TABLE_LIST::get_real_join_table()
diff --git a/sql/table.h b/sql/table.h
index 86e03cdaaf5..3ac75ec06e1 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -2190,7 +2190,7 @@ struct TABLE_LIST
void set_materialized_derived()
{
DBUG_ENTER("set_materialized_derived");
- derived_type= ((derived_type & DTYPE_MASK) |
+ derived_type= ((derived_type & (derived ? DTYPE_MASK : DTYPE_VIEW)) |
DTYPE_TABLE | DTYPE_MATERIALIZE);
set_check_materialized();
DBUG_VOID_RETURN;
diff --git a/sql/tztime.cc b/sql/tztime.cc
index 82f26ca4da4..2a5a5d1681b 100644
--- a/sql/tztime.cc
+++ b/sql/tztime.cc
@@ -2033,7 +2033,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
/*
At last we are doing the same thing for records in
- mysql.time_zone_transition table. Here we additionaly need records
+ mysql.time_zone_transition table. Here we additionally need records
in ascending order by index scan also satisfies us.
*/
table= tz_tables->table;