summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mnogosearch.org>2013-10-15 10:26:08 +0400
committerAlexander Barkov <bar@mnogosearch.org>2013-10-15 10:26:08 +0400
commita9240dce9e2f32941611b4f1a52e3b30a1508fc2 (patch)
treeab7a7ec71341e29676d9a6bb039aeface4f88ce6 /sql
parent2c0a073970cf5f1dc679b34bb13e7fc55109dfd0 (diff)
parenteb2c6f451392396ef2ca74f1dba761fc4459d171 (diff)
downloadmariadb-git-a9240dce9e2f32941611b4f1a52e3b30a1508fc2.tar.gz
Merge 10.0-base -> 10.0
Diffstat (limited to 'sql')
-rw-r--r--sql/CMakeLists.txt5
-rw-r--r--sql/item.cc10
-rw-r--r--sql/item.h1
-rw-r--r--sql/item_cmpfunc.cc248
-rw-r--r--sql/item_cmpfunc.h141
-rw-r--r--sql/item_create.cc69
-rw-r--r--sql/item_func.cc10
-rw-r--r--sql/item_func.h17
-rw-r--r--sql/item_strfunc.cc181
-rw-r--r--sql/item_strfunc.h43
-rw-r--r--sql/mysqld.cc65
-rw-r--r--sql/rpl_mi.h2
-rw-r--r--sql/slave.cc42
-rw-r--r--sql/spatial.cc6
-rw-r--r--sql/sql_base.cc1
-rw-r--r--sql/sql_derived.cc2
-rw-r--r--sql/sql_select.cc65
-rw-r--r--sql/sql_select.h5
-rw-r--r--sql/sql_string.h5
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, &gtid_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)
{