diff options
author | Alexander Barkov <bar@mnogosearch.org> | 2013-10-15 10:26:08 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mnogosearch.org> | 2013-10-15 10:26:08 +0400 |
commit | a9240dce9e2f32941611b4f1a52e3b30a1508fc2 (patch) | |
tree | ab7a7ec71341e29676d9a6bb039aeface4f88ce6 /sql | |
parent | 2c0a073970cf5f1dc679b34bb13e7fc55109dfd0 (diff) | |
parent | eb2c6f451392396ef2ca74f1dba761fc4459d171 (diff) | |
download | mariadb-git-a9240dce9e2f32941611b4f1a52e3b30a1508fc2.tar.gz |
Merge 10.0-base -> 10.0
Diffstat (limited to 'sql')
-rw-r--r-- | sql/CMakeLists.txt | 5 | ||||
-rw-r--r-- | sql/item.cc | 10 | ||||
-rw-r--r-- | sql/item.h | 1 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 248 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 141 | ||||
-rw-r--r-- | sql/item_create.cc | 69 | ||||
-rw-r--r-- | sql/item_func.cc | 10 | ||||
-rw-r--r-- | sql/item_func.h | 17 | ||||
-rw-r--r-- | sql/item_strfunc.cc | 181 | ||||
-rw-r--r-- | sql/item_strfunc.h | 43 | ||||
-rw-r--r-- | sql/mysqld.cc | 65 | ||||
-rw-r--r-- | sql/rpl_mi.h | 2 | ||||
-rw-r--r-- | sql/slave.cc | 42 | ||||
-rw-r--r-- | sql/spatial.cc | 6 | ||||
-rw-r--r-- | sql/sql_base.cc | 1 | ||||
-rw-r--r-- | sql/sql_derived.cc | 2 | ||||
-rw-r--r-- | sql/sql_select.cc | 65 | ||||
-rw-r--r-- | sql/sql_select.h | 5 | ||||
-rw-r--r-- | sql/sql_string.h | 5 |
19 files changed, 757 insertions, 161 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 56fa8ac8990..c4e0729b678 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -16,7 +16,8 @@ INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/sql -${CMAKE_SOURCE_DIR}/regex +${CMAKE_BINARY_DIR}/pcre +${CMAKE_SOURCE_DIR}/pcre ${ZLIB_INCLUDE_DIR} ${SSL_INCLUDE_DIRS} ${CMAKE_BINARY_DIR}/sql @@ -109,7 +110,7 @@ ADD_LIBRARY(sql STATIC ${SQL_SOURCE}) ADD_DEPENDENCIES(sql GenServerSource) DTRACE_INSTRUMENT(sql) TARGET_LINK_LIBRARIES(sql ${MYSQLD_STATIC_PLUGIN_LIBS} - mysys mysys_ssl dbug strings vio regex ${LIBJEMALLOC} + mysys mysys_ssl dbug strings vio pcre ${LIBJEMALLOC} ${LIBWRAP} ${LIBCRYPT} ${LIBDL} ${CMAKE_THREAD_LIBS_INIT} ${SSL_LIBRARIES}) diff --git a/sql/item.cc b/sql/item.cc index c806b1a6968..570af9fe5b7 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -5129,6 +5129,11 @@ bool Item_field::fix_fields(THD *thd, Item **reference) goto mark_non_agg_field; } + if (thd->lex->in_sum_func && + thd->lex->in_sum_func->nest_level == + thd->lex->current_select->nest_level) + set_if_bigger(thd->lex->in_sum_func->max_arg_level, + thd->lex->current_select->nest_level); /* if it is not expression from merged VIEW we will set this field. @@ -5145,11 +5150,6 @@ bool Item_field::fix_fields(THD *thd, Item **reference) return FALSE; set_field(from_field); - if (thd->lex->in_sum_func && - thd->lex->in_sum_func->nest_level == - thd->lex->current_select->nest_level) - set_if_bigger(thd->lex->in_sum_func->max_arg_level, - thd->lex->current_select->nest_level); } else if (thd->mark_used_columns != MARK_COLUMNS_NONE) { diff --git a/sql/item.h b/sql/item.h index e03012d9403..31a638fc9ec 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1195,6 +1195,7 @@ public: virtual bool view_used_tables_processor(uchar *arg) { return 0; } virtual bool eval_not_null_tables(uchar *opt_arg) { return 0; } virtual bool is_subquery_processor (uchar *opt_arg) { return 0; } + virtual bool count_sargable_conds(uchar *arg) { return 0; } virtual bool limit_index_condition_pushdown_processor(uchar *opt_arg) { return FALSE; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 0fd5ee4048b..5efa27ff083 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1435,6 +1435,7 @@ bool Item_in_optimizer::eval_not_null_tables(uchar *opt_arg) return FALSE; } + bool Item_in_optimizer::fix_left(THD *thd) { if ((!args[0]->fixed && args[0]->fix_fields(thd, args)) || @@ -2205,6 +2206,15 @@ bool Item_func_between::eval_not_null_tables(uchar *opt_arg) } +bool Item_func_between::count_sargable_conds(uchar *arg) +{ + SELECT_LEX *sel= (SELECT_LEX *) arg; + sel->cond_count++; + sel->between_count++; + return 0; +} + + void Item_func_between::fix_after_pullout(st_select_lex *new_parent, Item **ref) { /* This will re-calculate attributes of the arguments */ @@ -4802,6 +4812,7 @@ longlong Item_func_isnull::val_int() return args[0]->is_null() ? 1: 0; } + longlong Item_is_not_null_test::val_int() { DBUG_ASSERT(fixed == 1); @@ -5006,6 +5017,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref) return FALSE; } + void Item_func_like::cleanup() { canDoTurboBM= FALSE; @@ -5034,139 +5046,193 @@ bool Item_func_like::find_selective_predicates_list_processor(uchar *arg) } + +/** + Convert string to lib_charset, if needed. +*/ +String *Regexp_processor_pcre::convert_if_needed(String *str, String *converter) +{ + if (m_conversion_is_needed) + { + uint dummy_errors; + if (converter->copy(str->ptr(), str->length(), str->charset(), + m_library_charset, &dummy_errors)) + return NULL; + str= converter; + } + return str; +} + + /** @brief Compile regular expression. + @param[in] pattern the pattern to compile from. @param[in] send_error send error message if any. @details Make necessary character set conversion then compile regular expression passed in the args[1]. - @retval 0 success. - @retval 1 error occurred. - @retval -1 given null regular expression. + @retval false success. + @retval true error occurred. */ -int Item_func_regex::regcomp(bool send_error) +bool Regexp_processor_pcre::compile(String *pattern, bool send_error) { - char buff[MAX_FIELD_WIDTH]; - String tmp(buff,sizeof(buff),&my_charset_bin); - String *res= args[1]->val_str(&tmp); - int error; + const char *pcreErrorStr; + int pcreErrorOffset; - if (args[1]->null_value) - return -1; - - if (regex_compiled) + if (is_compiled()) { - if (!stringcmp(res, &prev_regexp)) - return 0; - prev_regexp.copy(*res); - my_regfree(&preg); - regex_compiled= 0; + if (!stringcmp(pattern, &m_prev_pattern)) + return false; + m_prev_pattern.copy(*pattern); + pcre_free(m_pcre); + m_pcre= NULL; } - if (cmp_collation.collation != regex_lib_charset) - { - /* Convert UCS2 strings to UTF8 */ - uint dummy_errors; - if (conv.copy(res->ptr(), res->length(), res->charset(), - regex_lib_charset, &dummy_errors)) - return 1; - res= &conv; - } + if (!(pattern= convert_if_needed(pattern, &pattern_converter))) + return true; + + m_pcre= pcre_compile(pattern->c_ptr_safe(), m_library_flags, + &pcreErrorStr, &pcreErrorOffset, NULL); - if ((error= my_regcomp(&preg, res->c_ptr_safe(), - regex_lib_flags, regex_lib_charset))) + if (m_pcre == NULL) { if (send_error) { - (void) my_regerror(error, &preg, buff, sizeof(buff)); + char buff[MAX_FIELD_WIDTH]; + my_snprintf(buff, sizeof(buff), "%s at offset %d", pcreErrorStr, pcreErrorOffset); my_error(ER_REGEXP_ERROR, MYF(0), buff); } - return 1; + return true; } - regex_compiled= 1; - return 0; + return false; } -void -Item_func_regex::fix_length_and_dec() +bool Regexp_processor_pcre::compile(Item *item, bool send_error) { - Item_bool_func::fix_length_and_dec(); + char buff[MAX_FIELD_WIDTH]; + String tmp(buff, sizeof(buff), &my_charset_bin); + String *pattern= item->val_str(&tmp); + if (item->null_value || compile(pattern, send_error)) + return true; + return false; +} - if (agg_arg_charsets_for_comparison(cmp_collation, args, 2)) - return; - regex_lib_flags= (cmp_collation.collation->state & - (MY_CS_BINSORT | MY_CS_CSSORT)) ? - REG_EXTENDED | REG_NOSUB : - REG_EXTENDED | REG_NOSUB | REG_ICASE; - /* - If the case of UCS2 and other non-ASCII character sets, - we will convert patterns and strings to UTF8. - */ - regex_lib_charset= (cmp_collation.collation->mbminlen > 1) ? - &my_charset_utf8_general_ci : - cmp_collation.collation; +bool Regexp_processor_pcre::exec(const char *str, int length, int offset) +{ + m_pcre_exec_rc= pcre_exec(m_pcre, NULL, str, length, + offset, 0, m_SubStrVec, m_subpatterns_needed * 3); + return false; +} + - if (!regex_compiled && args[1]->const_item()) +bool Regexp_processor_pcre::exec(String *str, int offset, + uint n_result_offsets_to_convert) +{ + if (!(str= convert_if_needed(str, &subject_converter))) + return true; + m_pcre_exec_rc= pcre_exec(m_pcre, NULL, str->c_ptr_safe(), str->length(), + offset, 0, m_SubStrVec, m_subpatterns_needed * 3); + if (m_pcre_exec_rc > 0) { - int comp_res= regcomp(TRUE); - if (comp_res == -1) - { // Will always return NULL - maybe_null= 1; - return; + uint i; + for (i= 0; i < n_result_offsets_to_convert; i++) + { + /* + Convert byte offset into character offset. + */ + m_SubStrVec[i]= (int) str->charset()->cset->numchars(str->charset(), + str->ptr(), + str->ptr() + + m_SubStrVec[i]); } - else if (comp_res) - return; /* Error */ - regex_is_const= 1; - maybe_null= args[0]->maybe_null; } - else - maybe_null=1; + return false; } -longlong Item_func_regex::val_int() +bool Regexp_processor_pcre::exec(Item *item, int offset, + uint n_result_offsets_to_convert) { - DBUG_ASSERT(fixed == 1); char buff[MAX_FIELD_WIDTH]; String tmp(buff,sizeof(buff),&my_charset_bin); - String *res= args[0]->val_str(&tmp); + String *res= item->val_str(&tmp); + if (item->null_value) + return true; + return exec(res, offset, n_result_offsets_to_convert); +} - if ((null_value= (args[0]->null_value || - (!regex_is_const && regcomp(FALSE))))) - return 0; - if (cmp_collation.collation != regex_lib_charset) +void Regexp_processor_pcre::fix_owner(Item_func *owner, + Item *subject_arg, + Item *pattern_arg) +{ + if (!is_compiled() && pattern_arg->const_item()) { - /* Convert UCS2 strings to UTF8 */ - uint dummy_errors; - if (conv.copy(res->ptr(), res->length(), res->charset(), - regex_lib_charset, &dummy_errors)) + if (compile(pattern_arg, true)) { - null_value= 1; - return 0; + owner->maybe_null= 1; // Will always return NULL + return; } - res= &conv; + set_const(true); + owner->maybe_null= subject_arg->maybe_null; } - return my_regexec(&preg,res->c_ptr_safe(),0,(my_regmatch_t*) 0,0) ? 0 : 1; + else + owner->maybe_null= 1; } -void Item_func_regex::cleanup() +void +Item_func_regex::fix_length_and_dec() { - DBUG_ENTER("Item_func_regex::cleanup"); - Item_bool_func::cleanup(); - if (regex_compiled) - { - my_regfree(&preg); - regex_compiled=0; - prev_regexp.length(0); - } - DBUG_VOID_RETURN; + Item_bool_func::fix_length_and_dec(); + + if (agg_arg_charsets_for_comparison(cmp_collation, args, 2)) + return; + + re.init(cmp_collation.collation, 0, 0); + re.fix_owner(this, args[0], args[1]); +} + + +longlong Item_func_regex::val_int() +{ + DBUG_ASSERT(fixed == 1); + if ((null_value= re.recompile(args[1]))) + return 0; + + if ((null_value= re.exec(args[0], 0, 0))) + return 0; + + return re.match(); +} + + +void +Item_func_regexp_instr::fix_length_and_dec() +{ + if (agg_arg_charsets_for_comparison(cmp_collation, args, 2)) + return; + + re.init(cmp_collation.collation, 0, 1); + re.fix_owner(this, args[0], args[1]); +} + + +longlong Item_func_regexp_instr::val_int() +{ + DBUG_ASSERT(fixed == 1); + if ((null_value= re.recompile(args[1]))) + return 0; + + if ((null_value= re.exec(args[0], 0, 1))) + return 0; + + return re.match() ? re.subpattern_start(0) + 1 : 0; } @@ -5642,7 +5708,8 @@ Item_equal::Item_equal(Item *f1, Item *f2, bool with_const_item) equal_items.push_back(f1); equal_items.push_back(f2); compare_as_dates= with_const_item && f2->cmp_type() == TIME_RESULT; - upper_levels= NULL; + upper_levels= NULL; + sargable= TRUE; } @@ -5673,6 +5740,7 @@ Item_equal::Item_equal(Item_equal *item_equal) compare_as_dates= item_equal->compare_as_dates; cond_false= item_equal->cond_false; upper_levels= item_equal->upper_levels; + sargable= TRUE; } @@ -6073,6 +6141,14 @@ void Item_equal::update_used_tables() } +bool Item_equal::count_sargable_conds(uchar *arg) +{ + SELECT_LEX *sel= (SELECT_LEX *) arg; + uint m= equal_items.elements; + sel->cond_count+= m*(m-1); + return 0; +} + /** @brief diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 823de615cc2..50d1eb036ff 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -25,7 +25,8 @@ #include "thr_malloc.h" /* sql_calloc */ #include "item_func.h" /* Item_int_func, Item_bool_func */ -#include "my_regex.h" +#define PCRE_STATIC 1 /* Important on Windows */ +#include "pcre.h" /* pcre header file */ extern Item_result item_cmp_type(Item_result a,Item_result b); class Item_bool_func2; @@ -371,7 +372,8 @@ protected: public: Item_bool_func2(Item *a,Item *b) - :Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1), abort_on_null(FALSE) {} + :Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1), + abort_on_null(FALSE) { sargable= TRUE; } void fix_length_and_dec(); int set_cmp_func() { @@ -676,7 +678,7 @@ public: /* TRUE <=> arguments will be compared as dates. */ Item *compare_as_dates; Item_func_between(Item *a, Item *b, Item *c) - :Item_func_opt_neg(a, b, c), compare_as_dates(FALSE) {} + :Item_func_opt_neg(a, b, c), compare_as_dates(FALSE) { sargable= TRUE; } longlong val_int(); optimize_type select_optimize() const { return OPTIMIZE_KEY; } enum Functype functype() const { return BETWEEN; } @@ -689,6 +691,7 @@ public: uint decimal_precision() const { return 1; } bool eval_not_null_tables(uchar *opt_arg); void fix_after_pullout(st_select_lex *new_parent, Item **ref); + bool count_sargable_conds(uchar *arg); }; @@ -1294,10 +1297,11 @@ public: Item_func_in(List<Item> &list) :Item_func_opt_neg(list), array(0), have_null(0), - arg_types_compatible(FALSE) + arg_types_compatible(FALSE) { bzero(&cmp_items, sizeof(cmp_items)); allowed_arg_cols= 0; // Fetch this value from first argument + sargable= TRUE; } longlong val_int(); bool fix_fields(THD *, Item **); @@ -1363,7 +1367,7 @@ public: class Item_func_isnull :public Item_bool_func { public: - Item_func_isnull(Item *a) :Item_bool_func(a) {} + Item_func_isnull(Item *a) :Item_bool_func(a) { sargable= TRUE; } longlong val_int(); enum Functype functype() const { return ISNULL_FUNC; } void fix_length_and_dec() @@ -1425,7 +1429,8 @@ class Item_func_isnotnull :public Item_bool_func { bool abort_on_null; public: - Item_func_isnotnull(Item *a) :Item_bool_func(a), abort_on_null(0) {} + Item_func_isnotnull(Item *a) :Item_bool_func(a), abort_on_null(0) + { sargable= TRUE; } longlong val_int(); enum Functype functype() const { return ISNOTNULL_FUNC; } void fix_length_and_dec() @@ -1484,21 +1489,100 @@ public: }; +class Regexp_processor_pcre +{ + pcre *m_pcre; + bool m_conversion_is_needed; + bool m_is_const; + int m_library_flags; + CHARSET_INFO *m_data_charset; + CHARSET_INFO *m_library_charset; + String m_prev_pattern; + int m_pcre_exec_rc; + int m_SubStrVec[30]; + uint m_subpatterns_needed; +public: + String *convert_if_needed(String *src, String *converter); + String subject_converter; + String pattern_converter; + String replace_converter; + Regexp_processor_pcre() : + m_pcre(NULL), m_conversion_is_needed(true), m_is_const(0), + m_library_flags(0), + m_data_charset(&my_charset_utf8_general_ci), + m_library_charset(&my_charset_utf8_general_ci), + m_subpatterns_needed(0) + {} + void init(CHARSET_INFO *data_charset, int extra_flags, uint nsubpatterns) + { + m_library_flags= extra_flags | + (data_charset != &my_charset_bin ? + (PCRE_UTF8 | PCRE_UCP) : 0) | + ((data_charset->state & + (MY_CS_BINSORT | MY_CS_CSSORT)) ? 0 : PCRE_CASELESS); + + // Convert text data to utf-8. + m_library_charset= data_charset == &my_charset_bin ? + &my_charset_bin : &my_charset_utf8_general_ci; + + m_conversion_is_needed= (data_charset != &my_charset_bin) && + !my_charset_same(data_charset, m_library_charset); + m_subpatterns_needed= nsubpatterns; + } + void fix_owner(Item_func *owner, Item *subject_arg, Item *pattern_arg); + bool compile(String *pattern, bool send_error); + bool compile(Item *item, bool send_error); + bool recompile(Item *item) + { + return !m_is_const && compile(item, false); + } + bool exec(const char *str, int length, int offset); + bool exec(String *str, int offset, uint n_result_offsets_to_convert); + bool exec(Item *item, int offset, uint n_result_offsets_to_convert); + bool match() const { return m_pcre_exec_rc < 0 ? 0 : 1; } + int nsubpatterns() const { return m_pcre_exec_rc <= 0 ? 0 : m_pcre_exec_rc; } + int subpattern_start(int n) const + { + return m_pcre_exec_rc <= 0 ? 0 : m_SubStrVec[n * 2]; + } + int subpattern_end(int n) const + { + return m_pcre_exec_rc <= 0 ? 0 : m_SubStrVec[n * 2 + 1]; + } + int subpattern_length(int n) const + { + return subpattern_end(n) - subpattern_start(n); + } + void cleanup() + { + if (m_pcre) + { + pcre_free(m_pcre); + m_pcre= NULL; + } + m_prev_pattern.length(0); + } + bool is_compiled() const { return m_pcre != NULL; } + bool is_const() const { return m_is_const; } + void set_const(bool arg) { m_is_const= arg; } + CHARSET_INFO * library_charset() const { return m_library_charset; } +}; + + class Item_func_regex :public Item_bool_func { - my_regex_t preg; - bool regex_compiled; - bool regex_is_const; - String prev_regexp; + Regexp_processor_pcre re; DTCollation cmp_collation; - CHARSET_INFO *regex_lib_charset; - int regex_lib_flags; - String conv; - int regcomp(bool send_error); public: - Item_func_regex(Item *a,Item *b) :Item_bool_func(a,b), - regex_compiled(0),regex_is_const(0) {} - void cleanup(); + Item_func_regex(Item *a,Item *b) :Item_bool_func(a,b) + {} + void cleanup() + { + DBUG_ENTER("Item_func_regex::cleanup"); + Item_bool_func::cleanup(); + re.cleanup(); + DBUG_VOID_RETURN; + } longlong val_int(); void fix_length_and_dec(); const char *func_name() const { return "regexp"; } @@ -1512,6 +1596,26 @@ public: }; +class Item_func_regexp_instr :public Item_int_func +{ + Regexp_processor_pcre re; + DTCollation cmp_collation; +public: + Item_func_regexp_instr(Item *a, Item *b) :Item_int_func(a, b) + {} + void cleanup() + { + DBUG_ENTER("Item_func_regexp_instr::cleanup"); + Item_int_func::cleanup(); + re.cleanup(); + DBUG_VOID_RETURN; + } + longlong val_int(); + void fix_length_and_dec(); + const char *func_name() const { return "regexp_instr"; } +}; + + typedef class Item COND; class Item_cond :public Item_bool_func @@ -1717,7 +1821,7 @@ public: inline Item_equal() : Item_bool_func(), with_const(FALSE), eval_item(0), cond_false(0), context_field(NULL) - { const_item_cache=0 ;} + { const_item_cache=0; sargable= TRUE; } Item_equal(Item *f1, Item *f2, bool with_const_item); Item_equal(Item_equal *item_equal); /* Currently the const item is always the first in the list of equal items */ @@ -1750,6 +1854,7 @@ public: void set_context_field(Item_field *ctx_field) { context_field= ctx_field; } void set_link_equal_fields(bool flag) { link_equal_fields= flag; } friend class Item_equal_fields_iterator; + bool count_sargable_conds(uchar *arg); friend class Item_equal_iterator<List_iterator_fast,Item>; friend class Item_equal_iterator<List_iterator,Item>; friend Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels, diff --git a/sql/item_create.cc b/sql/item_create.cc index 9842f88e904..fa8c016d61b 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -2028,6 +2028,45 @@ protected: }; +class Create_func_regexp_instr : public Create_func_arg2 +{ +public: + virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2); + + static Create_func_regexp_instr s_singleton; + +protected: + Create_func_regexp_instr() {} + virtual ~Create_func_regexp_instr() {} +}; + + +class Create_func_regexp_replace : public Create_func_arg3 +{ +public: + virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3); + + static Create_func_regexp_replace s_singleton; + +protected: + Create_func_regexp_replace() {} + virtual ~Create_func_regexp_replace() {} +}; + + +class Create_func_regexp_substr : public Create_func_arg2 +{ +public: + virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2); + + static Create_func_regexp_substr s_singleton; + +protected: + Create_func_regexp_substr() {} + virtual ~Create_func_regexp_substr() {} +}; + + class Create_func_radians : public Create_func_arg1 { public: @@ -4743,6 +4782,33 @@ Create_func_quote::create_1_arg(THD *thd, Item *arg1) } +Create_func_regexp_instr Create_func_regexp_instr::s_singleton; + +Item* +Create_func_regexp_instr::create_2_arg(THD *thd, Item *arg1, Item *arg2) +{ + return new (thd->mem_root) Item_func_regexp_instr(arg1, arg2); +} + + +Create_func_regexp_replace Create_func_regexp_replace::s_singleton; + +Item* +Create_func_regexp_replace::create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3) +{ + return new (thd->mem_root) Item_func_regexp_replace(arg1, arg2, arg3); +} + + +Create_func_regexp_substr Create_func_regexp_substr::s_singleton; + +Item* +Create_func_regexp_substr::create_2_arg(THD *thd, Item *arg1, Item *arg2) +{ + return new (thd->mem_root) Item_func_regexp_substr(arg1, arg2); +} + + Create_func_radians Create_func_radians::s_singleton; Item* @@ -5536,6 +5602,9 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("POW") }, BUILDER(Create_func_pow)}, { { C_STRING_WITH_LEN("POWER") }, BUILDER(Create_func_pow)}, { { C_STRING_WITH_LEN("QUOTE") }, BUILDER(Create_func_quote)}, + { { C_STRING_WITH_LEN("REGEXP_INSTR") }, BUILDER(Create_func_regexp_instr)}, + { { C_STRING_WITH_LEN("REGEXP_REPLACE") }, BUILDER(Create_func_regexp_replace)}, + { { C_STRING_WITH_LEN("REGEXP_SUBSTR") }, BUILDER(Create_func_regexp_substr)}, { { C_STRING_WITH_LEN("RADIANS") }, BUILDER(Create_func_radians)}, { { C_STRING_WITH_LEN("RAND") }, BUILDER(Create_func_rand)}, { { C_STRING_WITH_LEN("RELEASE_LOCK") }, BUILDER(Create_func_release_lock)}, diff --git a/sql/item_func.cc b/sql/item_func.cc index 27f9881d91e..1f516724a5f 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -759,6 +759,16 @@ double Item_int_func::val_real() return unsigned_flag ? (double) ((ulonglong) val_int()) : (double) val_int(); } +bool Item_int_func::count_sargable_conds(uchar *arg) +{ + if (sargable) + { + SELECT_LEX *sel= (SELECT_LEX *) arg; + sel->cond_count++; + } + return 0; +} + String *Item_int_func::val_str(String *str) { diff --git a/sql/item_func.h b/sql/item_func.h index 5c48498001b..03e67ddf11a 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -576,25 +576,28 @@ class Item_num_op :public Item_func_numhybrid class Item_int_func :public Item_func { +protected: + bool sargable; public: Item_int_func() :Item_func() - { collation.set_numeric(); fix_char_length(21); } + { collation.set_numeric(); fix_char_length(21); sargable= false; } Item_int_func(Item *a) :Item_func(a) - { collation.set_numeric(); fix_char_length(21); } + { collation.set_numeric(); fix_char_length(21); sargable= false; } Item_int_func(Item *a,Item *b) :Item_func(a,b) - { collation.set_numeric(); fix_char_length(21); } + { collation.set_numeric(); fix_char_length(21); sargable= false; } Item_int_func(Item *a,Item *b,Item *c) :Item_func(a,b,c) - { collation.set_numeric(); fix_char_length(21); } + { collation.set_numeric(); fix_char_length(21); sargable= false; } Item_int_func(Item *a,Item *b,Item *c, Item *d) :Item_func(a,b,c,d) - { collation.set_numeric(); fix_char_length(21); } + { collation.set_numeric(); fix_char_length(21); sargable= false; } Item_int_func(List<Item> &list) :Item_func(list) - { collation.set_numeric(); fix_char_length(21); } + { collation.set_numeric(); fix_char_length(21); sargable= false; } Item_int_func(THD *thd, Item_int_func *item) :Item_func(thd, item) - { collation.set_numeric(); } + { collation.set_numeric(); sargable= false; } double val_real(); String *val_str(String*str); enum Item_result result_type () const { return INT_RESULT; } void fix_length_and_dec() {} + bool count_sargable_conds(uchar *arg); }; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index d7aea544fee..8dd2a33b1a0 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1338,6 +1338,187 @@ void Item_func_replace::fix_length_and_dec() } +/*********************************************************************/ +void Item_func_regexp_replace::fix_length_and_dec() +{ + if (agg_arg_charsets_for_string_result_with_comparison(collation, args, 3)) + return; + max_length= MAX_BLOB_WIDTH; + re.init(collation.collation, 0, 10); + re.fix_owner(this, args[0], args[1]); +} + + +/* + Traverse through the replacement string and append to "str". + Sub-pattern references \0 .. \9 are recognized, which are replaced + to the chunks of the source string. +*/ +bool Item_func_regexp_replace::append_replacement(String *str, + const LEX_CSTRING *source, + const LEX_CSTRING *replace) +{ + const char *beg= replace->str; + const char *end= beg + replace->length; + CHARSET_INFO *cs= re.library_charset(); + + for ( ; ; ) + { + my_wc_t wc; + int cnv, n; + + if ((cnv= cs->cset->mb_wc(cs, &wc, (const uchar *) beg, + (const uchar *) end)) < 1) + break; /* End of line */ + beg+= cnv; + + if (wc != '\\') + { + if (str->append(beg - cnv, cnv, cs)) + return true; + continue; + } + + if ((cnv= cs->cset->mb_wc(cs, &wc, (const uchar *) beg, + (const uchar *) end)) < 1) + break; /* End of line */ + beg+= cnv; + + if ((n= ((int) wc) - '0') >= 0 && n <= 9 && n < re.nsubpatterns()) + { + /* A valid sub-pattern reference found */ + int pbeg= re.subpattern_start(n), plength= re.subpattern_end(n) - pbeg; + if (str->append(source->str + pbeg, plength, cs)) + return true; + } + else + { + /* + A non-digit character following after '\'. + Just add the character itself. + */ + if (str->append(beg - cnv, cnv, cs)) + return false; + } + } + return false; +} + + +String *Item_func_regexp_replace::val_str(String *str) +{ + DBUG_ASSERT(fixed == 1); + char buff0[MAX_FIELD_WIDTH]; + char buff2[MAX_FIELD_WIDTH]; + String tmp0(buff0,sizeof(buff0),&my_charset_bin); + String tmp2(buff2,sizeof(buff2),&my_charset_bin); + String *source= args[0]->val_str(&tmp0); + String *replace= args[2]->val_str(&tmp2); + LEX_CSTRING src, rpl; + int startoffset= 0; + + if ((null_value= (args[0]->null_value || args[2]->null_value || + re.recompile(args[1])))) + return (String *) 0; + + if (!(source= re.convert_if_needed(source, &re.subject_converter)) || + !(replace= re.convert_if_needed(replace, &re.replace_converter))) + goto err; + + src= source->lex_cstring(); + rpl= replace->lex_cstring(); + + str->length(0); + str->set_charset(collation.collation); + + for ( ; ; ) // Iterate through all matches + { + + if (re.exec(src.str, src.length, startoffset)) + goto err; + + if (!re.match() || re.subpattern_length(0) == 0) + { + /* + No match or an empty match. + Append the rest of the source string + starting from startoffset until the end of the source. + */ + if (str->append(src.str + startoffset, src.length - startoffset, re.library_charset())) + goto err; + return str; + } + + /* + Append prefix, the part before the matching pattern. + starting from startoffset until the next match + */ + if (str->append(src.str + startoffset, re.subpattern_start(0) - startoffset, re.library_charset())) + goto err; + + // Append replacement + if (append_replacement(str, &src, &rpl)) + goto err; + + // Set the new start point as the end of previous match + startoffset= re.subpattern_end(0); + } + return str; + +err: + null_value= true; + return (String *) 0; +} + + +void Item_func_regexp_substr::fix_length_and_dec() +{ + if (agg_arg_charsets_for_string_result_with_comparison(collation, args, 2)) + return; + fix_char_length(args[0]->max_char_length()); + re.init(collation.collation, 0, 10); + re.fix_owner(this, args[0], args[1]); +} + + +String *Item_func_regexp_substr::val_str(String *str) +{ + DBUG_ASSERT(fixed == 1); + char buff0[MAX_FIELD_WIDTH]; + String tmp0(buff0,sizeof(buff0),&my_charset_bin); + String *source= args[0]->val_str(&tmp0); + + if ((null_value= (args[0]->null_value || re.recompile(args[1])))) + return (String *) 0; + + if (!(source= re.convert_if_needed(source, &re.subject_converter))) + goto err; + + str->length(0); + str->set_charset(collation.collation); + + if (re.exec(source->ptr(), source->length(), 0)) + goto err; + + if (!re.match()) + return str; + + if (str->append(source->ptr() + re.subpattern_start(0), + re.subpattern_end(0) - re.subpattern_start(0), + re.library_charset())) + goto err; + + return str; + +err: + null_value= true; + return (String *) 0; +} + + +/************************************************************************/ + + String *Item_func_insert::val_str(String *str) { DBUG_ASSERT(fixed == 1); diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 582fa05b4a1..9ae0c92673f 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -217,6 +217,49 @@ public: }; +class Item_func_regexp_replace :public Item_str_func +{ + Regexp_processor_pcre re; + bool append_replacement(String *str, + const LEX_CSTRING *source, + const LEX_CSTRING *replace); +public: + Item_func_regexp_replace(Item *a, Item *b, Item *c) + :Item_str_func(a, b, c) + {} + void cleanup() + { + DBUG_ENTER("Item_func_regex::cleanup"); + Item_str_func::cleanup(); + re.cleanup(); + DBUG_VOID_RETURN; + } + String *val_str(String *str); + void fix_length_and_dec(); + const char *func_name() const { return "regexp_replace"; } +}; + + +class Item_func_regexp_substr :public Item_str_func +{ + Regexp_processor_pcre re; +public: + Item_func_regexp_substr(Item *a, Item *b) + :Item_str_func(a, b) + {} + void cleanup() + { + DBUG_ENTER("Item_func_regex::cleanup"); + Item_str_func::cleanup(); + re.cleanup(); + DBUG_VOID_RETURN; + } + String *val_str(String *str); + void fix_length_and_dec(); + const char *func_name() const { return "regexp_substr"; } +}; + + class Item_func_insert :public Item_str_func { String tmp_value; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 18c93f676ac..1b8727563db 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2018,7 +2018,6 @@ void clean_up(bool print_message) delete global_rpl_filter; end_ssl(); vio_end(); - my_regex_end(); #if defined(ENABLED_DEBUG_SYNC) /* End the debug sync facility. See debug_sync.cc. */ debug_sync_end(); @@ -3401,7 +3400,6 @@ void my_message_sql(uint error, const char *str, myf MyFlags) } -#ifndef EMBEDDED_LIBRARY extern "C" void *my_str_malloc_mysqld(size_t size); extern "C" void my_str_free_mysqld(void *ptr); extern "C" void *my_str_realloc_mysqld(void *ptr, size_t size); @@ -3421,7 +3419,6 @@ void *my_str_realloc_mysqld(void *ptr, size_t size) { return my_realloc(ptr, size, MYF(MY_FAE)); } -#endif /* EMBEDDED_LIBRARY */ #ifdef __WIN__ @@ -3453,24 +3450,57 @@ sizeof(load_default_groups)/sizeof(load_default_groups[0]); /** This function is used to check for stack overrun for pathological cases of regular expressions and 'like' expressions. - The call to current_thd is quite expensive, so we try to avoid it - for the normal cases. +*/ +extern "C" int +check_enough_stack_size_slow() +{ + uchar stack_top; + THD *my_thd= current_thd; + if (my_thd != NULL) + return check_stack_overrun(my_thd, STACK_MIN_SIZE * 2, &stack_top); + return 0; +} + + +/* + The call to current_thd in check_enough_stack_size_slow is quite expensive, + so we try to avoid it for the normal cases. The size of each stack frame for the wildcmp() routines is ~128 bytes, so checking *every* recursive call is not necessary. */ extern "C" int check_enough_stack_size(int recurse_level) { - uchar stack_top; if (recurse_level % 16 != 0) return 0; + return check_enough_stack_size_slow(); +} +#endif - THD *my_thd= current_thd; - if (my_thd != NULL) - return check_stack_overrun(my_thd, STACK_MIN_SIZE * 2, &stack_top); - return 0; + + +/* + Initialize my_str_malloc() and my_str_free() +*/ +static void init_libstrings() +{ + my_str_malloc= &my_str_malloc_mysqld; + my_str_free= &my_str_free_mysqld; + my_str_realloc= &my_str_realloc_mysqld; +#ifndef EMBEDDED_LIBRARY + my_string_stack_guard= check_enough_stack_size; +#endif } + + +static void init_pcre() +{ + pcre_malloc= pcre_stack_malloc= my_str_malloc_mysqld; + pcre_free= pcre_stack_free= my_str_free_mysqld; +#ifndef EMBEDDED_LIBRARY + pcre_stack_guard= check_enough_stack_size_slow; #endif +} /** @@ -3799,6 +3829,7 @@ static int init_common_variables() set_current_thd(0); set_malloc_size_cb(my_malloc_size_cb_func); + init_libstrings(); tzset(); // Set tzname sf_leaking_memory= 0; // no memory leaks from now on @@ -4101,12 +4132,7 @@ static int init_common_variables() if (item_create_init()) return 1; item_init(); -#ifndef EMBEDDED_LIBRARY - my_regex_init(&my_charset_latin1, check_enough_stack_size); - my_string_stack_guard= check_enough_stack_size; -#else - my_regex_init(&my_charset_latin1, NULL); -#endif + init_pcre(); /* Process a comma-separated character set list and choose the first available character set. This is mostly for @@ -5263,13 +5289,6 @@ int mysqld_main(int argc, char **argv) #endif /* - Initialize my_str_malloc(), my_str_realloc() and my_str_free() - */ - my_str_malloc= &my_str_malloc_mysqld; - my_str_free= &my_str_free_mysqld; - my_str_realloc= &my_str_realloc_mysqld; - - /* init signals & alarm After this we can't quit by a simple unireg_abort */ diff --git a/sql/rpl_mi.h b/sql/rpl_mi.h index 991f6673c3a..a136af38356 100644 --- a/sql/rpl_mi.h +++ b/sql/rpl_mi.h @@ -162,6 +162,8 @@ class Master_info : public Slave_reporting_capability events_queued_since_last_gtid is non-zero. */ rpl_gtid last_queued_gtid; + /* Whether last_queued_gtid had the FL_STANDALONE flag set. */ + bool last_queued_gtid_standalone; /* When slave IO thread needs to reconnect, gtid_reconnect_event_skip_count counts number of events to skip from the first GTID-prefixed event group, diff --git a/sql/slave.cc b/sql/slave.cc index 332a4a9669a..350728f32e7 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -5203,11 +5203,11 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len) case GTID_EVENT: { - uchar dummy_flag; + uchar gtid_flag; if (Gtid_log_event::peek(buf, event_len, checksum_alg, &event_gtid.domain_id, &event_gtid.server_id, - &event_gtid.seq_no, &dummy_flag, + &event_gtid.seq_no, >id_flag, rli->relay_log.description_event_for_queue)) { error= ER_SLAVE_RELAY_LOG_WRITE_FAILURE; @@ -5260,6 +5260,9 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len) /* We have successfully queued to relay log everything before this GTID, so in case of reconnect we can start from after any previous GTID. + (Normally we would have updated gtid_current_pos earlier at the end of + the previous event group, but better leave an extra check here for + safety). */ if (mi->events_queued_since_last_gtid) { @@ -5267,6 +5270,8 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len) mi->events_queued_since_last_gtid= 0; } mi->last_queued_gtid= event_gtid; + mi->last_queued_gtid_standalone= + (gtid_flag & Gtid_log_event::FL_STANDALONE) != 0; ++mi->events_queued_since_last_gtid; inc_pos= event_len; } @@ -5348,6 +5353,19 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len) else rli->relay_log.harvest_bytes_written(&rli->log_space_total); } + else if (mi->gtid_reconnect_event_skip_count == 0) + { + /* + Add a fake rotate event so that SQL thread can see the old-style + position where we re-connected in the middle of a GTID event group. + */ + Rotate_log_event fake_rev(mi->master_log_name, 0, mi->master_log_pos, 0); + fake_rev.server_id= mi->master_id; + if (rli->relay_log.append_no_lock(&fake_rev)) + error= ER_SLAVE_RELAY_LOG_WRITE_FAILURE; + else + rli->relay_log.harvest_bytes_written(&rli->log_space_total); + } } else if ((s_id == global_system_variables.server_id && @@ -5419,6 +5437,26 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len) } mysql_mutex_unlock(log_lock); + if (!error && + mi->using_gtid != Master_info::USE_GTID_NO && + mi->events_queued_since_last_gtid > 0 && + ( (mi->last_queued_gtid_standalone && + !Log_event::is_part_of_group((Log_event_type)(uchar) + buf[EVENT_TYPE_OFFSET])) || + (!mi->last_queued_gtid_standalone && + ((uchar)buf[EVENT_TYPE_OFFSET] == XID_EVENT || + ((uchar)buf[EVENT_TYPE_OFFSET] == QUERY_EVENT && + Query_log_event::peek_is_commit_rollback(buf, event_len, + checksum_alg)))))) + { + /* + The whole of the current event group is queued. So in case of + reconnect we can start from after the current GTID. + */ + mi->gtid_current_pos.update(&mi->last_queued_gtid); + mi->events_queued_since_last_gtid= 0; + } + skip_relay_logging: err: diff --git a/sql/spatial.cc b/sql/spatial.cc index 32a2012a49d..b82e6977f8a 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -480,7 +480,7 @@ bool Gis_point::init_from_wkt(Gis_read_stream *trs, String *wkb) { double x, y; if (trs->get_next_number(&x) || trs->get_next_number(&y) || - wkb->reserve(POINT_DATA_SIZE)) + wkb->reserve(POINT_DATA_SIZE, 512)) return 1; wkb->q_append(x); wkb->q_append(y); @@ -793,7 +793,7 @@ int Gis_line_string::store_shapes(Gcalc_shape_transporter *trn) const return 1; n_points= uint4korr(data); data+= 4; - if (n_points < 1 || no_data(data, POINT_DATA_SIZE * n_points)) + if (n_points < 1 || not_enough_points(data, n_points)) return 1; trn->start_line(); @@ -1230,7 +1230,7 @@ int Gis_polygon::store_shapes(Gcalc_shape_transporter *trn) const return 1; n_points= uint4korr(data); data+= 4; - if (!n_points || no_data(data, POINT_DATA_SIZE * n_points)) + if (!n_points || not_enough_points(data, n_points)) return 1; trn->start_ring(); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 878d4c1e619..e4700507886 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -8236,7 +8236,6 @@ int setup_conds(THD *thd, TABLE_LIST *tables, List<TABLE_LIST> &leaves, embedded->on_expr->fix_fields(thd, &embedded->on_expr)) || embedded->on_expr->check_cols(1)) goto err_no_arena; - select_lex->cond_count++; } /* If it's a semi-join nest, fix its "left expression", as it is used by diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 9f507df3767..86587280d03 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -395,8 +395,6 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived) if (dt_select->options & OPTION_SCHEMA_TABLE) parent_lex->options |= OPTION_SCHEMA_TABLE; - parent_lex->cond_count+= dt_select->cond_count; - if (!derived->get_unit()->prepared) { dt_select->leaf_tables.empty(); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index da4ed52eab8..9d17a0b9021 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2005,9 +2005,10 @@ int JOIN::init_execution() JOIN_TAB *last_join_tab= join_tab + top_join_tab_count - 1; do { - if (used_tables & last_join_tab->table->map) + if (used_tables & last_join_tab->table->map || + last_join_tab->use_join_cache) break; - last_join_tab->not_used_in_distinct=1; + last_join_tab->shortcut_for_distinct= true; } while (last_join_tab-- != join_tab); /* Optimize "select distinct b from t1 order by key_part_1 limit #" */ if (order && skip_sort_order) @@ -4976,6 +4977,33 @@ static void add_key_fields_for_nj(JOIN *join, TABLE_LIST *nested_join_table, } +void count_cond_for_nj(SELECT_LEX *sel, TABLE_LIST *nested_join_table) +{ + List_iterator<TABLE_LIST> li(nested_join_table->nested_join->join_list); + List_iterator<TABLE_LIST> li2(nested_join_table->nested_join->join_list); + bool have_another = FALSE; + TABLE_LIST *table; + + while ((table= li++) || (have_another && (li=li2, have_another=FALSE, + (table= li++)))) + if (table->nested_join) + { + if (!table->on_expr) + { + /* It's a semi-join nest. Walk into it as if it wasn't a nest */ + have_another= TRUE; + li2= li; + li= List_iterator<TABLE_LIST>(table->nested_join->join_list); + } + else + count_cond_for_nj(sel, table); + } + if (nested_join_table->on_expr) + nested_join_table->on_expr->walk(&Item::count_sargable_conds, + 0, (uchar*) sel); + +} + /** Update keyuse array with all possible keys we can use to fetch rows. @@ -5006,6 +5034,27 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, KEY_FIELD *key_fields, *end, *field; uint sz; uint m= MY_MAX(select_lex->max_equal_elems,1); + + SELECT_LEX *sel=thd->lex->current_select; + sel->cond_count= 0; + sel->between_count= 0; + if (cond) + cond->walk(&Item::count_sargable_conds, 0, (uchar*) sel); + for (i=0 ; i < tables ; i++) + { + if (*join_tab[i].on_expr_ref) + (*join_tab[i].on_expr_ref)->walk(&Item::count_sargable_conds, + 0, (uchar*) sel); + } + { + List_iterator<TABLE_LIST> li(*join_tab->join->join_list); + TABLE_LIST *table; + while ((table= li++)) + { + if (table->nested_join) + count_cond_for_nj(sel, table); + } + } /* We use the same piece of memory to store both KEY_FIELD @@ -5029,8 +5078,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, substitutions. */ sz= MY_MAX(sizeof(KEY_FIELD),sizeof(SARGABLE_PARAM))* - (((thd->lex->current_select->cond_count+1)*2 + - thd->lex->current_select->between_count)*m+1); + ((sel->cond_count*2 + sel->between_count)*m+1); if (!(key_fields=(KEY_FIELD*) thd->alloc(sz))) return TRUE; /* purecov: inspected */ and_level= 0; @@ -8658,6 +8706,7 @@ JOIN::make_simple_join(JOIN *parent, TABLE *temp_table) join_tab->keys.init(); join_tab->keys.set_all(); /* test everything in quick */ join_tab->ref.key = -1; + join_tab->shortcut_for_distinct= false; join_tab->read_first_record= join_init_read_record; join_tab->join= this; join_tab->ref.key_parts= 0; @@ -12011,13 +12060,10 @@ static bool check_row_equality(THD *thd, Item *left_row, Item_row *right_row, (Item_row *) left_item, (Item_row *) right_item, cond_equal, eq_list); - if (!is_converted) - thd->lex->current_select->cond_count++; } else { is_converted= check_simple_equality(left_item, right_item, 0, cond_equal); - thd->lex->current_select->cond_count++; } if (!is_converted) @@ -12076,7 +12122,6 @@ static bool check_equality(THD *thd, Item *item, COND_EQUAL *cond_equal, if (left_item->type() == Item::ROW_ITEM && right_item->type() == Item::ROW_ITEM) { - thd->lex->current_select->cond_count--; return check_row_equality(thd, (Item_row *) left_item, (Item_row *) right_item, @@ -17181,7 +17226,7 @@ static enum_nested_loop_state evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, int error) { - bool not_used_in_distinct=join_tab->not_used_in_distinct; + bool shortcut_for_distinct= join_tab->shortcut_for_distinct; ha_rows found_records=join->found_records; COND *select_cond= join_tab->select_cond; bool select_cond_result= TRUE; @@ -17346,7 +17391,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, was not in the field list; In this case we can abort if we found a row, as no new rows can be added to the result. */ - if (not_used_in_distinct && found_records != join->found_records) + if (shortcut_for_distinct && found_records != join->found_records) DBUG_RETURN(NESTED_LOOP_NO_MORE_ROWS); } else diff --git a/sql/sql_select.h b/sql/sql_select.h index 265b7716a36..3353b3749e4 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -310,8 +310,9 @@ typedef struct st_join_table { uint used_null_fields; uint used_uneven_bit_fields; enum join_type type; - bool cached_eq_ref_table,eq_ref_table,not_used_in_distinct; - bool sorted; + bool cached_eq_ref_table,eq_ref_table; + bool shortcut_for_distinct; + bool sorted; /* If it's not 0 the number stored this field indicates that the index scan has been chosen to access the table data and we expect to scan diff --git a/sql/sql_string.h b/sql/sql_string.h index 352dfbe9fa3..14509218ab5 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -164,6 +164,11 @@ public: LEX_STRING lex_string = { (char*) ptr(), length() }; return lex_string; } + LEX_CSTRING lex_cstring() const + { + LEX_CSTRING lex_cstring = { ptr(), length() }; + return lex_cstring; + } void set(String &str,uint32 offset,uint32 arg_length) { |