summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2014-06-06 00:07:27 +0200
committerSergei Golubchik <sergii@pisem.net>2014-06-06 00:07:27 +0200
commite27c338634739ef56a6888e7948e04c0fa0ba677 (patch)
treead63ccae614f3dd77509825d1905fd815ef322cb /sql
parent2a5905141a3c509a7c34c3d370fb146dbc1c965f (diff)
parent6d75570e99fbf070cdbeefdfbcfc94d1c7b3ad1f (diff)
downloadmariadb-git-e27c338634739ef56a6888e7948e04c0fa0ba677.tar.gz
5.5.38 merge
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc25
-rw-r--r--sql/item.cc4
-rw-r--r--sql/item_func.cc16
-rw-r--r--sql/item_strfunc.cc6
-rw-r--r--sql/item_timefunc.cc12
-rw-r--r--sql/opt_range.cc11
-rw-r--r--sql/share/errmsg-utf8.txt4
-rw-r--r--sql/sql_derived.cc17
-rw-r--r--sql/sql_error.h11
-rw-r--r--sql/sql_load.cc64
-rw-r--r--sql/sql_select.cc32
-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_time.cc21
-rw-r--r--sql/sql_time.h2
-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/table.cc5
-rw-r--r--sql/table.h2
21 files changed, 307 insertions, 100 deletions
diff --git a/sql/field.cc b/sql/field.cc
index 68617d0204e..32ea2a536ef 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -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);
@@ -5335,7 +5335,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,9 +5346,12 @@ 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);
@@ -5705,7 +5708,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);
}
@@ -7312,8 +7316,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*));
@@ -7885,12 +7888,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 +8069,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);
diff --git a/sql/item.cc b/sql/item.cc
index 2c963322eb6..9abf62df545 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;
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 41eb9257149..ccb7ec56021 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;
}
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 2c7fc455d41..ec6ab0f3040 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -5056,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_timefunc.cc b/sql/item_timefunc.cc
index 0aaeb3d55db..bd1dd6d89fb 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -1298,6 +1298,18 @@ 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)
+ {
+ char buff[DECIMAL_MAX_STR_LENGTH];
+ int length= sizeof(buff);
+ decimal2string(val, buff, &length, 0, 0, 0);
+ push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_TRUNCATED_WRONG_VALUE,
+ ER(ER_TRUNCATED_WRONG_VALUE), "DECIMAL",
+ buff);
+ return true;
+ }
+
interval->second= second;
interval->second_part= second_part;
return false;
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/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/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_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_select.cc b/sql/sql_select.cc
index 5db11f3d339..d430e8bc10d 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,
@@ -11017,20 +11018,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;
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 535b113db45..bbe5f780c25 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
@@ -121,12 +121,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 *);
/***************************************************************************
@@ -3864,14 +3893,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))
{
@@ -4004,6 +4041,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;
@@ -4448,6 +4493,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)
{
/*
@@ -4755,6 +4803,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) ||
@@ -4774,6 +4823,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))
@@ -4913,6 +4963,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_time.cc b/sql/sql_time.cc
index c8a2c2daf85..e0b17a918ee 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);
}
diff --git a/sql/sql_time.h b/sql/sql_time.h
index 5a468ef0649..24a87922fa9 100644
--- a/sql/sql_time.h
+++ b/sql/sql_time.h
@@ -46,7 +46,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 1e6485432a2..fe2ea02a8e2 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
@@ -181,12 +182,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;
@@ -226,16 +234,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);
}
@@ -482,10 +504,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 63e45ac1fec..1b808d333d8 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -1066,6 +1066,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/table.cc b/sql/table.cc
index bb336a0b9da..23761e02831 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -5051,6 +5051,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();
@@ -5063,6 +5067,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;