summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2014-08-07 18:06:56 +0200
committerSergei Golubchik <sergii@pisem.net>2014-08-07 18:06:56 +0200
commit6fb17a06016506498f4de75ff754f500f9f674f1 (patch)
treed03c86959f150edc0f6f27ca2c06ccbc0e6e5bf0 /sql
parent2023fac28130d7d3f7d6776332239c62c3890195 (diff)
parenta4ab2431a20f6e2198d980f8e84fa7118515ca3b (diff)
downloadmariadb-git-6fb17a06016506498f4de75ff754f500f9f674f1.tar.gz
5.5.39 merge
Diffstat (limited to 'sql')
-rw-r--r--sql/field.h23
-rw-r--r--sql/filesort.cc3
-rw-r--r--sql/handler.cc12
-rw-r--r--sql/item.cc2
-rw-r--r--sql/item.h38
-rw-r--r--sql/item_func.cc93
-rw-r--r--sql/item_func.h17
-rw-r--r--sql/item_strfunc.cc104
-rw-r--r--sql/item_strfunc.h15
-rw-r--r--sql/item_subselect.cc5
-rw-r--r--sql/item_timefunc.h10
-rw-r--r--sql/log.cc9
-rw-r--r--sql/log.h9
-rw-r--r--sql/log_event.cc6
-rw-r--r--sql/mysqld.cc7
-rw-r--r--sql/opt_range.cc279
-rw-r--r--sql/opt_range.h15
-rw-r--r--sql/replication.h14
-rw-r--r--sql/rpl_handler.cc79
-rw-r--r--sql/rpl_handler.h5
-rw-r--r--sql/scheduler.cc4
-rw-r--r--sql/slave.cc39
-rw-r--r--sql/sql_cache.cc4
-rw-r--r--sql/sql_class.cc2
-rw-r--r--sql/sql_delete.cc3
-rw-r--r--sql/sql_derived.cc6
-rw-r--r--sql/sql_insert.cc2
-rw-r--r--sql/sql_lex.cc21
-rw-r--r--sql/sql_lex.h6
-rw-r--r--sql/sql_parse.cc4
-rw-r--r--sql/sql_partition.cc43
-rw-r--r--sql/sql_plugin.cc2
-rw-r--r--sql/sql_repl.cc2
-rw-r--r--sql/sql_select.cc61
-rw-r--r--sql/sql_select.h4
-rw-r--r--sql/sql_show.cc5
-rw-r--r--sql/sql_table.cc64
-rw-r--r--sql/sql_table.h3
-rw-r--r--sql/sql_union.cc3
-rw-r--r--sql/sql_view.cc7
-rw-r--r--sql/sql_yacc.yy5
-rw-r--r--sql/sys_vars.cc9
-rw-r--r--sql/table.cc27
43 files changed, 666 insertions, 405 deletions
diff --git a/sql/field.h b/sql/field.h
index b5f332f5edc..06e7429c812 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -183,6 +183,29 @@ inline bool is_temporal_type(enum_field_types type)
return mysql_type_to_time_type(type) != MYSQL_TIMESTAMP_ERROR;
}
+
+/**
+ Tests if field type is temporal and has time part,
+ i.e. represents TIME, DATETIME or TIMESTAMP types in SQL.
+
+ @param type Field type, as returned by field->type().
+ @retval true If field type is temporal type with time part.
+ @retval false If field type is not temporal type with time part.
+*/
+inline bool is_temporal_type_with_time(enum_field_types type)
+{
+ switch (type)
+ {
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_TIMESTAMP:
+ return true;
+ default:
+ return false;
+ }
+}
+
+
/*
Virtual_column_info is the class to contain additional
characteristics that is specific for a virtual/computed
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 737165fc6d1..23cfd6a1817 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -721,6 +721,9 @@ static ha_rows find_all_keys(Sort_param *param, SQL_SELECT *select,
/* Temporary set for register_used_fields and register_field_in_read_map */
sort_form->read_set= &sort_form->tmp_set;
register_used_fields(param);
+ if (quick_select)
+ select->quick->add_used_key_part_to_set(sort_form->read_set);
+
Item *sort_cond= !select ?
0 : !select->pre_idx_push_select_cond ?
select->cond : select->pre_idx_push_select_cond;
diff --git a/sql/handler.cc b/sql/handler.cc
index 638723306fb..ff33243ebc9 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -588,7 +588,19 @@ int ha_initialize_handlerton(st_plugin_int *plugin)
savepoint_alloc_size+= tmp;
hton2plugin[hton->slot]=plugin;
if (hton->prepare)
+ {
total_ha_2pc++;
+ if (tc_log && tc_log != get_tc_log_implementation())
+ {
+ total_ha_2pc--;
+ hton->prepare= 0;
+ push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_UNKNOWN_ERROR,
+ "Cannot enable tc-log at run-time. "
+ "XA features of %s are disabled",
+ plugin->name.str);
+ }
+ }
break;
}
/* fall through */
diff --git a/sql/item.cc b/sql/item.cc
index 95df347f71a..107468030bb 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -2124,7 +2124,7 @@ bool agg_item_collations(DTCollation &c, const char *fname,
bool unknown_cs= 0;
c.set(av[0]->collation);
- for (i= 1, arg= &av[item_sep]; i < count; i++, arg++)
+ for (i= 1, arg= &av[item_sep]; i < count; i++, arg+= item_sep)
{
if (c.aggregate((*arg)->collation, flags))
{
diff --git a/sql/item.h b/sql/item.h
index 29e727b8d5f..00c1468bb48 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1034,9 +1034,47 @@ public:
virtual cond_result eq_cmp_result() const { return COND_OK; }
inline uint float_length(uint decimals_par) const
{ return decimals != NOT_FIXED_DEC ? (DBL_DIG+2+decimals_par) : DBL_DIG+8;}
+ /* Returns total number of decimal digits */
virtual uint decimal_precision() const;
+ /* Returns the number of integer part digits only */
inline int decimal_int_part() const
{ return my_decimal_int_part(decimal_precision(), decimals); }
+ /*
+ Returns the number of fractional digits only.
+ NOT_FIXED_DEC is replaced to the maximum possible number
+ of fractional digits, taking into account the data type.
+ */
+ uint decimal_scale() const
+ {
+ return decimals < NOT_FIXED_DEC ? decimals :
+ is_temporal_type_with_time(field_type()) ?
+ TIME_SECOND_PART_DIGITS :
+ MY_MIN(max_length, DECIMAL_MAX_SCALE);
+ }
+ /*
+ Returns how many digits a divisor adds into a division result.
+ This is important when the integer part of the divisor can be 0.
+ In this example:
+ SELECT 1 / 0.000001; -> 1000000.0000
+ the divisor adds 5 digits into the result precision.
+
+ Currently this method only replaces NOT_FIXED_DEC to
+ TIME_SECOND_PART_DIGITS for temporal data types.
+ This method can be made virtual, to create more efficient (smaller)
+ data types for division results.
+ For example, in
+ SELECT 1/1.000001;
+ the divisor could provide no additional precision into the result,
+ so could any other items that are know to return a result
+ with non-zero integer part.
+ */
+ uint divisor_precision_increment() const
+ {
+ return decimals < NOT_FIXED_DEC ? decimals :
+ is_temporal_type_with_time(field_type()) ?
+ TIME_SECOND_PART_DIGITS :
+ decimals;
+ }
/**
TIME or DATETIME precision of the item: 0..6
*/
diff --git a/sql/item_func.cc b/sql/item_func.cc
index ccb7ec56021..51a85e71f20 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -593,7 +593,7 @@ my_decimal *Item_real_func::val_decimal(my_decimal *decimal_value)
}
-void Item_func::fix_num_length_and_dec()
+void Item_udf_func::fix_num_length_and_dec()
{
uint fl_length= 0;
decimals=0;
@@ -611,11 +611,6 @@ void Item_func::fix_num_length_and_dec()
}
-void Item_func_numhybrid::fix_num_length_and_dec()
-{}
-
-
-
/**
Count max_length and decimals for temporal functions.
@@ -803,9 +798,9 @@ bool Item_func_connection_id::fix_fields(THD *thd, Item **ref)
function of two arguments.
*/
-void Item_num_op::find_num_type(void)
+void Item_num_op::fix_length_and_dec(void)
{
- DBUG_ENTER("Item_num_op::find_num_type");
+ DBUG_ENTER("Item_num_op::fix_length_and_dec");
DBUG_PRINT("info", ("name %s", func_name()));
DBUG_ASSERT(arg_count == 2);
Item_result r0= args[0]->cast_to_int_type();
@@ -849,22 +844,26 @@ void Item_num_op::find_num_type(void)
type depends only on the first argument)
*/
-void Item_func_num1::find_num_type()
+void Item_func_num1::fix_length_and_dec()
{
- DBUG_ENTER("Item_func_num1::find_num_type");
+ DBUG_ENTER("Item_func_num1::fix_length_and_dec");
DBUG_PRINT("info", ("name %s", func_name()));
switch (cached_result_type= args[0]->cast_to_int_type()) {
case INT_RESULT:
+ max_length= args[0]->max_length;
unsigned_flag= args[0]->unsigned_flag;
break;
case STRING_RESULT:
case REAL_RESULT:
cached_result_type= REAL_RESULT;
+ decimals= args[0]->decimals; // Preserve NOT_FIXED_DEC
max_length= float_length(decimals);
break;
case TIME_RESULT:
cached_result_type= DECIMAL_RESULT;
case DECIMAL_RESULT:
+ decimals= args[0]->decimal_scale(); // Do not preserve NOT_FIXED_DEC
+ max_length= args[0]->max_length;
break;
case ROW_RESULT:
case IMPOSSIBLE_RESULT:
@@ -879,20 +878,6 @@ void Item_func_num1::find_num_type()
}
-void Item_func_num1::fix_num_length_and_dec()
-{
- decimals= args[0]->decimals;
- max_length= args[0]->max_length;
-}
-
-
-void Item_func_numhybrid::fix_length_and_dec()
-{
- fix_num_length_and_dec();
- find_num_type();
-}
-
-
String *Item_func_hybrid_result_type::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
@@ -1537,11 +1522,14 @@ my_decimal *Item_func_plus::decimal_op(my_decimal *decimal_value)
*/
void Item_func_additive_op::result_precision()
{
- decimals= MY_MAX(args[0]->decimals, args[1]->decimals);
- int arg1_int= args[0]->decimal_precision() - args[0]->decimals;
- int arg2_int= args[1]->decimal_precision() - args[1]->decimals;
+ decimals= MY_MAX(args[0]->decimal_scale(), args[1]->decimal_scale());
+ int arg1_int= args[0]->decimal_precision() - args[0]->decimal_scale();
+ int arg2_int= args[1]->decimal_precision() - args[1]->decimal_scale();
int precision= MY_MAX(arg1_int, arg2_int) + 1 + decimals;
+ DBUG_ASSERT(arg1_int >= 0);
+ DBUG_ASSERT(arg2_int >= 0);
+
/* Integer operations keep unsigned_flag if one of arguments is unsigned */
if (result_type() == INT_RESULT)
unsigned_flag= args[0]->unsigned_flag | args[1]->unsigned_flag;
@@ -1778,7 +1766,8 @@ void Item_func_mul::result_precision()
unsigned_flag= args[0]->unsigned_flag | args[1]->unsigned_flag;
else
unsigned_flag= args[0]->unsigned_flag & args[1]->unsigned_flag;
- decimals= MY_MIN(args[0]->decimals + args[1]->decimals, DECIMAL_MAX_SCALE);
+ decimals= MY_MIN(args[0]->decimal_scale() + args[1]->decimal_scale(),
+ DECIMAL_MAX_SCALE);
uint est_prec = args[0]->decimal_precision() + args[1]->decimal_precision();
uint precision= MY_MIN(est_prec, DECIMAL_MAX_PRECISION);
max_length= my_decimal_precision_to_length_no_truncation(precision, decimals,
@@ -1832,8 +1821,20 @@ my_decimal *Item_func_div::decimal_op(my_decimal *decimal_value)
void Item_func_div::result_precision()
{
+ /*
+ We need to add args[1]->divisor_precision_increment(),
+ to properly handle the cases like this:
+ SELECT 5.05 / 0.014; -> 360.714286
+ i.e. when the divisor has a zero integer part
+ and non-zero digits appear only after the decimal point.
+ Precision in this example is calculated as
+ args[0]->decimal_precision() + // 3
+ args[1]->divisor_precision_increment() + // 3
+ prec_increment // 4
+ which gives 10 decimals digits.
+ */
uint precision=MY_MIN(args[0]->decimal_precision() +
- args[1]->decimals + prec_increment,
+ args[1]->divisor_precision_increment() + prec_increment,
DECIMAL_MAX_PRECISION);
/* Integer operations keep unsigned_flag if one of arguments is unsigned */
@@ -1841,7 +1842,7 @@ void Item_func_div::result_precision()
unsigned_flag= args[0]->unsigned_flag | args[1]->unsigned_flag;
else
unsigned_flag= args[0]->unsigned_flag & args[1]->unsigned_flag;
- decimals= MY_MIN(args[0]->decimals + prec_increment, DECIMAL_MAX_SCALE);
+ decimals= MY_MIN(args[0]->decimal_scale() + prec_increment, DECIMAL_MAX_SCALE);
max_length= my_decimal_precision_to_length_no_truncation(precision, decimals,
unsigned_flag);
}
@@ -2047,7 +2048,7 @@ my_decimal *Item_func_mod::decimal_op(my_decimal *decimal_value)
void Item_func_mod::result_precision()
{
- decimals= MY_MAX(args[0]->decimals, args[1]->decimals);
+ decimals= MY_MAX(args[0]->decimal_scale(), args[1]->decimal_scale());
max_length= MY_MAX(args[0]->max_length, args[1]->max_length);
}
@@ -2103,18 +2104,12 @@ my_decimal *Item_func_neg::decimal_op(my_decimal *decimal_value)
}
-void Item_func_neg::fix_num_length_and_dec()
-{
- decimals= args[0]->decimals;
- /* 1 add because sign can appear */
- max_length= args[0]->max_length + 1;
-}
-
-
void Item_func_neg::fix_length_and_dec()
{
DBUG_ENTER("Item_func_neg::fix_length_and_dec");
Item_func_num1::fix_length_and_dec();
+ /* 1 add because sign can appear */
+ max_length= args[0]->max_length + 1;
/*
If this is in integer context keep the context as integer if possible
@@ -2421,8 +2416,12 @@ void Item_func_integer::fix_length_and_dec()
decimals=0;
}
-void Item_func_int_val::fix_num_length_and_dec()
+
+void Item_func_int_val::fix_length_and_dec()
{
+ DBUG_ENTER("Item_func_int_val::fix_length_and_dec");
+ DBUG_PRINT("info", ("name %s", func_name()));
+
ulonglong tmp_max_length= (ulonglong ) args[0]->max_length -
(args[0]->decimals ? args[0]->decimals + 1 : 0) + 2;
max_length= tmp_max_length > (ulonglong) 4294967295U ?
@@ -2430,13 +2429,7 @@ void Item_func_int_val::fix_num_length_and_dec()
uint tmp= float_length(decimals);
set_if_smaller(max_length,tmp);
decimals= 0;
-}
-
-void Item_func_int_val::find_num_type()
-{
- DBUG_ENTER("Item_func_int_val::find_num_type");
- DBUG_PRINT("info", ("name %s", func_name()));
switch (cached_result_type= args[0]->cast_to_int_type())
{
case STRING_RESULT:
@@ -2960,7 +2953,7 @@ bool Item_func_min_max::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
{
ltime->time_type= MYSQL_TIMESTAMP_TIME;
ltime->hour+= (ltime->month * 32 + ltime->day) * 24;
- ltime->month= ltime->day= 0;
+ ltime->year= ltime->month= ltime->day= 0;
if (adjust_time_range_with_warn(ltime,
std::min<uint>(decimals, TIME_SECOND_PART_DIGITS)))
return (null_value= true);
@@ -3894,12 +3887,6 @@ String *Item_func_udf_decimal::val_str(String *str)
}
-void Item_func_udf_decimal::fix_length_and_dec()
-{
- fix_num_length_and_dec();
-}
-
-
/* Default max_length is max argument length */
void Item_func_udf_str::fix_length_and_dec()
diff --git a/sql/item_func.h b/sql/item_func.h
index 1696898812d..18265f672dd 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -154,7 +154,6 @@ public:
virtual void print(String *str, enum_query_type query_type);
void print_op(String *str, enum_query_type query_type);
void print_args(String *str, uint from, enum_query_type query_type);
- virtual void fix_num_length_and_dec();
void count_only_length(Item **item, uint nitems);
void count_real_length();
void count_decimal_length();
@@ -541,9 +540,6 @@ public:
Item_func_numhybrid(List<Item> &list)
:Item_func_hybrid_result_type(list)
{ }
- void fix_length_and_dec();
- void fix_num_length_and_dec();
- virtual void find_num_type()= 0; /* To be called from fix_length_and_dec */
String *str_op(String *str) { DBUG_ASSERT(0); return 0; }
bool date_op(MYSQL_TIME *ltime, uint fuzzydate) { DBUG_ASSERT(0); return true; }
};
@@ -555,9 +551,7 @@ class Item_func_num1: public Item_func_numhybrid
public:
Item_func_num1(Item *a) :Item_func_numhybrid(a) {}
Item_func_num1(Item *a, Item *b) :Item_func_numhybrid(a, b) {}
-
- void fix_num_length_and_dec();
- void find_num_type();
+ void fix_length_and_dec();
};
@@ -573,7 +567,7 @@ class Item_num_op :public Item_func_numhybrid
print_op(str, query_type);
}
- void find_num_type();
+ void fix_length_and_dec();
};
@@ -795,7 +789,6 @@ public:
const char *func_name() const { return "-"; }
enum Functype functype() const { return NEG_FUNC; }
void fix_length_and_dec();
- void fix_num_length_and_dec();
uint decimal_precision() const { return args[0]->decimal_precision(); }
bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
bool check_vcol_func_processor(uchar *int_arg) { return FALSE;}
@@ -962,8 +955,7 @@ class Item_func_int_val :public Item_func_num1
{
public:
Item_func_int_val(Item *a) :Item_func_num1(a) {}
- void fix_num_length_and_dec();
- void find_num_type();
+ void fix_length_and_dec();
};
@@ -1376,6 +1368,7 @@ public:
fixed= 1;
return res;
}
+ void fix_num_length_and_dec();
void update_used_tables()
{
/*
@@ -1489,7 +1482,7 @@ public:
my_decimal *val_decimal(my_decimal *);
String *val_str(String *str);
enum Item_result result_type () const { return DECIMAL_RESULT; }
- void fix_length_and_dec();
+ void fix_length_and_dec() { fix_num_length_and_dec(); }
};
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index bee1b600d8f..bb999f132c4 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -180,16 +180,27 @@ String *Item_func_md5::val_str_ascii(String *str)
}
+/*
+ The MD5()/SHA() functions treat their parameter as being a case sensitive.
+ Thus we set binary collation on it so different instances of MD5() will be
+ compared properly.
+*/
+static CHARSET_INFO *get_checksum_charset(const char *csname)
+{
+ CHARSET_INFO *cs= get_charset_by_csname(csname, MY_CS_BINSORT, MYF(0));
+ if (!cs)
+ {
+ // Charset has no binary collation: use my_charset_bin.
+ cs= &my_charset_bin;
+ }
+ return cs;
+}
+
+
void Item_func_md5::fix_length_and_dec()
{
- /*
- The MD5() function treats its parameter as being a case sensitive. Thus
- we set binary collation on it so different instances of MD5() will be
- compared properly.
- */
- args[0]->collation.set(
- get_charset_by_csname(args[0]->collation.collation->csname,
- MY_CS_BINSORT,MYF(0)), DERIVATION_COERCIBLE);
+ CHARSET_INFO *cs= get_checksum_charset(args[0]->collation.collation->csname);
+ args[0]->collation.set(cs, DERIVATION_COERCIBLE);
fix_length_and_charset(32, default_charset());
}
@@ -219,14 +230,8 @@ String *Item_func_sha::val_str_ascii(String *str)
void Item_func_sha::fix_length_and_dec()
{
- /*
- The SHA() function treats its parameter as being a case sensitive. Thus
- we set binary collation on it so different instances of MD5() will be
- compared properly.
- */
- args[0]->collation.set(
- get_charset_by_csname(args[0]->collation.collation->csname,
- MY_CS_BINSORT,MYF(0)), DERIVATION_COERCIBLE);
+ CHARSET_INFO *cs= get_checksum_charset(args[0]->collation.collation->csname);
+ args[0]->collation.set(cs, DERIVATION_COERCIBLE);
// size of hex representation of hash
fix_length_and_charset(SHA1_HASH_SIZE * 2, default_charset());
}
@@ -349,18 +354,9 @@ void Item_func_sha2::fix_length_and_dec()
ER(ER_WRONG_PARAMETERS_TO_NATIVE_FCT), "sha2");
}
- /*
- The SHA2() function treats its parameter as being a case sensitive.
- Thus we set binary collation on it so different instances of SHA2()
- will be compared properly.
- */
+ CHARSET_INFO *cs= get_checksum_charset(args[0]->collation.collation->csname);
+ args[0]->collation.set(cs, DERIVATION_COERCIBLE);
- args[0]->collation.set(
- get_charset_by_csname(
- args[0]->collation.collation->csname,
- MY_CS_BINSORT,
- MYF(0)),
- DERIVATION_COERCIBLE);
#else
push_warning_printf(current_thd,
Sql_condition::WARN_LEVEL_WARN,
@@ -1966,7 +1962,7 @@ String *Item_func_ltrim::val_str(String *str)
if ((remove_length= remove_str->length()) == 0 ||
remove_length > res->length())
- return res;
+ return non_trimmed_value(res);
ptr= (char*) res->ptr();
end= ptr+res->length();
@@ -1985,9 +1981,8 @@ String *Item_func_ltrim::val_str(String *str)
end+=remove_length;
}
if (ptr == res->ptr())
- return res;
- tmp_value.set(*res,(uint) (ptr - res->ptr()),(uint) (end-ptr));
- return &tmp_value;
+ return non_trimmed_value(res);
+ return trimmed_value(res, (uint32) (ptr - res->ptr()), (uint32) (end - ptr));
}
@@ -2013,7 +2008,7 @@ String *Item_func_rtrim::val_str(String *str)
if ((remove_length= remove_str->length()) == 0 ||
remove_length > res->length())
- return res;
+ return non_trimmed_value(res);
ptr= (char*) res->ptr();
end= ptr+res->length();
@@ -2025,11 +2020,11 @@ String *Item_func_rtrim::val_str(String *str)
{
char chr=(*remove_str)[0];
#ifdef USE_MB
- if (use_mb(res->charset()))
+ if (use_mb(collation.collation))
{
while (ptr < end)
{
- if ((l=my_ismbchar(res->charset(), ptr,end))) ptr+=l,p=ptr;
+ if ((l= my_ismbchar(collation.collation, ptr, end))) ptr+= l, p=ptr;
else ++ptr;
}
ptr=p;
@@ -2042,12 +2037,12 @@ String *Item_func_rtrim::val_str(String *str)
{
const char *r_ptr=remove_str->ptr();
#ifdef USE_MB
- if (use_mb(res->charset()))
+ if (use_mb(collation.collation))
{
loop:
while (ptr + remove_length < end)
{
- if ((l=my_ismbchar(res->charset(), ptr,end))) ptr+=l;
+ if ((l= my_ismbchar(collation.collation, ptr, end))) ptr+= l;
else ++ptr;
}
if (ptr + remove_length == end && !memcmp(ptr,r_ptr,remove_length))
@@ -2066,9 +2061,8 @@ String *Item_func_rtrim::val_str(String *str)
}
}
if (end == res->ptr()+res->length())
- return res;
- tmp_value.set(*res,0,(uint) (end-res->ptr()));
- return &tmp_value;
+ return non_trimmed_value(res);
+ return trimmed_value(res, 0, (uint32) (end - res->ptr()));
}
@@ -2095,37 +2089,22 @@ String *Item_func_trim::val_str(String *str)
if ((remove_length= remove_str->length()) == 0 ||
remove_length > res->length())
- return res;
+ return non_trimmed_value(res);
ptr= (char*) res->ptr();
end= ptr+res->length();
r_ptr= remove_str->ptr();
+ while (ptr+remove_length <= end && !memcmp(ptr,r_ptr,remove_length))
+ ptr+=remove_length;
#ifdef USE_MB
- if (use_mb(res->charset()))
+ if (use_mb(collation.collation))
{
- while (ptr + remove_length <= end)
- {
- uint num_bytes= 0;
- while (num_bytes < remove_length)
- {
- uint len;
- if ((len= my_ismbchar(res->charset(), ptr + num_bytes, end)))
- num_bytes+= len;
- else
- ++num_bytes;
- }
- if (num_bytes != remove_length)
- break;
- if (memcmp(ptr, r_ptr, remove_length))
- break;
- ptr+= remove_length;
- }
char *p=ptr;
register uint32 l;
loop:
while (ptr + remove_length < end)
{
- if ((l= my_ismbchar(res->charset(), ptr,end)))
+ if ((l= my_ismbchar(collation.collation, ptr, end)))
ptr+= l;
else
++ptr;
@@ -2141,16 +2120,13 @@ String *Item_func_trim::val_str(String *str)
else
#endif /* USE_MB */
{
- while (ptr+remove_length <= end && !memcmp(ptr,r_ptr,remove_length))
- ptr+=remove_length;
while (ptr + remove_length <= end &&
!memcmp(end-remove_length,r_ptr,remove_length))
end-=remove_length;
}
if (ptr == res->ptr() && end == ptr+res->length())
- return res;
- tmp_value.set(*res,(uint) (ptr - res->ptr()),(uint) (end-ptr));
- return &tmp_value;
+ return non_trimmed_value(res);
+ return trimmed_value(res, (uint32) (ptr - res->ptr()), (uint32) (end - ptr));
}
void Item_func_trim::fix_length_and_dec()
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index f3d5c064423..4551cc1ab46 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -349,6 +349,21 @@ class Item_func_trim :public Item_str_func
protected:
String tmp_value;
String remove;
+ String *trimmed_value(String *res, uint32 offset, uint32 length)
+ {
+ tmp_value.set(*res, offset, length);
+ /*
+ Make sure to return correct charset and collation:
+ TRIM(0x000000 FROM _ucs2 0x0061)
+ should set charset to "binary" rather than to "ucs2".
+ */
+ tmp_value.set_charset(collation.collation);
+ return &tmp_value;
+ }
+ String *non_trimmed_value(String *res)
+ {
+ return trimmed_value(res, 0, res->length());
+ }
public:
Item_func_trim(Item *a,Item *b) :Item_str_func(a,b) {}
Item_func_trim(Item *a) :Item_str_func(a) {}
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 38bb3121ed8..7db7b014d28 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -3654,8 +3654,9 @@ int subselect_single_select_engine::exec()
pushed down into the subquery. Those optimizations are ref[_or_null]
acceses. Change them to be full table scans.
*/
- for (JOIN_TAB *tab= first_linear_tab(join, WITHOUT_CONST_TABLES); tab;
- tab= next_linear_tab(join, tab, WITH_BUSH_ROOTS))
+ JOIN_TAB *tab;
+ for (tab= first_linear_tab(join, WITH_BUSH_ROOTS, WITHOUT_CONST_TABLES);
+ tab; tab= next_linear_tab(join, tab, WITH_BUSH_ROOTS))
{
if (tab && tab->keyuse)
{
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 29badddad8e..cb8b59501a4 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -413,16 +413,15 @@ protected:
public:
Item_func_seconds_hybrid() :Item_func_numhybrid() {}
Item_func_seconds_hybrid(Item *a) :Item_func_numhybrid(a) {}
- void fix_num_length_and_dec()
+ void fix_length_and_dec()
{
if (arg_count)
decimals= args[0]->temporal_precision(arg0_expected_type());
set_if_smaller(decimals, TIME_SECOND_PART_DIGITS);
max_length=17 + (decimals ? decimals + 1 : 0);
maybe_null= true;
+ cached_result_type= decimals ? DECIMAL_RESULT : INT_RESULT;
}
- void find_num_type()
- { cached_result_type= decimals ? DECIMAL_RESULT : INT_RESULT; }
double real_op() { DBUG_ASSERT(0); return 0; }
String *str_op(String *str) { DBUG_ASSERT(0); return 0; }
bool date_op(MYSQL_TIME *ltime, uint fuzzydate) { DBUG_ASSERT(0); return true; }
@@ -470,11 +469,6 @@ protected:
public:
Item_func_time_to_sec(Item *item) :Item_func_seconds_hybrid(item) {}
const char *func_name() const { return "time_to_sec"; }
- void fix_num_length_and_dec()
- {
- maybe_null= true;
- Item_func_seconds_hybrid::fix_num_length_and_dec();
- }
bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
bool check_vcol_func_processor(uchar *int_arg) { return FALSE;}
bool check_valid_arguments_processor(uchar *int_arg)
diff --git a/sql/log.cc b/sql/log.cc
index 42d0a897eaa..71975cd83b7 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -2369,7 +2369,7 @@ static int find_uniq_filename(char *name)
file_info= dir_info->dir_entry;
for (i= dir_info->number_of_files ; i-- ; file_info++)
{
- if (memcmp(file_info->name, start, length) == 0 &&
+ if (strncmp(file_info->name, start, length) == 0 &&
test_if_number(file_info->name+length, &number,0))
{
set_if_bigger(max_found,(ulong) number);
@@ -2649,9 +2649,10 @@ int MYSQL_LOG::generate_new_name(char *new_name, const char *log_name)
if (DBUG_EVALUATE_IF("binlog_inject_new_name_error", TRUE, FALSE) ||
find_uniq_filename(new_name))
{
- my_printf_error(ER_NO_UNIQUE_LOGFILE, ER(ER_NO_UNIQUE_LOGFILE),
- MYF(ME_FATALERROR), log_name);
- sql_print_error(ER(ER_NO_UNIQUE_LOGFILE), log_name);
+ if (current_thd)
+ my_printf_error(ER_NO_UNIQUE_LOGFILE, ER(ER_NO_UNIQUE_LOGFILE),
+ MYF(ME_FATALERROR), log_name);
+ sql_print_error(ER_DEFAULT(ER_NO_UNIQUE_LOGFILE), log_name);
return 1;
}
}
diff --git a/sql/log.h b/sql/log.h
index 67fcf068ec4..1bf87733ce2 100644
--- a/sql/log.h
+++ b/sql/log.h
@@ -1077,6 +1077,13 @@ end:
DBUG_RETURN(error);
}
-
+static inline TC_LOG *get_tc_log_implementation()
+{
+ if (total_ha_2pc <= 1)
+ return &tc_log_dummy;
+ if (opt_bin_log)
+ return &mysql_bin_log;
+ return &tc_log_mmap;
+}
#endif /* LOG_H */
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 188aa87ae51..20e71a48ed3 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -9009,9 +9009,9 @@ void Execute_load_query_log_event::print(FILE* file,
if (local_fname)
{
my_b_write(&cache, (uchar*) query, fn_pos_start);
- my_b_write_string(&cache, " LOCAL INFILE \'");
- my_b_printf(&cache, "%s", local_fname);
- my_b_write_string(&cache, "\'");
+ my_b_write_string(&cache, " LOCAL INFILE ");
+ pretty_print_str(&cache, local_fname, strlen(local_fname));
+
if (dup_handling == LOAD_DUP_REPLACE)
my_b_write_string(&cache, " REPLACE");
my_b_write_string(&cache, " INTO");
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index a23afb939a3..d751d6b7318 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -4802,6 +4802,8 @@ a file name for --log-bin-index option", opt_binlog_index_name);
if (ha_init_errors())
DBUG_RETURN(1);
+ tc_log= 0; // ha_initialize_handlerton() needs that
+
if (plugin_init(&remaining_argc, remaining_argv,
(opt_noacl ? PLUGIN_INIT_SKIP_PLUGIN_TABLE : 0) |
(opt_abort ? PLUGIN_INIT_SKIP_INITIALIZATION : 0)))
@@ -4937,10 +4939,7 @@ a file name for --log-bin-index option", opt_binlog_index_name);
internal_tmp_table_max_key_segments= myisam_max_key_segments();
#endif
- tc_log= (total_ha_2pc > 1 ? (opt_bin_log ?
- (TC_LOG *) &mysql_bin_log :
- (TC_LOG *) &tc_log_mmap) :
- (TC_LOG *) &tc_log_dummy);
+ tc_log= get_tc_log_implementation();
if (tc_log->open(opt_bin_log ? opt_bin_logname : opt_tc_log_file))
{
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index fc2aa75e604..b38b048c344 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2008, 2013, Monty Program Ab.
+/* Copyright (c) 2000, 2014, Oracle and/or its affiliates.
+ Copyright (c) 2008, 2014, Monty Program Ab.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -359,31 +359,54 @@ public:
elements(1),use_count(1),left(0),right(0),
next_key_part(0), color(BLACK), type(type_arg)
{}
- inline bool is_same(SEL_ARG *arg)
+ /**
+ returns true if a range predicate is equal. Use all_same()
+ to check for equality of all the predicates on this keypart.
+ */
+ inline bool is_same(const SEL_ARG *arg) const
{
if (type != arg->type || part != arg->part)
- return 0;
+ return false;
if (type != KEY_RANGE)
- return 1;
+ return true;
return cmp_min_to_min(arg) == 0 && cmp_max_to_max(arg) == 0;
}
+ /**
+ returns true if all the predicates in the keypart tree are equal
+ */
+ bool all_same(const SEL_ARG *arg) const
+ {
+ if (type != arg->type || part != arg->part)
+ return false;
+ if (type != KEY_RANGE)
+ return true;
+ if (arg == this)
+ return true;
+ const SEL_ARG *cmp_arg= arg->first();
+ const SEL_ARG *cur_arg= first();
+ for (; cur_arg && cmp_arg && cur_arg->is_same(cmp_arg);
+ cur_arg= cur_arg->next, cmp_arg= cmp_arg->next) ;
+ if (cur_arg || cmp_arg)
+ return false;
+ return true;
+ }
inline void merge_flags(SEL_ARG *arg) { maybe_flag|=arg->maybe_flag; }
inline void maybe_smaller() { maybe_flag=1; }
/* Return true iff it's a single-point null interval */
inline bool is_null_interval() { return maybe_null && max_value[0] == 1; }
- inline int cmp_min_to_min(SEL_ARG* arg)
+ inline int cmp_min_to_min(const SEL_ARG* arg) const
{
return sel_cmp(field,min_value, arg->min_value, min_flag, arg->min_flag);
}
- inline int cmp_min_to_max(SEL_ARG* arg)
+ inline int cmp_min_to_max(const SEL_ARG* arg) const
{
return sel_cmp(field,min_value, arg->max_value, min_flag, arg->max_flag);
}
- inline int cmp_max_to_max(SEL_ARG* arg)
+ inline int cmp_max_to_max(const SEL_ARG* arg) const
{
return sel_cmp(field,max_value, arg->max_value, max_flag, arg->max_flag);
}
- inline int cmp_max_to_min(SEL_ARG* arg)
+ inline int cmp_max_to_min(const SEL_ARG* arg) const
{
return sel_cmp(field,max_value, arg->min_value, max_flag, arg->min_flag);
}
@@ -563,6 +586,7 @@ public:
void test_use_count(SEL_ARG *root);
#endif
SEL_ARG *first();
+ const SEL_ARG *first() const;
SEL_ARG *last();
void make_root();
inline bool simple_key()
@@ -652,6 +676,18 @@ public:
SEL_ARG *clone_tree(RANGE_OPT_PARAM *param);
};
+/**
+ Helper function to compare two SEL_ARG's.
+*/
+static bool all_same(const SEL_ARG *sa1, const SEL_ARG *sa2)
+{
+ if (sa1 == NULL && sa2 == NULL)
+ return true;
+ if ((sa1 != NULL && sa2 == NULL) || (sa1 == NULL && sa2 != NULL))
+ return false;
+ return sa1->all_same(sa2);
+}
+
class SEL_IMERGE;
#define CLONE_KEY1_MAYBE 1
@@ -2495,6 +2531,13 @@ SEL_ARG *SEL_ARG::clone(RANGE_OPT_PARAM *param, SEL_ARG *new_parent,
return tmp;
}
+/**
+ This gives the first SEL_ARG in the interval list, and the minimal element
+ in the red-black tree
+
+ @return
+ SEL_ARG first SEL_ARG in the interval list
+*/
SEL_ARG *SEL_ARG::first()
{
SEL_ARG *next_arg=this;
@@ -2505,6 +2548,11 @@ SEL_ARG *SEL_ARG::first()
return next_arg;
}
+const SEL_ARG *SEL_ARG::first() const
+{
+ return const_cast<SEL_ARG*>(this)->first();
+}
+
SEL_ARG *SEL_ARG::last()
{
SEL_ARG *next_arg=this;
@@ -11043,6 +11091,7 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
uint part;
bool create_err= FALSE;
Cost_estimate cost;
+ uint max_used_key_len;
old_root= thd->mem_root;
/* The following call may change thd->mem_root */
@@ -11069,12 +11118,13 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
range->min_length= range->max_length= ref->key_length;
range->min_keypart_map= range->max_keypart_map=
make_prev_keypart_map(ref->key_parts);
- range->flag= (ref->key_length == key_info->key_length ? EQ_RANGE : 0);
+ range->flag= EQ_RANGE;
if (!(quick->key_parts=key_part=(KEY_PART *)
alloc_root(&quick->alloc,sizeof(KEY_PART)*ref->key_parts)))
goto err;
-
+
+ max_used_key_len=0;
for (part=0 ; part < ref->key_parts ;part++,key_part++)
{
key_part->part=part;
@@ -11083,7 +11133,12 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
key_part->store_length= key_info->key_part[part].store_length;
key_part->null_bit= key_info->key_part[part].null_bit;
key_part->flag= (uint8) key_info->key_part[part].key_part_flag;
+
+ max_used_key_len +=key_info->key_part[part].store_length;
}
+
+ quick->max_used_key_length= max_used_key_len;
+
if (insert_dynamic(&quick->ranges,(uchar*)&range))
goto err;
@@ -12334,6 +12389,66 @@ void QUICK_ROR_UNION_SELECT::add_keys_and_lengths(String *key_names,
}
+void QUICK_RANGE_SELECT::add_used_key_part_to_set(MY_BITMAP *col_set)
+{
+ uint key_len;
+ KEY_PART *part= key_parts;
+ for (key_len=0; key_len < max_used_key_length;
+ key_len += (part++)->store_length)
+ {
+ bitmap_set_bit(col_set, part->field->field_index);
+ }
+}
+
+
+void QUICK_GROUP_MIN_MAX_SELECT::add_used_key_part_to_set(MY_BITMAP *col_set)
+{
+ uint key_len;
+ KEY_PART_INFO *part= index_info->key_part;
+ for (key_len=0; key_len < max_used_key_length;
+ key_len += (part++)->store_length)
+ {
+ bitmap_set_bit(col_set, part->field->field_index);
+ }
+}
+
+
+void QUICK_ROR_INTERSECT_SELECT::add_used_key_part_to_set(MY_BITMAP *col_set)
+{
+ List_iterator_fast<QUICK_SELECT_WITH_RECORD> it(quick_selects);
+ QUICK_SELECT_WITH_RECORD *quick;
+ while ((quick= it++))
+ {
+ quick->quick->add_used_key_part_to_set(col_set);
+ }
+}
+
+
+void QUICK_INDEX_SORT_SELECT::add_used_key_part_to_set(MY_BITMAP *col_set)
+{
+ QUICK_RANGE_SELECT *quick;
+ List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
+ while ((quick= it++))
+ {
+ quick->add_used_key_part_to_set(col_set);
+ }
+ if (pk_quick_select)
+ pk_quick_select->add_used_key_part_to_set(col_set);
+}
+
+
+void QUICK_ROR_UNION_SELECT::add_used_key_part_to_set(MY_BITMAP *col_set)
+{
+ QUICK_SELECT_I *quick;
+ List_iterator_fast<QUICK_SELECT_I> it(quick_selects);
+
+ while ((quick= it++))
+ {
+ quick->add_used_key_part_to_set(col_set);
+ }
+}
+
+
/*******************************************************************************
* Implementation of QUICK_GROUP_MIN_MAX_SELECT
*******************************************************************************/
@@ -12341,6 +12456,8 @@ void QUICK_ROR_UNION_SELECT::add_keys_and_lengths(String *key_names,
static inline uint get_field_keypart(KEY *index, Field *field);
static inline SEL_ARG * get_index_range_tree(uint index, SEL_TREE* range_tree,
PARAM *param, uint *param_idx);
+static bool get_sel_arg_for_keypart(Field *field, SEL_ARG *index_range_tree,
+ SEL_ARG **cur_range);
static bool get_constant_key_infix(KEY *index_info, SEL_ARG *index_range_tree,
KEY_PART_INFO *first_non_group_part,
KEY_PART_INFO *min_max_arg_part,
@@ -12406,6 +12523,16 @@ cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts,
never stored after a unique key lookup in the clustered index and
furhter index_next/prev calls can not be used. So loose index scan
optimization can not be used in this case.
+ SA7. If Q has both AGG_FUNC(DISTINCT ...) and MIN/MAX() functions then this
+ access method is not used.
+ For above queries MIN/MAX() aggregation has to be done at
+ nested_loops_join (end_send_group). But with current design MIN/MAX()
+ is always set as part of loose index scan. Because of this mismatch
+ MIN() and MAX() values will be set incorrectly. For such queries to
+ work we need a new interface for loose index scan. This new interface
+ should only fetch records with min and max values and let
+ end_send_group to do aggregation. Until then do not use
+ loose_index_scan.
GA1. If Q has a GROUP BY clause, then GA is a prefix of I. That is, if
G_i = A_j => i = j.
GA2. If Q has a DISTINCT clause, then there is a permutation of SA that
@@ -12437,6 +12564,8 @@ cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts,
above tests. By transitivity then it also follows that each WA_i
participates in the index I (if this was already tested for GA, NGA
and C).
+ WA2. If there is a predicate on C, then it must be in conjunction
+ to all predicates on all earlier keyparts in I.
C) Overall query form:
SELECT EXPR([A_1,...,A_k], [B_1,...,B_m], [MIN(C)], [MAX(C)])
@@ -12571,6 +12700,13 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree, double read_time)
DBUG_RETURN(NULL);
}
}
+
+ /* Check (SA7). */
+ if (is_agg_distinct && (have_max || have_min))
+ {
+ DBUG_RETURN(NULL);
+ }
+
/* Check (SA5). */
if (join->select_distinct)
{
@@ -12860,6 +12996,25 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree, double read_time)
}
}
+ /**
+ Test WA2:If there are conditions on a column C participating in
+ MIN/MAX, those conditions must be conjunctions to all earlier
+ keyparts. Otherwise, Loose Index Scan cannot be used.
+ */
+ if (tree && min_max_arg_item)
+ {
+ uint dummy;
+ SEL_ARG *index_range_tree= get_index_range_tree(cur_index, tree, param,
+ &dummy);
+ SEL_ARG *cur_range= NULL;
+ if (get_sel_arg_for_keypart(min_max_arg_part->field,
+ index_range_tree, &cur_range) ||
+ (cur_range && cur_range->type != SEL_ARG::KEY_RANGE))
+ {
+ goto next_index;
+ }
+ }
+
/* If we got to this point, cur_index_info passes the test. */
key_infix_parts= cur_key_infix_len ? (uint)
(first_non_infix_part - first_non_group_part) : 0;
@@ -13177,73 +13332,75 @@ check_group_min_max_predicates(Item *cond, Item_field *min_max_arg_item,
/*
- Get SEL_ARG tree, if any, for the keypart covering non grouping
- attribute (NGA) field 'nga_field'.
+ Get the SEL_ARG tree 'tree' for the keypart covering 'field', if
+ any. 'tree' must be a unique conjunction to ALL predicates in earlier
+ keyparts of 'keypart_tree'.
+
+ E.g., if 'keypart_tree' is for a composite index (kp1,kp2) and kp2
+ covers 'field', all these conditions satisfies the requirement:
- This function enforces the NGA3 test: If 'keypart_tree' contains a
- condition for 'nga_field', there can only be one range. In the
- opposite case, this function returns with error and 'cur_range'
- should not be used.
+ 1. "(kp1=2 OR kp1=3) AND kp2=10" => returns "kp2=10"
+ 2. "(kp1=2 AND kp2=10) OR (kp1=3 AND kp2=10)" => returns "kp2=10"
+ 3. "(kp1=2 AND (kp2=10 OR kp2=11)) OR (kp1=3 AND (kp2=10 OR kp2=11))"
+ => returns "kp2=10 OR kp2=11"
- Note that the NGA1 and NGA2 requirements, like whether or not the
- range predicate for 'nga_field' is equality, is not tested by this
- function.
+ whereas these do not
+ 1. "(kp1=2 AND kp2=10) OR kp1=3"
+ 2. "(kp1=2 AND kp2=10) OR (kp1=3 AND kp2=11)"
+ 3. "(kp1=2 AND kp2=10) OR (kp1=3 AND (kp2=10 OR kp2=11))"
- @param[in] nga_field The NGA field we want the SEL_ARG tree for
+ This function effectively tests requirement WA2. In combination with
+ a test that the returned tree has no more than one range it is also
+ a test of NGA3.
+
+ @param[in] field The field we want the SEL_ARG tree for
@param[in] keypart_tree Root node of the SEL_ARG* tree for the index
@param[out] cur_range The SEL_ARG tree, if any, for the keypart
covering field 'keypart_field'
- @retval true 'keypart_tree' contained a predicate for 'nga_field' but
- multiple ranges exists. 'cur_range' should not be used.
+ @retval true 'keypart_tree' contained a predicate for 'field' that
+ is not conjunction to all predicates on earlier keyparts
@retval false otherwise
*/
static bool
-get_sel_arg_for_keypart(Field *nga_field,
+get_sel_arg_for_keypart(Field *field,
SEL_ARG *keypart_tree,
SEL_ARG **cur_range)
{
- if(keypart_tree == NULL)
+ if (keypart_tree == NULL)
return false;
- if(keypart_tree->field->eq(nga_field))
+ if (keypart_tree->field->eq(field))
{
- /*
- Enforce NGA3: If a condition for nga_field has been found, only
- a single range is allowed.
- */
- if (keypart_tree->prev || keypart_tree->next)
- return true; // There are multiple ranges
-
*cur_range= keypart_tree;
return false;
}
- SEL_ARG *found_tree= NULL;
+ SEL_ARG *tree_first_range= NULL;
SEL_ARG *first_kp= keypart_tree->first();
- for (SEL_ARG *cur_kp= first_kp; cur_kp && !found_tree;
- cur_kp= cur_kp->next)
+ for (SEL_ARG *cur_kp= first_kp; cur_kp; cur_kp= cur_kp->next)
{
+ SEL_ARG *curr_tree= NULL;
if (cur_kp->next_key_part)
{
- if (get_sel_arg_for_keypart(nga_field,
+ if (get_sel_arg_for_keypart(field,
cur_kp->next_key_part,
- &found_tree))
+ &curr_tree))
return true;
-
}
/*
- Enforce NGA3: If a condition for nga_field has been found,only
- a single range is allowed.
- */
- if (found_tree && first_kp->next)
- return true; // There are multiple ranges
+ Check if the SEL_ARG tree for 'field' is identical for all ranges in
+ 'keypart_tree
+ */
+ if (cur_kp == first_kp)
+ tree_first_range= curr_tree;
+ else if (!all_same(tree_first_range, curr_tree))
+ return true;
}
- *cur_range= found_tree;
+ *cur_range= tree_first_range;
return false;
}
-
/*
Extract a sequence of constants from a conjunction of equality predicates.
@@ -13266,7 +13423,8 @@ get_sel_arg_for_keypart(Field *nga_field,
(const_ci = NG_i).. In addition, there can only be one range when there is
such a gap.
Thus all the NGF_i attributes must fill the 'gap' between the last group-by
- attribute and the MIN/MAX attribute in the index (if present). If these
+ attribute and the MIN/MAX attribute in the index (if present). Also ensure
+ that there is only a single range on NGF_i (NGA3). If these
conditions hold, copy each constant from its corresponding predicate into
key_infix, in the order its NG_i attribute appears in the index, and update
key_infix_len with the total length of the key parts in key_infix.
@@ -13275,7 +13433,6 @@ get_sel_arg_for_keypart(Field *nga_field,
TRUE if the index passes the test
FALSE o/w
*/
-
static bool
get_constant_key_infix(KEY *index_info, SEL_ARG *index_range_tree,
KEY_PART_INFO *first_non_group_part,
@@ -13295,32 +13452,42 @@ get_constant_key_infix(KEY *index_info, SEL_ARG *index_range_tree,
{
cur_range= NULL;
/*
- Find the range tree for the current keypart. We assume that
- index_range_tree points to the first keypart in the index.
+ Check NGA3:
+ 1. get_sel_arg_for_keypart gets the range tree for the 'field' and also
+ checks for a unique conjunction of this tree with all the predicates
+ on the earlier keyparts in the index.
+ 2. Check for multiple ranges on the found keypart tree.
+
+ We assume that index_range_tree points to the leftmost keypart in
+ the index.
*/
- if(get_sel_arg_for_keypart(cur_part->field, index_range_tree, &cur_range))
+ if (get_sel_arg_for_keypart(cur_part->field, index_range_tree,
+ &cur_range))
+ return false;
+
+ if (cur_range && cur_range->elements > 1)
return false;
if (!cur_range || cur_range->type != SEL_ARG::KEY_RANGE)
{
if (min_max_arg_part)
- return FALSE; /* The current keypart has no range predicates at all. */
+ return false; /* The current keypart has no range predicates at all. */
else
{
*first_non_infix_part= cur_part;
- return TRUE;
+ return true;
}
}
if ((cur_range->min_flag & NO_MIN_RANGE) ||
(cur_range->max_flag & NO_MAX_RANGE) ||
(cur_range->min_flag & NEAR_MIN) || (cur_range->max_flag & NEAR_MAX))
- return FALSE;
+ return false;
uint field_length= cur_part->store_length;
if (cur_range->maybe_null &&
cur_range->min_value[0] && cur_range->max_value[0])
- {
+ {
/*
cur_range specifies 'IS NULL'. In this case the argument points
to a "null value" (is_null_string) that may not always be long
@@ -13339,7 +13506,7 @@ get_constant_key_infix(KEY *index_info, SEL_ARG *index_range_tree,
*key_infix_len+= field_length;
}
else
- return FALSE;
+ return false;
}
if (!min_max_arg_part && (cur_part == last_part))
diff --git a/sql/opt_range.h b/sql/opt_range.h
index 1ca245ea420..54b15826d1b 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -389,6 +389,13 @@ public:
Returns a QUICK_SELECT with reverse order of to the index.
*/
virtual QUICK_SELECT_I *make_reverse(uint used_key_parts_arg) { return NULL; }
+
+ /*
+ Add the key columns used by the quick select into table's read set.
+
+ This is used by an optimization in filesort.
+ */
+ virtual void add_used_key_part_to_set(MY_BITMAP *col_set)=0;
};
@@ -479,6 +486,9 @@ public:
#endif
virtual void replace_handler(handler *new_file) { file= new_file; }
QUICK_SELECT_I *make_reverse(uint used_key_parts_arg);
+
+ virtual void add_used_key_part_to_set(MY_BITMAP *col_set);
+
private:
/* Default copy ctor used by QUICK_SELECT_DESC */
friend class TRP_ROR_INTERSECT;
@@ -640,6 +650,8 @@ public:
virtual int read_keys_and_merge()= 0;
/* used to get rows collected in Unique */
READ_RECORD read_record;
+
+ virtual void add_used_key_part_to_set(MY_BITMAP *col_set);
};
@@ -714,6 +726,7 @@ public:
void add_keys_and_lengths(String *key_names, String *used_lengths);
Explain_quick_select *get_explain(MEM_ROOT *alloc);
bool is_keys_used(const MY_BITMAP *fields);
+ void add_used_key_part_to_set(MY_BITMAP *col_set);
#ifndef DBUG_OFF
void dbug_dump(int indent, bool verbose);
#endif
@@ -793,6 +806,7 @@ public:
void add_keys_and_lengths(String *key_names, String *used_lengths);
Explain_quick_select *get_explain(MEM_ROOT *alloc);
bool is_keys_used(const MY_BITMAP *fields);
+ void add_used_key_part_to_set(MY_BITMAP *col_set);
#ifndef DBUG_OFF
void dbug_dump(int indent, bool verbose);
#endif
@@ -935,6 +949,7 @@ public:
bool unique_key_range() { return false; }
int get_type() { return QS_TYPE_GROUP_MIN_MAX; }
void add_keys_and_lengths(String *key_names, String *used_lengths);
+ void add_used_key_part_to_set(MY_BITMAP *col_set);
#ifndef DBUG_OFF
void dbug_dump(int indent, bool verbose);
#endif
diff --git a/sql/replication.h b/sql/replication.h
index 510e56a3085..fc48ecd9ffc 100644
--- a/sql/replication.h
+++ b/sql/replication.h
@@ -16,6 +16,20 @@
#ifndef REPLICATION_H
#define REPLICATION_H
+/***************************************************************************
+ NOTE: plugin locking.
+ This API was created specifically for the semisync plugin and its locking
+ logic is also matches semisync plugin usage pattern. In particular, a plugin
+ is locked on Binlog_transmit_observer::transmit_start and is unlocked after
+ Binlog_transmit_observer::transmit_stop. All other master observable events
+ happen between these two and don't lock the plugin at all. This works well
+ for the semisync_master plugin.
+
+ Also a plugin is locked on Binlog_relay_IO_observer::thread_start
+ and unlocked after Binlog_relay_IO_observer::thread_stop. This works well for
+ the semisync_slave plugin.
+***************************************************************************/
+
#include <mysql.h>
typedef struct st_mysql MYSQL;
diff --git a/sql/rpl_handler.cc b/sql/rpl_handler.cc
index 2777dabf451..34d3df23435 100644
--- a/sql/rpl_handler.cc
+++ b/sql/rpl_handler.cc
@@ -170,40 +170,16 @@ void delegates_destroy()
/*
This macro is used by almost all the Delegate methods to iterate
over all the observers running given callback function of the
- delegate .
-
- Add observer plugins to the thd->lex list, after each statement, all
- plugins add to thd->lex will be automatically unlocked.
+ delegate.
*/
-#define FOREACH_OBSERVER(r, f, thd, args) \
+#define FOREACH_OBSERVER(r, f, do_lock, args) \
param.server_id= thd->variables.server_id; \
- /*
- Use a struct to make sure that they are allocated adjacent, check
- delete_dynamic().
- */ \
- struct { \
- DYNAMIC_ARRAY plugins; \
- /* preallocate 8 slots */ \
- plugin_ref plugins_buffer[8]; \
- } s; \
- DYNAMIC_ARRAY *plugins= &s.plugins; \
- plugin_ref *plugins_buffer= s.plugins_buffer; \
- my_init_dynamic_array2(plugins, sizeof(plugin_ref), \
- plugins_buffer, 8, 8, MYF(0)); \
read_lock(); \
Observer_info_iterator iter= observer_info_iter(); \
Observer_info *info= iter++; \
for (; info; info= iter++) \
{ \
- plugin_ref plugin= \
- my_plugin_lock(0, info->plugin); \
- if (!plugin) \
- { \
- /* plugin is not intialized or deleted, this is not an error */ \
- r= 0; \
- break; \
- } \
- insert_dynamic(plugins, (uchar *)&plugin); \
+ if (do_lock) plugin_lock(thd, plugin_int_to_ref(info->plugin_int)); \
if (((Observer *)info->observer)->f \
&& ((Observer *)info->observer)->f args) \
{ \
@@ -213,17 +189,7 @@ void delegates_destroy()
break; \
} \
} \
- unlock(); \
- /*
- Unlock plugins should be done after we released the Delegate lock
- to avoid possible deadlock when this is the last user of the
- plugin, and when we unlock the plugin, it will try to
- deinitialize the plugin, which will try to lock the Delegate in
- order to remove the observers.
- */ \
- plugin_unlock_list(0, (plugin_ref*)plugins->buffer, \
- plugins->elements); \
- delete_dynamic(plugins)
+ unlock();
int Trans_delegate::after_commit(THD *thd, bool all)
@@ -240,7 +206,7 @@ int Trans_delegate::after_commit(THD *thd, bool all)
param.log_pos= log_info ? log_info->log_pos : 0;
int ret= 0;
- FOREACH_OBSERVER(ret, after_commit, thd, (&param));
+ FOREACH_OBSERVER(ret, after_commit, false, (&param));
/*
This is the end of a real transaction or autocommit statement, we
@@ -268,7 +234,7 @@ int Trans_delegate::after_rollback(THD *thd, bool all)
param.log_pos= log_info ? log_info->log_pos : 0;
int ret= 0;
- FOREACH_OBSERVER(ret, after_rollback, thd, (&param));
+ FOREACH_OBSERVER(ret, after_rollback, false, (&param));
/*
This is the end of a real transaction or autocommit statement, we
@@ -307,7 +273,7 @@ int Binlog_storage_delegate::after_flush(THD *thd,
log_info->log_pos = log_pos;
int ret= 0;
- FOREACH_OBSERVER(ret, after_flush, thd,
+ FOREACH_OBSERVER(ret, after_flush, false,
(&param, log_info->log_file, log_info->log_pos, flags));
return ret;
}
@@ -321,7 +287,7 @@ int Binlog_transmit_delegate::transmit_start(THD *thd, ushort flags,
param.flags= flags;
int ret= 0;
- FOREACH_OBSERVER(ret, transmit_start, thd, (&param, log_file, log_pos));
+ FOREACH_OBSERVER(ret, transmit_start, true, (&param, log_file, log_pos));
return ret;
}
@@ -331,7 +297,7 @@ int Binlog_transmit_delegate::transmit_stop(THD *thd, ushort flags)
param.flags= flags;
int ret= 0;
- FOREACH_OBSERVER(ret, transmit_stop, thd, (&param));
+ FOREACH_OBSERVER(ret, transmit_stop, false, (&param));
return ret;
}
@@ -356,13 +322,6 @@ int Binlog_transmit_delegate::reserve_header(THD *thd, ushort flags,
Observer_info *info= iter++;
for (; info; info= iter++)
{
- plugin_ref plugin=
- my_plugin_lock(thd, info->plugin);
- if (!plugin)
- {
- ret= 1;
- break;
- }
hlen= 0;
if (((Observer *)info->observer)->reserve_header
&& ((Observer *)info->observer)->reserve_header(&param,
@@ -371,10 +330,8 @@ int Binlog_transmit_delegate::reserve_header(THD *thd, ushort flags,
&hlen))
{
ret= 1;
- plugin_unlock(thd, plugin);
break;
}
- plugin_unlock(thd, plugin);
if (hlen == 0)
continue;
if (hlen > RESERVE_HEADER_SIZE || packet->append((char *)header, hlen))
@@ -396,7 +353,7 @@ int Binlog_transmit_delegate::before_send_event(THD *thd, ushort flags,
param.flags= flags;
int ret= 0;
- FOREACH_OBSERVER(ret, before_send_event, thd,
+ FOREACH_OBSERVER(ret, before_send_event, false,
(&param, (uchar *)packet->c_ptr(),
packet->length(),
log_file+dirname_length(log_file), log_pos));
@@ -410,7 +367,7 @@ int Binlog_transmit_delegate::after_send_event(THD *thd, ushort flags,
param.flags= flags;
int ret= 0;
- FOREACH_OBSERVER(ret, after_send_event, thd,
+ FOREACH_OBSERVER(ret, after_send_event, false,
(&param, packet->c_ptr(), packet->length()));
return ret;
}
@@ -422,7 +379,7 @@ int Binlog_transmit_delegate::after_reset_master(THD *thd, ushort flags)
param.flags= flags;
int ret= 0;
- FOREACH_OBSERVER(ret, after_reset_master, thd, (&param));
+ FOREACH_OBSERVER(ret, after_reset_master, false, (&param));
return ret;
}
@@ -443,7 +400,7 @@ int Binlog_relay_IO_delegate::thread_start(THD *thd, Master_info *mi)
init_param(&param, mi);
int ret= 0;
- FOREACH_OBSERVER(ret, thread_start, thd, (&param));
+ FOREACH_OBSERVER(ret, thread_start, true, (&param));
return ret;
}
@@ -455,7 +412,7 @@ int Binlog_relay_IO_delegate::thread_stop(THD *thd, Master_info *mi)
init_param(&param, mi);
int ret= 0;
- FOREACH_OBSERVER(ret, thread_stop, thd, (&param));
+ FOREACH_OBSERVER(ret, thread_stop, false, (&param));
return ret;
}
@@ -467,7 +424,7 @@ int Binlog_relay_IO_delegate::before_request_transmit(THD *thd,
init_param(&param, mi);
int ret= 0;
- FOREACH_OBSERVER(ret, before_request_transmit, thd, (&param, (uint32)flags));
+ FOREACH_OBSERVER(ret, before_request_transmit, false, (&param, (uint32)flags));
return ret;
}
@@ -480,7 +437,7 @@ int Binlog_relay_IO_delegate::after_read_event(THD *thd, Master_info *mi,
init_param(&param, mi);
int ret= 0;
- FOREACH_OBSERVER(ret, after_read_event, thd,
+ FOREACH_OBSERVER(ret, after_read_event, false,
(&param, packet, len, event_buf, event_len));
return ret;
}
@@ -498,7 +455,7 @@ int Binlog_relay_IO_delegate::after_queue_event(THD *thd, Master_info *mi,
flags |= BINLOG_STORAGE_IS_SYNCED;
int ret= 0;
- FOREACH_OBSERVER(ret, after_queue_event, thd,
+ FOREACH_OBSERVER(ret, after_queue_event, false,
(&param, event_buf, event_len, flags));
return ret;
}
@@ -510,7 +467,7 @@ int Binlog_relay_IO_delegate::after_reset_slave(THD *thd, Master_info *mi)
init_param(&param, mi);
int ret= 0;
- FOREACH_OBSERVER(ret, after_reset_slave, thd, (&param));
+ FOREACH_OBSERVER(ret, after_reset_slave, false, (&param));
return ret;
}
#endif /* HAVE_REPLICATION */
diff --git a/sql/rpl_handler.h b/sql/rpl_handler.h
index e028fb49808..e262ebdbd6b 100644
--- a/sql/rpl_handler.h
+++ b/sql/rpl_handler.h
@@ -26,13 +26,10 @@ class Observer_info {
public:
void *observer;
st_plugin_int *plugin_int;
- plugin_ref plugin;
Observer_info(void *ob, st_plugin_int *p)
:observer(ob), plugin_int(p)
- {
- plugin= plugin_int_to_ref(plugin_int);
- }
+ { }
};
class Delegate {
diff --git a/sql/scheduler.cc b/sql/scheduler.cc
index ecf49e633ab..a9b253e478a 100644
--- a/sql/scheduler.cc
+++ b/sql/scheduler.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
- Copyright (c) 2012, 2013, Monty Program Ab
+/* Copyright (c) 2007, 2013, Oracle and/or its affiliates.
+ Copyright (c) 2012, 2014, SkySQL Ab.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/sql/slave.cc b/sql/slave.cc
index 5d6ce9287f2..cdab2779e86 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -1772,15 +1772,35 @@ when it try to get the value of TIME_ZONE global variable from master.";
llstr((ulonglong) (mi->heartbeat_period*1000000000UL), llbuf);
sprintf(query, query_format, llbuf);
- if (mysql_real_query(mysql, query, strlen(query))
- && !check_io_slave_killed(mi, NULL))
+ DBUG_EXECUTE_IF("simulate_slave_heartbeat_network_error",
+ { static ulong dbug_count= 0;
+ if (++dbug_count < 3)
+ goto heartbeat_network_error;
+ });
+ if (mysql_real_query(mysql, query, strlen(query)))
{
- errmsg= "The slave I/O thread stops because SET @master_heartbeat_period "
- "on master failed.";
- err_code= ER_SLAVE_FATAL_ERROR;
- sprintf(err_buff, "%s Error: %s", errmsg, mysql_error(mysql));
- mysql_free_result(mysql_store_result(mysql));
- goto err;
+ if (check_io_slave_killed(mi, NULL))
+ goto slave_killed_err;
+
+ if (is_network_error(mysql_errno(mysql)))
+ {
+ IF_DBUG(heartbeat_network_error: , )
+ mi->report(WARNING_LEVEL, mysql_errno(mysql),
+ "SET @master_heartbeat_period to master failed with error: %s",
+ mysql_error(mysql));
+ mysql_free_result(mysql_store_result(mysql));
+ goto network_err;
+ }
+ else
+ {
+ /* Fatal error */
+ errmsg= "The slave I/O thread stops because a fatal error is encountered "
+ "when it tries to SET @master_heartbeat_period on master.";
+ err_code= ER_SLAVE_FATAL_ERROR;
+ sprintf(err_buff, "%s Error: %s", errmsg, mysql_error(mysql));
+ mysql_free_result(mysql_store_result(mysql));
+ goto err;
+ }
}
mysql_free_result(mysql_store_result(mysql));
}
@@ -4179,9 +4199,10 @@ err_during_init:
// TODO: make rpl_status part of Master_info
change_rpl_status(RPL_ACTIVE_SLAVE,RPL_IDLE_SLAVE);
mysql_mutex_lock(&LOCK_thread_count);
+ thd->unlink();
+ mysql_mutex_unlock(&LOCK_thread_count);
THD_CHECK_SENTRY(thd);
delete thd;
- mysql_mutex_unlock(&LOCK_thread_count);
mi->abort_slave= 0;
mi->slave_running= MYSQL_SLAVE_NOT_RUN;
mi->io_thd= 0;
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index cf68ba36997..6001517b0c7 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -1711,7 +1711,7 @@ Query_cache::send_result_to_client(THD *thd, char *org_sql, uint query_length)
DBUG_ENTER("Query_cache::send_result_to_client");
/*
- Testing 'query_cache_size' without a lock here is safe: the thing
+ Testing without a lock here is safe: the thing
we may loose is that the query won't be served from cache, but we
save on mutex locking in the case when query cache is disabled.
@@ -1731,8 +1731,6 @@ Query_cache::send_result_to_client(THD *thd, char *org_sql, uint query_length)
goto err;
}
- DBUG_ASSERT(query_cache_size != 0); // otherwise cache would be disabled
-
thd->query_cache_is_applicable= 1;
sql= org_sql; sql_end= sql + query_length;
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 27e195e52d4..650966dd78a 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2008, 2013, Monty Program Ab.
+ Copyright (c) 2008, 2014, SkySQL Ab.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index b3a8eb2a97b..a8f7e270891 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -912,7 +912,8 @@ multi_delete::initialize_tables(JOIN *join)
walk= delete_tables;
- for (JOIN_TAB *tab= first_linear_tab(join, WITH_CONST_TABLES);
+ for (JOIN_TAB *tab= first_linear_tab(join, WITHOUT_BUSH_ROOTS,
+ WITH_CONST_TABLES);
tab;
tab= next_linear_tab(join, tab, WITHOUT_BUSH_ROOTS))
{
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index a910ed6290f..c62fb81334a 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -614,6 +614,7 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
SELECT_LEX_UNIT *unit= derived->get_unit();
DBUG_ENTER("mysql_derived_prepare");
bool res= FALSE;
+ DBUG_PRINT("enter", ("unit 0x%lx", (ulong) unit));
// Skip already prepared views/DT
if (!unit || unit->prepared ||
@@ -623,9 +624,6 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
thd->lex->sql_command == SQLCOM_DELETE_MULTI))))
DBUG_RETURN(FALSE);
- Query_arena *arena, backup;
- arena= thd->activate_stmt_arena_if_needed(&backup);
-
SELECT_LEX *first_select= unit->first_select();
/* prevent name resolving out of derived table */
@@ -743,8 +741,6 @@ exit:
if (derived->outer_join)
table->maybe_null= 1;
}
- if (arena)
- thd->restore_active_arena(arena, &backup);
DBUG_RETURN(res);
}
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index d1b9961503f..e0f6a998e66 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2009, 2013, Monty Program Ab.
+ Copyright (c) 2010, 2014, SkySQL Ab.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index c549a7be2cc..e38075f1746 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2009, 2013, Monty Program Ab.
+/* Copyright (c) 2000, 2014, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2014, Monty Program Ab.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -30,7 +30,7 @@
#include "sp.h"
#include "sql_select.h"
-static int lex_one_token(void *arg, THD *thd);
+static int lex_one_token(YYSTYPE *yylval, THD *thd);
/*
We are using pointer to this variable for distinguishing between assignment
@@ -958,15 +958,17 @@ bool consume_comment(Lex_input_stream *lip, int remaining_recursions_permitted)
/*
MYSQLlex remember the following states from the following MYSQLlex()
+ @param yylval [out] semantic value of the token being parsed (yylval)
+ @param thd THD
+
- MY_LEX_EOQ Found end of query
- MY_LEX_OPERATOR_OR_IDENT Last state was an ident, text or number
(which can't be followed by a signed number)
*/
-int MYSQLlex(void *arg, THD *thd)
+int MYSQLlex(YYSTYPE *yylval, THD *thd)
{
Lex_input_stream *lip= & thd->m_parser_state->m_lip;
- YYSTYPE *yylval=(YYSTYPE*) arg;
int token;
if (lip->lookahead_token >= 0)
@@ -983,7 +985,7 @@ int MYSQLlex(void *arg, THD *thd)
return token;
}
- token= lex_one_token(arg, thd);
+ token= lex_one_token(yylval, thd);
switch(token) {
case WITH:
@@ -994,7 +996,7 @@ int MYSQLlex(void *arg, THD *thd)
to transform the grammar into a LALR(1) grammar,
which sql_yacc.yy can process.
*/
- token= lex_one_token(arg, thd);
+ token= lex_one_token(yylval, thd);
switch(token) {
case CUBE_SYM:
lip->m_digest_psi= MYSQL_ADD_TOKEN(lip->m_digest_psi, WITH_CUBE_SYM,
@@ -1023,7 +1025,7 @@ int MYSQLlex(void *arg, THD *thd)
return token;
}
-int lex_one_token(void *arg, THD *thd)
+static int lex_one_token(YYSTYPE *yylval, THD *thd)
{
reg1 uchar c;
bool comment_closed;
@@ -1032,7 +1034,6 @@ int lex_one_token(void *arg, THD *thd)
enum my_lex_states state;
Lex_input_stream *lip= & thd->m_parser_state->m_lip;
LEX *lex= thd->lex;
- YYSTYPE *yylval=(YYSTYPE*) arg;
CHARSET_INFO *const cs= thd->charset();
const uchar *const state_map= cs->state_map;
const uchar *const ident_map= cs->ident_map;
@@ -3281,7 +3282,7 @@ static void fix_prepare_info_in_table_list(THD *thd, TABLE_LIST *tbl)
{
for (; tbl; tbl= tbl->next_local)
{
- if (tbl->on_expr)
+ if (tbl->on_expr && !tbl->prep_on_expr)
{
thd->check_and_register_item_tree(&tbl->prep_on_expr, &tbl->on_expr);
tbl->on_expr= tbl->on_expr->copy_andor_structure(thd);
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 76288e94c75..e15901a9c54 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -1,5 +1,5 @@
-/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2010, 2013, Monty Program Ab.
+/* Copyright (c) 2000, 2014, Oracle and/or its affiliates.
+ Copyright (c) 2010, 2014, Monty Program Ab.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -2911,7 +2911,7 @@ extern void lex_start(THD *thd);
extern void lex_end(LEX *lex);
void end_lex_with_single_table(THD *thd, TABLE *table, LEX *old_lex);
int init_lex_with_single_table(THD *thd, TABLE *table, LEX *lex);
-extern int MYSQLlex(void *arg, THD *thd);
+extern int MYSQLlex(union YYSTYPE *yylval, THD *thd);
extern void trim_whitespace(CHARSET_INFO *cs, LEX_STRING *str);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index d3f1ad9afba..4070a833f82 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2008, 2013, Monty Program Ab
+ Copyright (c) 2008, 2014, SkySQL Ab.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -7390,7 +7390,7 @@ static uint kill_threads_for_user(THD *thd, LEX_USER *user,
I_List_iterator<THD> it(threads);
while ((tmp=it++))
{
- if (tmp->get_command() == COM_DAEMON)
+ if (!tmp->security_ctx->user)
continue;
/*
Check that hostname (if given) and user name matches.
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index 1ce952b9030..18e49d878cd 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2005, 2013, Oracle and/or its affiliates.
- Copyright (c) 2009, 2013, Monty Program Ab.
+/* Copyright (c) 2005, 2014, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2014, SkySQL Ab.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -3167,19 +3167,28 @@ uint32 get_partition_id_cols_list_for_endpoint(partition_info *part_info,
uint num_columns= part_info->part_field_list.elements;
uint list_index;
uint min_list_index= 0;
+ int cmp;
+ /* Notice that max_list_index = last_index + 1 here! */
uint max_list_index= part_info->num_list_values;
DBUG_ENTER("get_partition_id_cols_list_for_endpoint");
/* Find the matching partition (including taking endpoint into account). */
do
{
- /* Midpoint, adjusted down, so it can never be > last index. */
+ /* Midpoint, adjusted down, so it can never be >= max_list_index. */
list_index= (max_list_index + min_list_index) >> 1;
- if (cmp_rec_and_tuple_prune(list_col_array + list_index*num_columns,
- nparts, left_endpoint, include_endpoint) > 0)
+ cmp= cmp_rec_and_tuple_prune(list_col_array + list_index*num_columns,
+ nparts, left_endpoint, include_endpoint);
+ if (cmp > 0)
+ {
min_list_index= list_index + 1;
+ }
else
+ {
max_list_index= list_index;
+ if (cmp == 0)
+ break;
+ }
} while (max_list_index > min_list_index);
list_index= max_list_index;
@@ -3196,12 +3205,10 @@ uint32 get_partition_id_cols_list_for_endpoint(partition_info *part_info,
nparts, left_endpoint,
include_endpoint)));
- if (!left_endpoint)
- {
- /* Set the end after this list tuple if not already after the last. */
- if (list_index < part_info->num_parts)
- list_index++;
- }
+ /* Include the right endpoint if not already passed end of array. */
+ if (!left_endpoint && include_endpoint && cmp == 0 &&
+ list_index < part_info->num_list_values)
+ list_index++;
DBUG_RETURN(list_index);
}
@@ -7573,15 +7580,13 @@ static int cmp_rec_and_tuple_prune(part_column_list_val *val,
field= val->part_info->part_field_array + n_vals_in_rec;
if (!(*field))
{
- /*
- Full match, if right endpoint and not including the endpoint,
- (rec < part) return lesser.
- */
- if (!is_left_endpoint && !include_endpoint)
- return -4;
+ /* Full match. Only equal if including endpoint. */
+ if (include_endpoint)
+ return 0;
- /* Otherwise they are equal! */
- return 0;
+ if (is_left_endpoint)
+ return +4; /* Start of range, part_tuple < rec, return higher. */
+ return -4; /* End of range, rec < part_tupe, return lesser. */
}
/*
The prefix is equal and there are more partition columns to compare.
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
index d79cc0aaada..0521baaf77f 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -1613,7 +1613,7 @@ int plugin_init(int *argc, char **argv, int flags)
if (plugin_initialize(&tmp_root, plugin_ptr, argc, argv, !is_myisam &&
(flags & PLUGIN_INIT_SKIP_INITIALIZATION)))
{
- if (mandatory)
+ if (plugin_ptr->load_option == PLUGIN_FORCE)
goto err_unlock;
plugin_ptr->state= PLUGIN_IS_DISABLED;
}
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index e2ba5197dc4..0f4a7c5133e 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2008, 2013, Monty Program Ab
+ Copyright (c) 2008, 2014, SkySQL Ab.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 3b3d1527607..160ffe11abc 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1441,7 +1441,8 @@ TODO: make view to decide if it is possible to write to WHERE directly or make S
Perform the optimization on fields evaluation mentioned above
for all on expressions.
*/
- for (JOIN_TAB *tab= first_linear_tab(this, WITHOUT_CONST_TABLES); tab;
+ JOIN_TAB *tab;
+ for (tab= first_linear_tab(this, WITH_BUSH_ROOTS, WITHOUT_CONST_TABLES); tab;
tab= next_linear_tab(this, tab, WITH_BUSH_ROOTS))
{
if (*tab->on_expr_ref)
@@ -1464,7 +1465,7 @@ TODO: make view to decide if it is possible to write to WHERE directly or make S
Perform the optimization on fields evaliation mentioned above
for all used ref items.
*/
- for (JOIN_TAB *tab= first_linear_tab(this, WITHOUT_CONST_TABLES); tab;
+ for (tab= first_linear_tab(this, WITH_BUSH_ROOTS, WITHOUT_CONST_TABLES); tab;
tab= next_linear_tab(this, tab, WITH_BUSH_ROOTS))
{
uint key_copy_index=0;
@@ -2099,7 +2100,8 @@ bool JOIN::setup_subquery_caches()
if (conds)
conds= conds->transform(&Item::expr_cache_insert_transformer,
(uchar*) thd);
- for (JOIN_TAB *tab= first_linear_tab(this, WITHOUT_CONST_TABLES);
+ JOIN_TAB *tab;
+ for (tab= first_linear_tab(this, WITH_BUSH_ROOTS, WITHOUT_CONST_TABLES);
tab; tab= next_linear_tab(this, tab, WITH_BUSH_ROOTS))
{
if (tab->select_cond)
@@ -2261,7 +2263,8 @@ JOIN::reinit()
/* need to reset ref access state (see join_read_key) */
if (join_tab)
{
- for (JOIN_TAB *tab= first_linear_tab(this, WITH_CONST_TABLES); tab;
+ JOIN_TAB *tab;
+ for (tab= first_linear_tab(this, WITH_BUSH_ROOTS, WITH_CONST_TABLES); tab;
tab= next_linear_tab(this, tab, WITH_BUSH_ROOTS))
{
tab->ref.key_err= TRUE;
@@ -3120,8 +3123,9 @@ JOIN::destroy()
{
if (join_tab != tmp_join->join_tab)
{
- for (JOIN_TAB *tab= first_linear_tab(this, WITH_CONST_TABLES); tab;
- tab= next_linear_tab(this, tab, WITH_BUSH_ROOTS))
+ JOIN_TAB *tab;
+ for (tab= first_linear_tab(this, WITH_BUSH_ROOTS, WITH_CONST_TABLES);
+ tab; tab= next_linear_tab(this, tab, WITH_BUSH_ROOTS))
{
tab->cleanup();
}
@@ -8186,14 +8190,24 @@ JOIN_TAB *next_top_level_tab(JOIN *join, JOIN_TAB *tab)
}
-JOIN_TAB *first_linear_tab(JOIN *join, enum enum_with_const_tables const_tbls)
+JOIN_TAB *first_linear_tab(JOIN *join,
+ enum enum_with_bush_roots include_bush_roots,
+ enum enum_with_const_tables const_tbls)
{
JOIN_TAB *first= join->join_tab;
if (const_tbls == WITHOUT_CONST_TABLES)
first+= join->const_tables;
- if (first < join->join_tab + join->top_join_tab_count)
- return first;
- return NULL; /* All tables were const tables */
+
+ if (first >= join->join_tab + join->top_join_tab_count)
+ return NULL; /* All are const tables */
+
+ if (first->bush_children && include_bush_roots == WITHOUT_BUSH_ROOTS)
+ {
+ /* This JOIN_TAB is a SJM nest; Start from first table in nest */
+ return first->bush_children->start;
+ }
+
+ return first;
}
@@ -9045,9 +9059,10 @@ inline void add_cond_and_fix(THD *thd, Item **e1, Item *e2)
static void add_not_null_conds(JOIN *join)
{
+ JOIN_TAB *tab;
DBUG_ENTER("add_not_null_conds");
- for (JOIN_TAB *tab= first_linear_tab(join, WITHOUT_CONST_TABLES);
+ for (tab= first_linear_tab(join, WITH_BUSH_ROOTS, WITHOUT_CONST_TABLES);
tab;
tab= next_linear_tab(join, tab, WITH_BUSH_ROOTS))
{
@@ -9218,7 +9233,7 @@ make_outerjoin_info(JOIN *join)
tab->table->pos_in_table_list being set.
*/
JOIN_TAB *tab;
- for (tab= first_linear_tab(join, WITHOUT_CONST_TABLES);
+ for (tab= first_linear_tab(join, WITH_BUSH_ROOTS, WITHOUT_CONST_TABLES);
tab;
tab= next_linear_tab(join, tab, WITH_BUSH_ROOTS))
{
@@ -9230,7 +9245,7 @@ make_outerjoin_info(JOIN *join)
}
}
- for (JOIN_TAB *tab= first_linear_tab(join, WITHOUT_CONST_TABLES); tab;
+ for (JOIN_TAB *tab= first_linear_tab(join, WITH_BUSH_ROOTS, WITHOUT_CONST_TABLES); tab;
tab= next_linear_tab(join, tab, WITH_BUSH_ROOTS))
{
TABLE *table= tab->table;
@@ -9982,7 +9997,7 @@ bool generate_derived_keys(DYNAMIC_ARRAY *keyuse_array)
void JOIN::drop_unused_derived_keys()
{
JOIN_TAB *tab;
- for (tab= first_linear_tab(this, WITHOUT_CONST_TABLES);
+ for (tab= first_linear_tab(this, WITH_BUSH_ROOTS, WITHOUT_CONST_TABLES);
tab;
tab= next_linear_tab(this, tab, WITH_BUSH_ROOTS))
{
@@ -10670,7 +10685,7 @@ void check_join_cache_usage_for_tables(JOIN *join, ulonglong options,
JOIN_TAB *tab;
JOIN_TAB *prev_tab;
- for (tab= first_linear_tab(join, WITHOUT_CONST_TABLES);
+ for (tab= first_linear_tab(join, WITH_BUSH_ROOTS, WITHOUT_CONST_TABLES);
tab;
tab= next_linear_tab(join, tab, WITH_BUSH_ROOTS))
{
@@ -10678,7 +10693,7 @@ void check_join_cache_usage_for_tables(JOIN *join, ulonglong options,
}
uint idx= join->const_tables;
- for (tab= first_linear_tab(join, WITHOUT_CONST_TABLES);
+ for (tab= first_linear_tab(join, WITH_BUSH_ROOTS, WITHOUT_CONST_TABLES);
tab;
tab= next_linear_tab(join, tab, WITH_BUSH_ROOTS))
{
@@ -10852,7 +10867,8 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after)
tab->partial_join_cardinality= 1;
JOIN_TAB *prev_tab= NULL;
- for (tab= first_linear_tab(join, WITHOUT_CONST_TABLES), i= join->const_tables;
+ i= join->const_tables;
+ for (tab= first_linear_tab(join, WITH_BUSH_ROOTS, WITHOUT_CONST_TABLES);
tab;
prev_tab=tab, tab= next_linear_tab(join, tab, WITH_BUSH_ROOTS))
{
@@ -10877,7 +10893,7 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after)
check_join_cache_usage_for_tables(join, options, no_jbuf_after);
JOIN_TAB *first_tab;
- for (tab= first_tab= first_linear_tab(join, WITHOUT_CONST_TABLES);
+ for (tab= first_tab= first_linear_tab(join, WITH_BUSH_ROOTS, WITHOUT_CONST_TABLES);
tab;
tab= next_linear_tab(join, tab, WITH_BUSH_ROOTS))
{
@@ -11571,7 +11587,8 @@ void JOIN::cleanup(bool full)
}
if (full)
{
- JOIN_TAB *sort_tab= first_linear_tab(this, WITHOUT_CONST_TABLES);
+ JOIN_TAB *sort_tab= first_linear_tab(this, WITH_BUSH_ROOTS,
+ WITHOUT_CONST_TABLES);
if (pre_sort_join_tab)
{
if (sort_tab && sort_tab->select == pre_sort_join_tab->select)
@@ -11618,7 +11635,7 @@ void JOIN::cleanup(bool full)
}
else
{
- for (tab= first_linear_tab(this, WITH_CONST_TABLES); tab;
+ for (tab= first_linear_tab(this, WITH_BUSH_ROOTS, WITH_CONST_TABLES); tab;
tab= next_linear_tab(this, tab, WITH_BUSH_ROOTS))
{
if (tab->table)
@@ -11780,7 +11797,9 @@ only_eq_ref_tables(JOIN *join,ORDER *order,table_map tables)
static void update_depend_map(JOIN *join)
{
- for (JOIN_TAB *join_tab= first_linear_tab(join, WITH_CONST_TABLES); join_tab;
+ JOIN_TAB *join_tab;
+ for (join_tab= first_linear_tab(join, WITH_BUSH_ROOTS, WITH_CONST_TABLES);
+ join_tab;
join_tab= next_linear_tab(join, join_tab, WITH_BUSH_ROOTS))
{
TABLE_REF *ref= &join_tab->ref;
diff --git a/sql/sql_select.h b/sql/sql_select.h
index dc86825e8e9..490d8c91a9e 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -1500,7 +1500,9 @@ private:
enum enum_with_bush_roots { WITH_BUSH_ROOTS, WITHOUT_BUSH_ROOTS};
enum enum_with_const_tables { WITH_CONST_TABLES, WITHOUT_CONST_TABLES};
-JOIN_TAB *first_linear_tab(JOIN *join, enum enum_with_const_tables const_tbls);
+JOIN_TAB *first_linear_tab(JOIN *join,
+ enum enum_with_bush_roots include_bush_roots,
+ enum enum_with_const_tables const_tbls);
JOIN_TAB *next_linear_tab(JOIN* join, JOIN_TAB* tab,
enum enum_with_bush_roots include_bush_roots);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 025eee72878..3916b7acf6b 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -8072,8 +8072,9 @@ bool get_schema_tables_result(JOIN *join,
Warnings_only_error_handler err_handler;
thd->push_internal_handler(&err_handler);
old_proc_info= thd_proc_info(thd, "Filling schema table");
-
- for (JOIN_TAB *tab= first_linear_tab(join, WITH_CONST_TABLES);
+
+ JOIN_TAB *tab;
+ for (tab= first_linear_tab(join, WITHOUT_BUSH_ROOTS, WITH_CONST_TABLES);
tab;
tab= next_linear_tab(join, tab, WITHOUT_BUSH_ROOTS))
{
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 3a44303e3ba..5f2f1141a04 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2014, Oracle and/or its affiliates.
- Copyright (c) 2010, 2014, Monty Program Ab.
+ Copyright (c) 2010, 2014, SkySQL Ab.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -75,6 +75,7 @@ static bool prepare_blob_field(THD *thd, Create_field *sql_field);
static bool check_engine(THD *, const char *, const char *, HA_CREATE_INFO *);
static int mysql_prepare_create_table(THD *, HA_CREATE_INFO *, Alter_info *,
uint *, handler *, KEY **, uint *, int);
+static uint blob_length_by_type(enum_field_types type);
/**
@brief Helper function for explain_filename
@@ -3812,7 +3813,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
CHARSET_INFO *ft_key_charset=0; // for FULLTEXT
for (uint column_nr=0 ; (column=cols++) ; column_nr++)
{
- uint length;
Key_part_spec *dup_column;
it.rewind();
@@ -3890,7 +3890,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
}
if (f_is_geom(sql_field->pack_flag) && sql_field->geom_type ==
Field::GEOM_POINT)
- column->length= 25;
+ column->length= MAX_LEN_GEOM_POINT_FIELD;
if (!column->length)
{
my_error(ER_BLOB_KEY_WITHOUT_LENGTH, MYF(0), column->field_name.str);
@@ -3956,30 +3956,31 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
key_part_info->fieldnr= field;
key_part_info->offset= (uint16) sql_field->offset;
key_part_info->key_type=sql_field->pack_flag;
- length= sql_field->key_length;
+ uint key_part_length= sql_field->key_length;
if (column->length)
{
if (f_is_blob(sql_field->pack_flag))
{
- if ((length=column->length) > max_key_length ||
- length > file->max_key_part_length())
+ key_part_length= MY_MIN(column->length,
+ blob_length_by_type(sql_field->sql_type)
+ * sql_field->charset->mbmaxlen);
+ if (key_part_length > max_key_length ||
+ key_part_length > file->max_key_part_length())
{
- length=MY_MIN(max_key_length, file->max_key_part_length());
+ key_part_length= MY_MIN(max_key_length, file->max_key_part_length());
if (key->type == Key::MULTIPLE)
{
/* not a critical problem */
- char warn_buff[MYSQL_ERRMSG_SIZE];
- my_snprintf(warn_buff, sizeof(warn_buff), ER(ER_TOO_LONG_KEY),
- length);
- push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_TOO_LONG_KEY, warn_buff);
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_TOO_LONG_KEY, ER(ER_TOO_LONG_KEY),
+ key_part_length);
/* Align key length to multibyte char boundary */
- length-= length % sql_field->charset->mbmaxlen;
+ key_part_length-= key_part_length % sql_field->charset->mbmaxlen;
}
else
{
- my_error(ER_TOO_LONG_KEY,MYF(0),length);
+ my_error(ER_TOO_LONG_KEY, MYF(0), key_part_length);
DBUG_RETURN(TRUE);
}
}
@@ -3987,9 +3988,9 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
// Catch invalid use of partial keys
else if (!f_is_geom(sql_field->pack_flag) &&
// is the key partial?
- column->length != length &&
+ column->length != key_part_length &&
// is prefix length bigger than field length?
- (column->length > length ||
+ (column->length > key_part_length ||
// can the field have a partial key?
!Field::type_can_have_key_part (sql_field->sql_type) ||
// a packed field can't be used in a partial key
@@ -3998,44 +3999,43 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
((file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS) &&
// and is this a 'unique' key?
(key_info->flags & HA_NOSAME))))
- {
+ {
my_message(ER_WRONG_SUB_KEY, ER(ER_WRONG_SUB_KEY), MYF(0));
DBUG_RETURN(TRUE);
}
else if (!(file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS))
- length=column->length;
+ key_part_length= column->length;
}
- else if (length == 0 && (sql_field->flags & NOT_NULL_FLAG))
+ else if (key_part_length == 0 && (sql_field->flags & NOT_NULL_FLAG))
{
my_error(ER_WRONG_KEY_COLUMN, MYF(0), file->table_type(),
column->field_name.str);
DBUG_RETURN(TRUE);
}
- if (length > file->max_key_part_length() && key->type != Key::FULLTEXT)
+ if (key_part_length > file->max_key_part_length() &&
+ key->type != Key::FULLTEXT)
{
- length= file->max_key_part_length();
+ key_part_length= file->max_key_part_length();
if (key->type == Key::MULTIPLE)
{
/* not a critical problem */
- char warn_buff[MYSQL_ERRMSG_SIZE];
- my_snprintf(warn_buff, sizeof(warn_buff), ER(ER_TOO_LONG_KEY),
- length);
- push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_TOO_LONG_KEY, warn_buff);
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_TOO_LONG_KEY, ER(ER_TOO_LONG_KEY),
+ key_part_length);
/* Align key length to multibyte char boundary */
- length-= length % sql_field->charset->mbmaxlen;
+ key_part_length-= key_part_length % sql_field->charset->mbmaxlen;
}
else
{
- my_error(ER_TOO_LONG_KEY,MYF(0),length);
+ my_error(ER_TOO_LONG_KEY, MYF(0), key_part_length);
DBUG_RETURN(TRUE);
}
}
- key_part_info->length=(uint16) length;
+ key_part_info->length= (uint16) key_part_length;
/* Use packed keys for long strings on the first column */
if (!((*db_options) & HA_OPTION_NO_PACK_KEYS) &&
!((create_info->table_options & HA_OPTION_NO_PACK_KEYS)) &&
- (length >= KEY_DEFAULT_PACK_LENGTH &&
+ (key_part_length >= KEY_DEFAULT_PACK_LENGTH &&
(sql_field->sql_type == MYSQL_TYPE_STRING ||
sql_field->sql_type == MYSQL_TYPE_VARCHAR ||
sql_field->pack_flag & FIELDFLAG_BLOB)))
@@ -4047,10 +4047,10 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
key_info->flags|= HA_PACK_KEY;
}
/* Check if the key segment is partial, set the key flag accordingly */
- if (length != sql_field->key_length)
+ if (key_part_length != sql_field->key_length)
key_info->flags|= HA_KEY_HAS_PART_KEY_SEG;
- key_length+=length;
+ key_length+= key_part_length;
key_part_info++;
/* Create the key name based on the first column (if not given) */
diff --git a/sql/sql_table.h b/sql/sql_table.h
index 444626e0363..2b383623873 100644
--- a/sql/sql_table.h
+++ b/sql/sql_table.h
@@ -117,6 +117,9 @@ enum enum_explain_filename_mode
EXPLAIN_PARTITIONS_AS_COMMENT
};
+/* Maximum length of GEOM_POINT Field */
+#define MAX_LEN_GEOM_POINT_FIELD 25
+
/* depends on errmsg.txt Database `db`, Table `t` ... */
#define EXPLAIN_FILENAME_MAX_EXTRA_LENGTH 63
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 9d068e464f5..fe8bb7a6620 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -1,4 +1,5 @@
-/* Copyright (c) 2000, 2011, Oracle and/or its affiliates.
+/* Copyright (c) 2000, 2014, Oracle and/or its affiliates.
+ Copyright (c) 2010, 2014, SkySQL Ab.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index a18193c6eb6..07169f299d7 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -400,9 +400,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
TABLE_LIST *tables= lex->query_tables;
TABLE_LIST *tbl;
SELECT_LEX *select_lex= &lex->select_lex;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
SELECT_LEX *sl;
-#endif
SELECT_LEX_UNIT *unit= &lex->unit;
bool res= FALSE;
DBUG_ENTER("mysql_create_view");
@@ -547,7 +545,8 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
}
/* Check if the auto generated column names are conforming. */
- make_valid_column_names(select_lex->item_list);
+ for (sl= select_lex; sl; sl= sl->next_select())
+ make_valid_column_names(sl->item_list);
if (check_duplicate_names(select_lex->item_list, 1))
{
@@ -624,7 +623,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
if (!res)
tdc_remove_table(thd, TDC_RT_REMOVE_ALL, view->db, view->table_name, false);
- if (mysql_bin_log.is_open())
+ if (!res && mysql_bin_log.is_open())
{
String buff;
const LEX_STRING command[3]=
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index d6b3fa41c78..7aaa8d31ee5 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -76,7 +76,7 @@ int yylex(void *yylval, void *yythd);
ulong val= *(F); \
if (my_yyoverflow((B), (D), &val)) \
{ \
- yyerror(current_thd, (char*) (A)); \
+ yyerror(thd, (char*) (A)); \
return 2; \
} \
else \
@@ -6296,7 +6296,8 @@ spatial_type:
| GEOMETRYCOLLECTION { $$= Field::GEOM_GEOMETRYCOLLECTION; }
| POINT_SYM
{
- Lex->length= (char*)"25";
+ Lex->length= const_cast<char*>(STRINGIFY_ARG
+ (MAX_LEN_GEOM_POINT_FIELD));
$$= Field::GEOM_POINT;
}
| MULTIPOINT { $$= Field::GEOM_MULTIPOINT; }
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 24e64ed5756..9a38b2269ac 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002, 2013, Oracle and/or its affiliates.
+/* Copyright (c) 2002, 2014, Oracle and/or its affiliates.
Copyright (c) 2012, 2014, SkySQL Ab.
This program is free software; you can redistribute it and/or modify
@@ -3244,9 +3244,10 @@ static Sys_var_ulonglong Sys_tmp_table_size(
static Sys_var_mybool Sys_timed_mutexes(
"timed_mutexes",
- "Specify whether to time mutexes (only InnoDB mutexes are currently "
- "supported)",
- GLOBAL_VAR(timed_mutexes), CMD_LINE(OPT_ARG), DEFAULT(0));
+ "Specify whether to time mutexes. Deprecated, has no effect.",
+ GLOBAL_VAR(timed_mutexes), CMD_LINE(OPT_ARG), DEFAULT(0),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(NULL), ON_UPDATE(NULL),
+ DEPRECATED(""));
static char *server_version_ptr;
static Sys_var_charptr Sys_version(
diff --git a/sql/table.cc b/sql/table.cc
index 23761e02831..c951351fba8 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -1774,13 +1774,25 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
key_part= keyinfo->key_part;
for (i=0 ; i < keyinfo->user_defined_key_parts ;i++)
{
- uint fieldnr= key_part[i].fieldnr;
- if (!fieldnr ||
- share->field[fieldnr-1]->null_ptr ||
- share->field[fieldnr-1]->key_length() !=
- key_part[i].length)
+ DBUG_ASSERT(key_part[i].fieldnr > 0);
+ // Table field corresponding to the i'th key part.
+ Field *table_field= share->field[key_part[i].fieldnr - 1];
+
+ /*
+ If the key column is of NOT NULL BLOB type, then it
+ will definitly have key prefix. And if key part prefix size
+ is equal to the BLOB column max size, then we can promote
+ it to primary key.
+ */
+ if (!table_field->real_maybe_null() &&
+ table_field->type() == MYSQL_TYPE_BLOB &&
+ table_field->field_length == key_part[i].length)
+ continue;
+
+ if (table_field->real_maybe_null() ||
+ table_field->key_length() != key_part[i].length)
{
- primary_key=MAX_KEY; // Can't be used
+ primary_key= MAX_KEY; // Can't be used
break;
}
}
@@ -4210,7 +4222,8 @@ bool TABLE_LIST::create_field_translation(THD *thd)
while ((item= it++))
{
- transl[field_count].name= item->name;
+ DBUG_ASSERT(item->name && item->name[0]);
+ transl[field_count].name= thd->strdup(item->name);
transl[field_count++].item= item;
}
field_translation= transl;