diff options
author | Sergei Golubchik <sergii@pisem.net> | 2014-06-06 00:07:27 +0200 |
---|---|---|
committer | Sergei Golubchik <sergii@pisem.net> | 2014-06-06 00:07:27 +0200 |
commit | e27c338634739ef56a6888e7948e04c0fa0ba677 (patch) | |
tree | ad63ccae614f3dd77509825d1905fd815ef322cb /sql | |
parent | 2a5905141a3c509a7c34c3d370fb146dbc1c965f (diff) | |
parent | 6d75570e99fbf070cdbeefdfbcfc94d1c7b3ad1f (diff) | |
download | mariadb-git-e27c338634739ef56a6888e7948e04c0fa0ba677.tar.gz |
5.5.38 merge
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.cc | 25 | ||||
-rw-r--r-- | sql/item.cc | 4 | ||||
-rw-r--r-- | sql/item_func.cc | 16 | ||||
-rw-r--r-- | sql/item_strfunc.cc | 6 | ||||
-rw-r--r-- | sql/item_timefunc.cc | 12 | ||||
-rw-r--r-- | sql/opt_range.cc | 11 | ||||
-rw-r--r-- | sql/share/errmsg-utf8.txt | 4 | ||||
-rw-r--r-- | sql/sql_derived.cc | 17 | ||||
-rw-r--r-- | sql/sql_error.h | 11 | ||||
-rw-r--r-- | sql/sql_load.cc | 64 | ||||
-rw-r--r-- | sql/sql_select.cc | 32 | ||||
-rw-r--r-- | sql/sql_show.cc | 67 | ||||
-rw-r--r-- | sql/sql_string.cc | 36 | ||||
-rw-r--r-- | sql/sql_string.h | 3 | ||||
-rw-r--r-- | sql/sql_time.cc | 21 | ||||
-rw-r--r-- | sql/sql_time.h | 2 | ||||
-rw-r--r-- | sql/sql_truncate.cc | 52 | ||||
-rw-r--r-- | sql/sql_truncate.h | 10 | ||||
-rw-r--r-- | sql/sql_update.cc | 7 | ||||
-rw-r--r-- | sql/table.cc | 5 | ||||
-rw-r--r-- | sql/table.h | 2 |
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, <ime, 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), <ime, &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, <ime, &was_cut); return store_TIME_with_warning(<ime, &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, ¬_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, ¬_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; |