diff options
author | unknown <evgen@sunlight.local> | 2006-07-30 00:33:24 +0400 |
---|---|---|
committer | unknown <evgen@sunlight.local> | 2006-07-30 00:33:24 +0400 |
commit | ddb91478e80a02f17c24b6b061123916d1f70e19 (patch) | |
tree | 7459ead6708231c323be75b3f99c455341370348 /sql | |
parent | fc466665b74a8b50af586c2c56777409b9214826 (diff) | |
parent | 08be4e96a953a883240e9eebb38a9e8b965d3b1d (diff) | |
download | mariadb-git-ddb91478e80a02f17c24b6b061123916d1f70e19.tar.gz |
Merge sunlight.local:/local_work/tmp_merge-5.0-opt-mysql
into sunlight.local:/local_work/tmp_merge-5.1-opt-mysql
client/mysql.cc:
Auto merged
mysql-test/r/date_formats.result:
Auto merged
mysql-test/r/func_gconcat.result:
Auto merged
mysql-test/r/func_group.result:
Auto merged
mysql-test/r/func_str.result:
Auto merged
mysql-test/r/group_min_max.result:
Auto merged
BitKeeper/deleted/.del-make_win_src_distribution.sh~f80d8fca44e4e5f1:
Auto merged
BitKeeper/deleted/.del-mysqld.dsp~ffdbf2d234e23e56:
Auto merged
BitKeeper/deleted/.del-mysqld_ia64.dsp~7f8cf84d81ee04e2:
Auto merged
BitKeeper/deleted/.del-mysqldump.dsp~a8bd23547d3fc27e:
Auto merged
BitKeeper/deleted/.del-mysqldump_ia64.dsp~a2aabe898be35b31:
Auto merged
mysql-test/r/innodb.result:
Auto merged
mysql-test/r/innodb_mysql.result:
Auto merged
mysql-test/r/ps_7ndb.result:
Auto merged
mysql-test/r/type_ranges.result:
Auto merged
mysql-test/r/udf.result:
Auto merged
mysql-test/r/union.result:
Auto merged
mysql-test/r/view.result:
Auto merged
mysql-test/t/date_formats.test:
Auto merged
mysql-test/t/func_gconcat.test:
Auto merged
mysql-test/t/func_group.test:
Auto merged
mysql-test/t/group_min_max.test:
Auto merged
mysql-test/t/innodb.test:
Auto merged
mysql-test/t/innodb_mysql.test:
Auto merged
mysql-test/t/mysql.test:
Auto merged
mysql-test/t/select.test:
Auto merged
mysql-test/t/sp.test:
Auto merged
mysql-test/t/view.test:
Auto merged
sql/field.cc:
Auto merged
sql/item_cmpfunc.cc:
Auto merged
sql/item_cmpfunc.h:
Auto merged
sql/item_func.cc:
Auto merged
sql/item_func.h:
Auto merged
sql/item_strfunc.cc:
Auto merged
sql/item_subselect.cc:
Auto merged
sql/item_subselect.h:
Auto merged
sql/opt_range.h:
Auto merged
sql/sql_base.cc:
Auto merged
sql/sql_class.cc:
Auto merged
sql/sql_insert.cc:
Auto merged
sql/sql_parse.cc:
Auto merged
sql/sql_show.cc:
Auto merged
sql/sql_yacc.yy:
Auto merged
sql/time.cc:
Auto merged
storage/ndb/test/ndbapi/Makefile.am:
Auto merged
strings/decimal.c:
Auto merged
mysql-test/r/analyse.result:
Manual merge
mysql-test/r/bigint.result:
Manual merge
mysql-test/r/create.result:
Manual merge
mysql-test/r/information_schema.result:
Manual merge
mysql-test/r/ps_2myisam.result:
Manual merge
mysql-test/r/ps_3innodb.result:
Manual merge
mysql-test/r/ps_4heap.result:
Manual merge
mysql-test/r/ps_5merge.result:
Manual merge
mysql-test/r/ps_6bdb.result:
Manual merge
mysql-test/r/rpl_insert_id.result:
Manual merge
mysql-test/r/select.result:
Manual merge
mysql-test/r/sp.result:
Manual merge
mysql-test/r/subselect.result:
Manual merge
mysql-test/t/information_schema.test:
Manual merge
mysql-test/t/rpl_insert_id.test:
Manual merge
sql/field.h:
Manual merge
sql/item.cc:
Manual merge
sql/item.h:
Manual merge
sql/item_strfunc.h:
Manual merge
sql/item_sum.cc:
Manual merge
sql/mysql_priv.h:
Manual merge
sql/share/errmsg.txt:
Manual merge
sql/sql_class.h:
Manual merge
sql/sql_select.cc:
Manual merge
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.cc | 18 | ||||
-rw-r--r-- | sql/field.h | 18 | ||||
-rw-r--r-- | sql/item.cc | 19 | ||||
-rw-r--r-- | sql/item.h | 12 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 22 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 2 | ||||
-rw-r--r-- | sql/item_func.cc | 6 | ||||
-rw-r--r-- | sql/item_func.h | 7 | ||||
-rw-r--r-- | sql/item_strfunc.cc | 56 | ||||
-rw-r--r-- | sql/item_strfunc.h | 7 | ||||
-rw-r--r-- | sql/item_subselect.cc | 9 | ||||
-rw-r--r-- | sql/item_subselect.h | 9 | ||||
-rw-r--r-- | sql/item_sum.cc | 4 | ||||
-rw-r--r-- | sql/mysql_priv.h | 6 | ||||
-rw-r--r-- | sql/opt_range.h | 2 | ||||
-rw-r--r-- | sql/share/errmsg.txt | 2 | ||||
-rw-r--r-- | sql/sql_base.cc | 47 | ||||
-rw-r--r-- | sql/sql_class.cc | 1 | ||||
-rw-r--r-- | sql/sql_class.h | 2 | ||||
-rw-r--r-- | sql/sql_insert.cc | 15 | ||||
-rw-r--r-- | sql/sql_parse.cc | 2 | ||||
-rw-r--r-- | sql/sql_select.cc | 123 | ||||
-rw-r--r-- | sql/sql_show.cc | 1 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 4 |
24 files changed, 320 insertions, 74 deletions
diff --git a/sql/field.cc b/sql/field.cc index d4bd38724ae..fc08ce7eb60 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -4585,6 +4585,24 @@ Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg, } +Field_timestamp::Field_timestamp(bool maybe_null_arg, + const char *field_name_arg, + struct st_table *table_arg, CHARSET_INFO *cs) + :Field_str((char*) 0, 19, maybe_null_arg ? (uchar*) "": 0, 0, + NONE, field_name_arg, table_arg, cs) +{ + /* For 4.0 MYD and 4.0 InnoDB compatibility */ + flags|= ZEROFILL_FLAG | UNSIGNED_FLAG; + if (table && !table->timestamp_field && + unireg_check != NONE) + { + /* This timestamp has auto-update */ + table->timestamp_field= this; + flags|=TIMESTAMP_FLAG; + } +} + + /* Get auto-set type for TIMESTAMP field. diff --git a/sql/field.h b/sql/field.h index 3a4118df01e..b38c81971e3 100644 --- a/sql/field.h +++ b/sql/field.h @@ -793,7 +793,10 @@ public: Field_timestamp(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg, + struct st_table *table_arg, TABLE_SHARE *share, CHARSET_INFO *cs); + Field_timestamp(bool maybe_null_arg, const char *field_name_arg, + struct st_table *table_arg, CHARSET_INFO *cs); enum_field_types type() const { return FIELD_TYPE_TIMESTAMP;} enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; } enum Item_result cmp_type () const { return INT_RESULT; } @@ -1144,6 +1147,21 @@ public: { flags|= BLOB_FLAG; } + Field_blob(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, + struct st_table *table_arg, CHARSET_INFO *cs, bool set_packlength) + :Field_longstr((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0, + NONE, field_name_arg, table_arg, cs) + { + flags|= BLOB_FLAG; + packlength= 4; + if (set_packlength) + { + uint32 char_length= len_arg/cs->mbmaxlen; + packlength= char_length <= 255 ? 1 : + char_length <= 65535 ? 2 : + char_length <= 16777215 ? 3 : 4; + } + } enum_field_types type() const { return FIELD_TYPE_BLOB;} enum ha_base_keytype key_type() const { return binary() ? HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2; } diff --git a/sql/item.cc b/sql/item.cc index 7d4eca07232..e38142fdb0d 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -587,6 +587,7 @@ void Item::set_name(const char *str, uint length, CHARSET_INFO *cs) } if (cs->ctype) { + uint orig_len= length; /* This will probably need a better implementation in the future: a function in CHARSET_INFO structure. @@ -596,6 +597,11 @@ void Item::set_name(const char *str, uint length, CHARSET_INFO *cs) length--; str++; } + if (orig_len != length && !is_autogenerated_name) + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_REMOVED_SPACES, ER(ER_REMOVED_SPACES), + str + length - orig_len); + } if (!my_charset_same(cs, system_charset_info)) { @@ -3949,7 +3955,9 @@ Field *Item::make_string_field(TABLE *table) if (max_length/collation.collation->mbmaxlen > CONVERT_IF_BIGGER_TO_BLOB) field= new Field_blob(max_length, maybe_null, name, collation.collation); - else if (max_length > 0) + /* Item_type_holder holds the exact type, do not change it */ + else if (max_length > 0 && + (type() != Item::TYPE_HOLDER || field_type() != MYSQL_TYPE_STRING)) field= new Field_varstring(max_length, maybe_null, name, table->s, collation.collation); else @@ -4029,6 +4037,7 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table, bool fixed_length) field= new Field_time(maybe_null, name, &my_charset_bin); break; case MYSQL_TYPE_TIMESTAMP: + return new Field_timestamp(maybe_null, name, table, &my_charset_bin); case MYSQL_TYPE_DATETIME: field= new Field_datetime(maybe_null, name, &my_charset_bin); break; @@ -4062,7 +4071,11 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table, bool fixed_length) case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_BLOB: case MYSQL_TYPE_GEOMETRY: - field= new Field_blob(max_length, maybe_null, name, collation.collation); + if (this->type() == Item::TYPE_HOLDER) + field= new Field_blob(max_length, maybe_null, name, table, + collation.collation, 1); + else + field= new Field_blob(max_length, maybe_null, name, table, collation.collation); break; // Blob handled outside of case } if (field) @@ -6232,7 +6245,7 @@ uint32 Item_type_holder::display_length(Item *item) case MYSQL_TYPE_DOUBLE: return 53; case MYSQL_TYPE_NULL: - return 4; + return 0; case MYSQL_TYPE_LONGLONG: return 20; case MYSQL_TYPE_INT24: diff --git a/sql/item.h b/sql/item.h index be25d51bea1..0e62d2aa9f0 100644 --- a/sql/item.h +++ b/sql/item.h @@ -737,9 +737,16 @@ public: Any new item which can be NULL must implement this call. */ virtual bool is_null() { return 0; } + /* - it is "top level" item of WHERE clause and we do not need correct NULL - handling + Inform the item that there will be no distinction between its result + being FALSE or NULL. + + NOTE + This function will be called for eg. Items that are top-level AND-parts + of the WHERE clause. Items implementing this function (currently + Item_cond_and and subquery-related item) enable special optimizations + when they are "top level". */ virtual void top_level_item() {} /* @@ -784,6 +791,7 @@ public: virtual bool collect_item_field_processor(byte * arg) { return 0; } virtual bool find_item_in_field_list_processor(byte *arg) { return 0; } virtual bool change_context_processor(byte *context) { return 0; } + virtual bool is_expensive_processor(byte *arg) { return 0; } virtual bool register_field_in_read_map(byte *arg) { return 0; } /* Check if a partition function is allowed diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 9a3f43c7f05..d3272fae4ed 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -3671,6 +3671,28 @@ Item *Item_cond_or::neg_transformer(THD *thd) /* NOT(a OR b OR ...) -> */ } +Item *Item_func_nop_all::neg_transformer(THD *thd) +{ + /* "NOT (e $cmp$ ANY (SELECT ...)) -> e $rev_cmp$" ALL (SELECT ...) */ + Item_func_not_all *new_item= new Item_func_not_all(args[0]); + Item_allany_subselect *allany= (Item_allany_subselect*)args[0]; + allany->func= allany->func_creator(FALSE); + allany->all= !allany->all; + allany->upper_item= new_item; + return new_item; +} + +Item *Item_func_not_all::neg_transformer(THD *thd) +{ + /* "NOT (e $cmp$ ALL (SELECT ...)) -> e $rev_cmp$" ANY (SELECT ...) */ + Item_func_nop_all *new_item= new Item_func_nop_all(args[0]); + Item_allany_subselect *allany= (Item_allany_subselect*)args[0]; + allany->all= !allany->all; + allany->func= allany->func_creator(TRUE); + allany->upper_item= new_item; + return new_item; +} + Item *Item_func_eq::negated_item() /* a = b -> a != b */ { return new Item_func_ne(args[0], args[1]); diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 82cb5febe7d..04462e05e9f 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -313,6 +313,7 @@ public: void set_sum_test(Item_sum_hybrid *item) { test_sum_item= item; }; void set_sub_test(Item_maxmin_subselect *item) { test_sub_item= item; }; bool empty_underlying_subquery(); + Item *neg_transformer(THD *thd); }; @@ -323,6 +324,7 @@ public: Item_func_nop_all(Item *a) :Item_func_not_all(a) {} longlong val_int(); const char *func_name() const { return "<nop>"; } + Item *neg_transformer(THD *thd); }; diff --git a/sql/item_func.cc b/sql/item_func.cc index 12e3491cf23..e901eaf8654 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -402,6 +402,12 @@ Field *Item_func::tmp_table_field(TABLE *table) } +bool Item_func::is_expensive_processor(byte *arg) +{ + return is_expensive(); +} + + my_decimal *Item_func::val_decimal(my_decimal *decimal_value) { DBUG_ASSERT(fixed); diff --git a/sql/item_func.h b/sql/item_func.h index ae7bff8a737..3a1952c8d0f 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -55,7 +55,7 @@ public: NOT_FUNC, NOT_ALL_FUNC, NOW_FUNC, TRIG_COND_FUNC, GUSERVAR_FUNC, COLLATE_FUNC, - EXTRACT_FUNC, CHAR_TYPECAST_FUNC, FUNC_SP }; + EXTRACT_FUNC, CHAR_TYPECAST_FUNC, FUNC_SP, UDF_FUNC }; enum optimize_type { OPTIMIZE_NONE,OPTIMIZE_KEY,OPTIMIZE_OP, OPTIMIZE_NULL, OPTIMIZE_EQUAL }; enum Type type() const { return FUNC_ITEM; } @@ -189,6 +189,8 @@ public: Item *transform(Item_transformer transformer, byte *arg); void traverse_cond(Cond_traverser traverser, void * arg, traverse_order order); + bool is_expensive_processor(byte *arg); + virtual bool is_expensive() { return 0; } }; @@ -962,6 +964,7 @@ public: Item_udf_func(udf_func *udf_arg, List<Item> &list) :Item_func(list), udf(udf_arg) {} const char *func_name() const { return udf.name(); } + enum Functype functype() const { return UDF_FUNC; } bool fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); @@ -974,6 +977,7 @@ public: void cleanup(); Item_result result_type () const { return udf.result_type(); } table_map not_null_tables() const { return 0; } + bool is_expensive() { return 1; } }; @@ -1503,6 +1507,7 @@ public: virtual enum Functype functype() const { return FUNC_SP; } bool fix_fields(THD *thd, Item **ref); + bool is_expensive() { return 1; } }; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 76cff159b5c..dee7f408733 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -752,44 +752,47 @@ String *Item_func_reverse::val_str(String *str) { DBUG_ASSERT(fixed == 1); String *res = args[0]->val_str(str); - char *ptr,*end; + char *ptr, *end, *tmp; if ((null_value=args[0]->null_value)) return 0; /* An empty string is a special case as the string pointer may be null */ if (!res->length()) return &my_empty_string; - res=copy_if_not_alloced(str,res,res->length()); - ptr = (char *) res->ptr(); - end=ptr+res->length(); + if (tmp_value.alloced_length() < res->length() && + tmp_value.realloc(res->length())) + { + null_value= 1; + return 0; + } + tmp_value.length(res->length()); + tmp_value.set_charset(res->charset()); + ptr= (char *) res->ptr(); + end= ptr + res->length(); + tmp= (char *) tmp_value.ptr() + tmp_value.length(); #ifdef USE_MB if (use_mb(res->charset())) { - String tmpstr; - tmpstr.copy(*res); - char *tmp = (char *) tmpstr.ptr() + tmpstr.length(); register uint32 l; while (ptr < end) { - if ((l=my_ismbchar(res->charset(), ptr,end))) - tmp-=l, memcpy(tmp,ptr,l), ptr+=l; + if ((l= my_ismbchar(res->charset(),ptr,end))) + { + tmp-= l; + memcpy(tmp,ptr,l); + ptr+= l; + } else - *--tmp=*ptr++; + *--tmp= *ptr++; } - memcpy((char *) res->ptr(),(char *) tmpstr.ptr(), res->length()); } else #endif /* USE_MB */ { - char tmp; while (ptr < end) - { - tmp=*ptr; - *ptr++=*--end; - *end=tmp; - } + *--tmp= *ptr++; } - return res; + return &tmp_value; } @@ -1500,6 +1503,23 @@ void Item_func_trim::fix_length_and_dec() } } +void Item_func_trim::print(String *str) +{ + if (arg_count == 1) + { + Item_func::print(str); + return; + } + str->append(Item_func_trim::func_name()); + str->append('('); + str->append(mode_name()); + str->append(' '); + args[1]->print(str); + str->append(STRING_WITH_LEN(" from ")); + args[0]->print(str); + str->append(')'); +} + /* Item_func_password */ diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index c021aacf114..e085c0b4d7b 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -105,6 +105,7 @@ public: class Item_func_reverse :public Item_str_func { + String tmp_value; public: Item_func_reverse(Item *a) :Item_str_func(a) {} String *val_str(String *); @@ -239,6 +240,8 @@ public: String *val_str(String *); void fix_length_and_dec(); const char *func_name() const { return "trim"; } + void print(String *str); + virtual const char *mode_name() const { return "both"; } bool check_partition_func_processor(byte *bool_arg) { return 0;} }; @@ -250,6 +253,7 @@ public: Item_func_ltrim(Item *a) :Item_func_trim(a) {} String *val_str(String *); const char *func_name() const { return "ltrim"; } + const char *mode_name() const { return "leading"; } }; @@ -260,6 +264,7 @@ public: Item_func_rtrim(Item *a) :Item_func_trim(a) {} String *val_str(String *); const char *func_name() const { return "rtrim"; } + const char *mode_name() const { return "trailing"; } }; @@ -741,7 +746,7 @@ public: void fix_length_and_dec(); bool eq(const Item *item, bool binary_cmp) const; const char *func_name() const { return "collate"; } - enum Functype func_type() const { return COLLATE_FUNC; } + enum Functype functype() const { return COLLATE_FUNC; } void print(String *str); Item_field *filed_for_view_update() { diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index a08ac5d5f6a..7dfe65d793a 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -615,14 +615,14 @@ Item_in_subselect::Item_in_subselect(Item * left_exp, } Item_allany_subselect::Item_allany_subselect(Item * left_exp, - Comp_creator *fn, + chooser_compare_func_creator fc, st_select_lex *select_lex, bool all_arg) - :Item_in_subselect(), all(all_arg) + :Item_in_subselect(), func_creator(fc), all(all_arg) { DBUG_ENTER("Item_in_subselect::Item_in_subselect"); left_expr= left_exp; - func= fn; + func= func_creator(all_arg); init(select_lex, new select_exists_subselect(this)); max_columns= 1; abort_on_null= 0; @@ -845,7 +845,8 @@ Item_in_subselect::single_value_transformer(JOIN *join, if (!select_lex->group_list.elements && !select_lex->having && !select_lex->with_sum_func && - !(select_lex->next_select())) + !(select_lex->next_select()) && + select_lex->table_list.elements) { Item_sum_hybrid *item; nesting_map save_allow_sum_func; diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 85bd7a1139d..a72c6e85739 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -270,14 +270,13 @@ public: /* ALL/ANY/SOME subselect */ class Item_allany_subselect :public Item_in_subselect { -protected: - Comp_creator *func; - public: + chooser_compare_func_creator func_creator; + Comp_creator *func; bool all; - Item_allany_subselect(Item * left_expr, Comp_creator *f, - st_select_lex *select_lex, bool all); + Item_allany_subselect(Item * left_expr, chooser_compare_func_creator fc, + st_select_lex *select_lex, bool all); // only ALL subquery has upper not subs_type substype() { return all?ALL_SUBS:ANY_SUBS; } diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 51c8ba6e5da..024b0ecfb42 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -381,7 +381,9 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table, field= new Field_longlong(max_length, maybe_null, name, unsigned_flag); break; case STRING_RESULT: - if (max_length/collation.collation->mbmaxlen <= 255 || !convert_blob_length) + if (max_length/collation.collation->mbmaxlen <= 255 || + max_length/collation.collation->mbmaxlen >=UINT_MAX16 || + !convert_blob_length) return make_string_field(table); field= new Field_varstring(convert_blob_length, maybe_null, name, table->s, collation.collation); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index c270759f6b9..0b3a76a71cf 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -538,11 +538,13 @@ enum enum_var_type OPT_DEFAULT= 0, OPT_SESSION, OPT_GLOBAL }; class sys_var; -#include "item.h" -extern my_decimal decimal_zero; #ifdef MYSQL_SERVER +class Comp_creator; typedef Comp_creator* (*chooser_compare_func_creator)(bool invert); #endif +#include "item.h" +extern my_decimal decimal_zero; + /* sql_parse.cc */ void free_items(Item *item); void cleanup_items(Item *item); diff --git a/sql/opt_range.h b/sql/opt_range.h index 85cedf663cd..6f26f9f782c 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -670,7 +670,7 @@ private: #ifdef NOT_USED bool test_if_null_range(QUICK_RANGE *range, uint used_key_parts); #endif - int reset(void) { next=0; rev_it.rewind(); return 0; } + int reset(void) { rev_it.rewind(); return QUICK_RANGE_SELECT::reset(); } List<QUICK_RANGE> rev_ranges; List_iterator<QUICK_RANGE> rev_it; }; diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 75aba522543..a5fefc38c59 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5802,6 +5802,8 @@ ER_FOREIGN_DUPLICATE_KEY 23000 S1009 eng "Upholding foreign key constraints for table '%.64s', entry '%-.64s', key %d would lead to a duplicate entry" ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE eng "Column count of mysql.%s is wrong. Expected %d, found %d. Created with MySQL %d, now running %d. Please use scripts/mysql_fix_privilege_tables" +ER_REMOVED_SPACES + eng "Leading spaces are removed from name '%s'" ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR eng "Cannot switch out of the row-based binary log format when the session has open temporary tables" ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT diff --git a/sql/sql_base.cc b/sql/sql_base.cc index db11a3442c2..e40b9721911 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -4974,36 +4974,48 @@ store_top_level_join_columns(THD *thd, TABLE_LIST *table_ref, if (table_ref->nested_join) { List_iterator_fast<TABLE_LIST> nested_it(table_ref->nested_join->join_list); - TABLE_LIST *cur_left_neighbor= nested_it++; - TABLE_LIST *cur_right_neighbor= NULL; + TABLE_LIST *same_level_left_neighbor= nested_it++; + TABLE_LIST *same_level_right_neighbor= NULL; + /* Left/right-most neighbors, possibly at higher levels in the join tree. */ + TABLE_LIST *real_left_neighbor, *real_right_neighbor; - while (cur_left_neighbor) + while (same_level_left_neighbor) { - TABLE_LIST *cur_table_ref= cur_left_neighbor; - cur_left_neighbor= nested_it++; + TABLE_LIST *cur_table_ref= same_level_left_neighbor; + same_level_left_neighbor= nested_it++; /* The order of RIGHT JOIN operands is reversed in 'join list' to transform it into a LEFT JOIN. However, in this procedure we need the join operands in their lexical order, so below we reverse the - join operands. Notice that this happens only in the first loop, and - not in the second one, as in the second loop cur_left_neighbor == NULL. - This is the correct behavior, because the second loop - sets cur_table_ref reference correctly after the join operands are + join operands. Notice that this happens only in the first loop, + and not in the second one, as in the second loop + same_level_left_neighbor == NULL. + This is the correct behavior, because the second loop sets + cur_table_ref reference correctly after the join operands are swapped in the first loop. */ - if (cur_left_neighbor && + if (same_level_left_neighbor && cur_table_ref->outer_join & JOIN_TYPE_RIGHT) { /* This can happen only for JOIN ... ON. */ DBUG_ASSERT(table_ref->nested_join->join_list.elements == 2); - swap_variables(TABLE_LIST*, cur_left_neighbor, cur_table_ref); + swap_variables(TABLE_LIST*, same_level_left_neighbor, cur_table_ref); } + /* + Pick the parent's left and right neighbors if there are no immediate + neighbors at the same level. + */ + real_left_neighbor= (same_level_left_neighbor) ? + same_level_left_neighbor : left_neighbor; + real_right_neighbor= (same_level_right_neighbor) ? + same_level_right_neighbor : right_neighbor; + if (cur_table_ref->nested_join && store_top_level_join_columns(thd, cur_table_ref, - cur_left_neighbor, cur_right_neighbor)) + real_left_neighbor, real_right_neighbor)) goto err; - cur_right_neighbor= cur_table_ref; + same_level_right_neighbor= cur_table_ref; } } @@ -5876,12 +5888,17 @@ fill_record(THD * thd, List<Item> &fields, List<Item> &values, bool ignore_errors) { List_iterator_fast<Item> f(fields),v(values); - Item *value; + Item *value, *fld; Item_field *field; DBUG_ENTER("fill_record"); - while ((field=(Item_field*) f++)) + while ((fld= f++)) { + if (!(field= fld->filed_for_view_update())) + { + my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), fld->name); + DBUG_RETURN(TRUE); + } value=v++; Field *rfield= field->field; TABLE *table= rfield->table; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index c1a3b76ce55..e0ad74887f8 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -310,6 +310,7 @@ THD::THD() tablespace_op=FALSE; ulong tmp=sql_rnd_with_mutex(); randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::query_id); + substitute_null_with_insert_id = FALSE; thr_lock_info_init(&lock_info); /* safety: will be reset after start */ thr_lock_owner_init(&main_lock_id, &lock_info); } diff --git a/sql/sql_class.h b/sql/sql_class.h index 35de14835a4..01b28eaee96 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1276,6 +1276,8 @@ public: bool last_cuted_field; bool no_errors, password, is_fatal_error; bool query_start_used, rand_used, time_zone_used; + /* for IS NULL => = last_insert_id() fix in remove_eq_conds() */ + bool substitute_null_with_insert_id; bool in_lock_tables; bool query_error, bootstrap, cleanup_done; bool tmp_table_used; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 25ed03c4051..966fe45e690 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -730,6 +730,7 @@ static bool check_view_insertability(THD * thd, TABLE_LIST *view) uint used_fields_buff_size= bitmap_buffer_size(table->s->fields); uint32 *used_fields_buff= (uint32*)thd->alloc(used_fields_buff_size); MY_BITMAP used_fields; + bool save_set_query_id= thd->set_query_id; DBUG_ENTER("check_key_in_view"); if (!used_fields_buff) @@ -741,15 +742,26 @@ static bool check_view_insertability(THD * thd, TABLE_LIST *view) bitmap_clear_all(&used_fields); view->contain_auto_increment= 0; + /* + we must not set query_id for fields as they're not + really used in this context + */ + thd->set_query_id= 0; /* check simplicity and prepare unique test of view */ for (trans= trans_start; trans != trans_end; trans++) { if (!trans->item->fixed && trans->item->fix_fields(thd, &trans->item)) - return TRUE; + { + thd->set_query_id= save_set_query_id; + DBUG_RETURN(TRUE); + } Item_field *field; /* simple SELECT list entry (field without expression) */ if (!(field= trans->item->filed_for_view_update())) + { + thd->set_query_id= save_set_query_id; DBUG_RETURN(TRUE); + } if (field->field->unireg_check == Field::NEXT_NUMBER) view->contain_auto_increment= 1; /* prepare unique test */ @@ -759,6 +771,7 @@ static bool check_view_insertability(THD * thd, TABLE_LIST *view) */ trans->item= field; } + thd->set_query_id= save_set_query_id; /* unique test */ for (trans= trans_start; trans != trans_end; trans++) { diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 897d9155b0a..30dea60f7a2 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7305,7 +7305,7 @@ Item * all_any_subquery_creator(Item *left_expr, return new Item_func_not(new Item_in_subselect(left_expr, select_lex)); Item_allany_subselect *it= - new Item_allany_subselect(left_expr, (*cmp)(all), select_lex, all); + new Item_allany_subselect(left_expr, cmp, select_lex, all); if (all) return it->upper_item= new Item_func_not_all(it); /* ALL */ diff --git a/sql/sql_select.cc b/sql/sql_select.cc index f224f333a98..52f09b13311 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -689,6 +689,24 @@ JOIN::optimize() DBUG_PRINT("info",("Select tables optimized away")); zero_result_cause= "Select tables optimized away"; tables_list= 0; // All tables resolved + /* + Extract all table-independent conditions and replace the WHERE + clause with them. All other conditions were computed by opt_sum_query + and the MIN/MAX/COUNT function(s) have been replaced by constants, + so there is no need to compute the whole WHERE clause again. + Notice that make_cond_for_table() will always succeed to remove all + computed conditions, because opt_sum_query() is applicable only to + conjunctions. + */ + if (conds) + { + COND *table_independent_conds= + make_cond_for_table(conds, PSEUDO_TABLE_BITS, 0); + DBUG_EXECUTE("where", + print_where(table_independent_conds, + "where after opt_sum_query()");); + conds= table_independent_conds; + } } } if (!tables_list) @@ -1067,6 +1085,23 @@ JOIN::optimize() { need_tmp=1; simple_order=simple_group=0; // Force tmp table without sort } + if (order) + { + /* + Force using of tmp table if sorting by a SP or UDF function due to + their expensive and probably non-deterministic nature. + */ + for (ORDER *tmp_order= order; tmp_order ; tmp_order=tmp_order->next) + { + Item *item= *tmp_order->item; + if (item->walk(&Item::is_expensive_processor,(byte*)0)) + { + /* Force tmp table without sort */ + need_tmp=1; simple_order=simple_group=0; + break; + } + } + } } tmp_having= having; @@ -1212,6 +1247,11 @@ int JOIN::reinit() { DBUG_ENTER("JOIN::reinit"); + + unit->offset_limit_cnt= (ha_rows)(select_lex->offset_limit ? + select_lex->offset_limit->val_uint() : + ULL(0)); + first_record= 0; if (exec_tmp_table1) @@ -2492,8 +2532,11 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end, /* field = expression OR field IS NULL */ old->level= and_level; old->optimize= KEY_OPTIMIZE_REF_OR_NULL; - /* Remember the NOT NULL value */ - if (old->val->is_null()) + /* + Remember the NOT NULL value unless the value does not depend + on other tables. + */ + if (!old->val->used_tables() && old->val->is_null()) old->val= new_fields->val; /* The referred expression can be NULL: */ old->null_rejecting= 0; @@ -5520,6 +5563,7 @@ make_join_readinfo(JOIN *join, uint options) { uint i; bool statistics= test(!(join->select_options & SELECT_DESCRIBE)); + bool ordered_set= 0; bool sorted= 1; DBUG_ENTER("make_join_readinfo"); @@ -5530,6 +5574,22 @@ make_join_readinfo(JOIN *join, uint options) tab->read_record.table= table; tab->read_record.file=table->file; tab->next_select=sub_select; /* normal select */ + + /* + Determine if the set is already ordered for ORDER BY, so it can + disable join cache because it will change the ordering of the results. + Code handles sort table that is at any location (not only first after + the const tables) despite the fact that it's currently prohibited. + */ + if (!ordered_set && + (table == join->sort_by_table && + (!join->order || join->skip_sort_order || + test_if_skip_sort_order(tab, join->order, join->select_limit, + 1)) + ) || + (join->sort_by_table == (TABLE *) 1 && i != join->const_tables)) + ordered_set= 1; + tab->sorted= sorted; sorted= 0; // only first must be sorted switch (tab->type) { @@ -5602,10 +5662,11 @@ make_join_readinfo(JOIN *join, uint options) case JT_ALL: /* If previous table use cache + If the incoming data set is already sorted don't use cache. */ table->status=STATUS_NO_RECORD; if (i != join->const_tables && !(options & SELECT_NO_JOIN_CACHE) && - tab->use_quick != 2 && !tab->first_inner) + tab->use_quick != 2 && !tab->first_inner && !ordered_set) { if ((options & SELECT_DESCRIBE) || !join_init_cache(join->thd,join->join_tab+join->const_tables, @@ -6192,10 +6253,16 @@ return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables, DBUG_RETURN(0); } - +/* + used only in JOIN::clear +*/ static void clear_tables(JOIN *join) { - for (uint i=0 ; i < join->tables ; i++) + /* + must clear only the non-const tables, as const tables + are not re-calculated. + */ + for (uint i=join->const_tables ; i < join->tables ; i++) mark_as_null_row(join->table[i]); // All fields are NULL } @@ -8056,7 +8123,12 @@ Field *create_tmp_field_from_field(THD *thd, Field *org_field, { Field *new_field; - if (convert_blob_length && (org_field->flags & BLOB_FLAG)) + /* + Make sure that the blob fits into a Field_varstring which has + 2-byte lenght. + */ + if (convert_blob_length && convert_blob_length < UINT_MAX16 && + (org_field->flags & BLOB_FLAG)) new_field= new Field_varstring(convert_blob_length, org_field->maybe_null(), org_field->field_name, table->s, @@ -8121,8 +8193,13 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, item->name, item->decimals); break; case INT_RESULT: - new_field= new Field_longlong(item->max_length, maybe_null, - item->name, item->unsigned_flag); + /* Select an integer type with the minimal fit precision */ + if (item->max_length > 11) + new_field=new Field_longlong(item->max_length, maybe_null, + item->name, item->unsigned_flag); + else + new_field=new Field_long(item->max_length, maybe_null, + item->name, item->unsigned_flag); break; case STRING_RESULT: DBUG_ASSERT(item->collation.collation); @@ -8135,8 +8212,13 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, if ((type= item->field_type()) == MYSQL_TYPE_DATETIME || type == MYSQL_TYPE_TIME || type == MYSQL_TYPE_DATE) new_field= item->tmp_table_field_from_field_type(table, 1); + /* + Make sure that the blob fits into a Field_varstring which has + 2-byte lenght. + */ else if (item->max_length/item->collation.collation->mbmaxlen > 255 && - convert_blob_length) + item->max_length/item->collation.collation->mbmaxlen < UINT_MAX16 + && convert_blob_length) new_field= new Field_varstring(convert_blob_length, maybe_null, item->name, table->s, item->collation.collation); @@ -10710,8 +10792,13 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), { if (!join->first_record) { + List_iterator_fast<Item> it(*join->fields); + Item *item; /* No matching rows for group function */ join->clear(); + + while ((item= it++)) + item->no_rows_in_result(); } if (join->having && join->having->val_int() == 0) error= -1; // Didn't satisfy having @@ -12881,7 +12968,7 @@ count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields, { if (! field->const_item()) { - Item_sum *sum_item=(Item_sum*) field; + Item_sum *sum_item=(Item_sum*) field->real_item(); if (!sum_item->quick_group) param->quick_group=0; // UDF SUM function param->sum_func_count++; @@ -13141,10 +13228,11 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, param->copy_funcs.empty(); for (i= 0; (pos= li++); i++) { - if (pos->real_item()->type() == Item::FIELD_ITEM) + Item *real_pos= pos->real_item(); + if (real_pos->type() == Item::FIELD_ITEM) { Item_field *item; - pos= pos->real_item(); + pos= real_pos; if (!(item= new Item_field(thd, ((Item_field*) pos)))) goto err; pos= item; @@ -13183,12 +13271,13 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, } } } - else if ((pos->type() == Item::FUNC_ITEM || - pos->type() == Item::SUBSELECT_ITEM || - pos->type() == Item::CACHE_ITEM || - pos->type() == Item::COND_ITEM) && - !pos->with_sum_func) + else if ((real_pos->type() == Item::FUNC_ITEM || + real_pos->type() == Item::SUBSELECT_ITEM || + real_pos->type() == Item::CACHE_ITEM || + real_pos->type() == Item::COND_ITEM) && + !real_pos->with_sum_func) { // Save for send fields + pos= real_pos; /* TODO: In most cases this result will be sent to the user. This should be changed to use copy_int or copy_real depending diff --git a/sql/sql_show.cc b/sql/sql_show.cc index d80282eecf6..bf09f516499 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -5107,6 +5107,7 @@ bool get_schema_tables_result(JOIN *join) table_list->table->file->delete_all_rows(); free_io_cache(table_list->table); filesort_free_buffers(table_list->table); + table_list->table->null_row= 0; } else table_list->table->file->stats.records= 0; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index ff422c4418c..9236820cd25 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5766,8 +5766,8 @@ select_item: YYABORT; if ($4.str) { - $2->set_name($4.str, $4.length, system_charset_info); $2->is_autogenerated_name= FALSE; + $2->set_name($4.str, $4.length, system_charset_info); } else if (!$2->name) { char *str = $1; @@ -6655,8 +6655,8 @@ udf_expr: { if ($4.str) { - $2->set_name($4.str, $4.length, system_charset_info); $2->is_autogenerated_name= FALSE; + $2->set_name($4.str, $4.length, system_charset_info); } else $2->set_name($1, (uint) ($3 - $1), YYTHD->charset()); |