summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/examples/ha_tina.cc101
-rw-r--r--sql/field.cc4
-rw-r--r--sql/ha_federated.cc8
-rw-r--r--sql/ha_innodb.cc8
-rw-r--r--sql/handler.cc49
-rw-r--r--sql/handler.h1
-rw-r--r--sql/item.cc7
-rw-r--r--sql/item_cmpfunc.cc17
-rw-r--r--sql/item_cmpfunc.h6
-rw-r--r--sql/item_func.cc14
-rw-r--r--sql/item_func.h5
-rw-r--r--sql/item_strfunc.h5
-rw-r--r--sql/item_sum.cc37
-rw-r--r--sql/item_sum.h25
-rw-r--r--sql/item_timefunc.cc13
-rw-r--r--sql/item_timefunc.h1
-rw-r--r--sql/log.cc213
-rw-r--r--sql/my_decimal.cc2
-rw-r--r--sql/mysql_priv.h5
-rw-r--r--sql/mysqld.cc5
-rw-r--r--sql/nt_servc.cc12
-rw-r--r--sql/nt_servc.h14
-rw-r--r--sql/opt_range.cc2
-rw-r--r--sql/opt_sum.cc6
-rw-r--r--sql/set_var.cc67
-rw-r--r--sql/set_var.h47
-rw-r--r--sql/sql_base.cc3
-rw-r--r--sql/sql_class.h7
-rw-r--r--sql/sql_cursor.cc18
-rw-r--r--sql/sql_select.cc41
-rw-r--r--sql/sql_show.cc28
-rw-r--r--sql/sql_table.cc4
-rw-r--r--sql/sql_update.cc26
-rw-r--r--sql/sql_view.cc13
-rw-r--r--sql/tztime.cc22
-rw-r--r--sql/tztime.h3
36 files changed, 635 insertions, 204 deletions
diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc
index 0b57fe86e62..aaaa3b8ffb4 100644
--- a/sql/examples/ha_tina.cc
+++ b/sql/examples/ha_tina.cc
@@ -416,37 +416,96 @@ int ha_tina::find_current_row(byte *buf)
if ((end_ptr= find_eoln(share->mapped_file, current_position, share->file_stat.st_size)) == 0)
DBUG_RETURN(HA_ERR_END_OF_FILE);
+ /*
+ Parse the line obtained using the following algorithm
+
+ BEGIN
+ 1) Store the EOL (end of line) for the current row
+ 2) Until all the fields in the current query have not been
+ filled
+ 2.1) If the current character begins with a quote
+ 2.1.1) Until EOL has not been reached
+ a) If end of current field is reached, move
+ to next field and jump to step 2.3
+ b) If current character begins with \\ handle
+ \\n, \\r, \\, \\"
+ c) else append the current character into the buffer
+ before checking that EOL has not been reached.
+ 2.2) If the current character does not begin with a quote
+ 2.2.1) Until EOL has not been reached
+ a) If the end of field has been reached move to the
+ next field and jump to step 2.3
+ b) append the current character into the buffer
+ 2.3) Store the current field value and jump to 2)
+ TERMINATE
+ */
+
for (Field **field=table->field ; *field ; field++)
{
buffer.length(0);
- mapped_ptr++; // Increment past the first quote
- for(;mapped_ptr != end_ptr; mapped_ptr++)
+ /* Handle the case where the first character begins with a quote */
+ if (*mapped_ptr == '"')
{
- //Need to convert line feeds!
- if (*mapped_ptr == '"' &&
- (((mapped_ptr[1] == ',') && (mapped_ptr[2] == '"')) || (mapped_ptr == end_ptr -1 )))
+ /* Increment past the first quote */
+ mapped_ptr++;
+ /* Loop through the row to extract the values for the current field */
+ for(; mapped_ptr != end_ptr; mapped_ptr++)
{
- mapped_ptr += 2; // Move past the , and the "
- break;
- }
- if (*mapped_ptr == '\\' && mapped_ptr != (end_ptr - 1))
- {
- mapped_ptr++;
- if (*mapped_ptr == 'r')
- buffer.append('\r');
- else if (*mapped_ptr == 'n' )
- buffer.append('\n');
- else if ((*mapped_ptr == '\\') || (*mapped_ptr == '"'))
- buffer.append(*mapped_ptr);
- else /* This could only happed with an externally created file */
+ /* check for end of the current field */
+ if (*mapped_ptr == '"' &&
+ (mapped_ptr[1] == ',' || mapped_ptr == end_ptr -1 ))
{
- buffer.append('\\');
+ /* Move past the , and the " */
+ mapped_ptr += 2;
+ break;
+ }
+ if (*mapped_ptr == '\\' && mapped_ptr != (end_ptr - 1))
+ {
+ mapped_ptr++;
+ if (*mapped_ptr == 'r')
+ buffer.append('\r');
+ else if (*mapped_ptr == 'n' )
+ buffer.append('\n');
+ else if ((*mapped_ptr == '\\') || (*mapped_ptr == '"'))
+ buffer.append(*mapped_ptr);
+ else /* This could only happed with an externally created file */
+ {
+ buffer.append('\\');
+ buffer.append(*mapped_ptr);
+ }
+ }
+ else
+ {
+ /*
+ If no last quote was found, but the end of row has been reached
+ it implies that there has been error.
+ */
+ if (mapped_ptr == end_ptr -1)
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+ /* Store current character in the buffer for the field */
buffer.append(*mapped_ptr);
}
- }
- else
+ }
+ }
+ else
+ {
+ /* Handle the case where the current row does not start with quotes */
+
+ /* Loop through the row to extract the values for the current field */
+ for (; mapped_ptr != end_ptr; mapped_ptr++)
+ {
+ /* check for end of current field */
+ if (*mapped_ptr == ',')
+ {
+ /* Increment past the current comma */
+ mapped_ptr++;
+ break;
+ }
+ /* store the current character in the buffer for the field */
buffer.append(*mapped_ptr);
+ }
}
+ /* Store the field value from the buffer */
(*field)->store(buffer.ptr(), buffer.length(), buffer.charset());
}
next_position= (end_ptr - share->mapped_file)+1;
diff --git a/sql/field.cc b/sql/field.cc
index 3d3f698f912..f8ab4b852ec 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -3473,7 +3473,7 @@ int Field_longlong::store(double nr)
error= 1;
}
else
- res=(longlong) (ulonglong) nr;
+ res=(longlong) double2ulonglong(nr);
}
else
{
@@ -5372,6 +5372,7 @@ int Field_newdate::store_time(MYSQL_TIME *ltime, timestamp_type time_type)
{
char buff[MAX_DATE_STRING_REP_LENGTH];
String str(buff, sizeof(buff), &my_charset_latin1);
+ tmp= 0;
make_date((DATE_TIME_FORMAT *) 0, ltime, &str);
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED,
str.ptr(), str.length(), MYSQL_TIMESTAMP_DATE, 1);
@@ -5608,6 +5609,7 @@ int Field_datetime::store_time(MYSQL_TIME *ltime,timestamp_type time_type)
{
char buff[MAX_DATE_STRING_REP_LENGTH];
String str(buff, sizeof(buff), &my_charset_latin1);
+ tmp= 0;
make_datetime((DATE_TIME_FORMAT *) 0, ltime, &str);
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED,
str.ptr(), str.length(), MYSQL_TIMESTAMP_DATETIME,1);
diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc
index b4788dd9c87..d4144a41a2a 100644
--- a/sql/ha_federated.cc
+++ b/sql/ha_federated.cc
@@ -1320,6 +1320,14 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table)
thr_lock_init(&share->lock);
pthread_mutex_init(&share->mutex, MY_MUTEX_INIT_FAST);
}
+ else
+ {
+ /*
+ Free tmp_share.scheme allocated in the parse_url()
+ as we found share in the hash and tmp_share isn't needed anymore.
+ */
+ my_free((gptr) tmp_share.scheme, MYF(MY_ALLOW_ZERO_PTR));
+ }
share->use_count++;
pthread_mutex_unlock(&federated_mutex);
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index 1c0f8a6e9b3..83e2d025f18 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -2158,6 +2158,14 @@ ha_innobase::open(
UT_NOT_USED(test_if_locked);
thd = current_thd;
+
+ /* Under some cases MySQL seems to call this function while
+ holding btr_search_latch. This breaks the latching order as
+ we acquire dict_sys->mutex below and leads to a deadlock. */
+ if (thd != NULL) {
+ innobase_release_temporary_latches(thd);
+ }
+
normalize_table_name(norm_name, name);
user_thd = NULL;
diff --git a/sql/handler.cc b/sql/handler.cc
index 67ec5f3e759..71d184ad84b 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -1957,8 +1957,53 @@ bool handler::get_error_message(int error, String* buf)
}
+/**
+ Check for incompatible collation changes.
+
+ @retval
+ HA_ADMIN_NEEDS_UPGRADE Table may have data requiring upgrade.
+ @retval
+ 0 No upgrade required.
+*/
+
+int handler::check_collation_compatibility()
+{
+ ulong mysql_version= table->s->mysql_version;
+
+ if (mysql_version < 50048)
+ {
+ KEY *key= table->key_info;
+ KEY *key_end= key + table->s->keys;
+ for (; key < key_end; key++)
+ {
+ KEY_PART_INFO *key_part= key->key_part;
+ KEY_PART_INFO *key_part_end= key_part + key->key_parts;
+ for (; key_part < key_part_end; key_part++)
+ {
+ if (!key_part->fieldnr)
+ continue;
+ Field *field= table->field[key_part->fieldnr - 1];
+ uint cs_number= field->charset()->number;
+ if (mysql_version < 50048 &&
+ (cs_number == 11 || /* ascii_general_ci - bug #29499, bug #27562 */
+ cs_number == 41 || /* latin7_general_ci - bug #29461 */
+ cs_number == 42 || /* latin7_general_cs - bug #29461 */
+ cs_number == 20 || /* latin7_estonian_cs - bug #29461 */
+ cs_number == 21 || /* latin2_hungarian_ci - bug #29461 */
+ cs_number == 22 || /* koi8u_general_ci - bug #29461 */
+ cs_number == 23 || /* cp1251_ukrainian_ci - bug #29461 */
+ cs_number == 26)) /* cp1250_general_ci - bug #29461 */
+ return HA_ADMIN_NEEDS_UPGRADE;
+ }
+ }
+ }
+ return 0;
+}
+
+
int handler::ha_check_for_upgrade(HA_CHECK_OPT *check_opt)
{
+ int error;
KEY *keyinfo, *keyend;
KEY_PART_INFO *keypart, *keypartend;
@@ -1987,6 +2032,10 @@ int handler::ha_check_for_upgrade(HA_CHECK_OPT *check_opt)
}
if (table->s->frm_version != FRM_VER_TRUE_VARCHAR)
return HA_ADMIN_NEEDS_ALTER;
+
+ if ((error= check_collation_compatibility()))
+ return error;
+
return check_for_upgrade(check_opt);
}
diff --git a/sql/handler.h b/sql/handler.h
index aa3377c3868..8706aae5fce 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -787,6 +787,7 @@ protected:
virtual int check_for_upgrade(HA_CHECK_OPT *check_opt)
{ return 0; }
public:
+ int check_collation_compatibility();
int ha_check_for_upgrade(HA_CHECK_OPT *check_opt);
int check_old_types();
/* to be actually called to get 'check()' functionality*/
diff --git a/sql/item.cc b/sql/item.cc
index 182f4abdfe6..2a89c86cd88 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -4950,6 +4950,9 @@ int Item_hex_string::save_in_field(Field *field, bool no_conversions)
ulonglong nr;
uint32 length= str_value.length();
+ if (!length)
+ return 1;
+
if (length > 8)
{
nr= field->flags & UNSIGNED_FLAG ? ULONGLONG_MAX : LONGLONG_MAX;
@@ -6792,7 +6795,7 @@ enum_field_types Item_type_holder::get_real_type(Item *item)
*/
Item_sum *item_sum= (Item_sum *) item;
if (item_sum->keep_field_type())
- return get_real_type(item_sum->args[0]);
+ return get_real_type(item_sum->get_arg(0));
break;
}
case FUNC_ITEM:
@@ -7056,7 +7059,7 @@ void Item_type_holder::get_full_info(Item *item)
if (item->type() == Item::SUM_FUNC_ITEM &&
(((Item_sum*)item)->sum_func() == Item_sum::MAX_FUNC ||
((Item_sum*)item)->sum_func() == Item_sum::MIN_FUNC))
- item = ((Item_sum*)item)->args[0];
+ item = ((Item_sum*)item)->get_arg(0);
/*
We can have enum/set type after merging only if we have one enum|set
field (or MIN|MAX(enum|set field)) and number of NULL fields
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 0410c781590..3b1d18b4252 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -745,11 +745,11 @@ Arg_comparator::can_compare_as_dates(Item *a, Item *b, ulonglong *const_value)
obtained value
*/
-ulonglong
+longlong
get_time_value(THD *thd, Item ***item_arg, Item **cache_arg,
Item *warn_item, bool *is_null)
{
- ulonglong value;
+ longlong value;
Item *item= **item_arg;
MYSQL_TIME ltime;
@@ -761,7 +761,7 @@ get_time_value(THD *thd, Item ***item_arg, Item **cache_arg,
else
{
*is_null= item->get_time(&ltime);
- value= !*is_null ? TIME_to_ulonglong_datetime(&ltime) : 0;
+ value= !*is_null ? (longlong) TIME_to_ulonglong_datetime(&ltime) : 0;
}
/*
Do not cache GET_USER_VAR() function as its const_item() may return TRUE
@@ -886,11 +886,11 @@ void Arg_comparator::set_datetime_cmp_func(Item **a1, Item **b1)
obtained value
*/
-ulonglong
+longlong
get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg,
Item *warn_item, bool *is_null)
{
- ulonglong value= 0;
+ longlong value= 0;
String buf, *str= 0;
Item *item= **item_arg;
@@ -925,7 +925,7 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg,
enum_field_types f_type= warn_item->field_type();
timestamp_type t_type= f_type ==
MYSQL_TYPE_DATE ? MYSQL_TIMESTAMP_DATE : MYSQL_TIMESTAMP_DATETIME;
- value= get_date_from_str(thd, str, t_type, warn_item->name, &error);
+ value= (longlong) get_date_from_str(thd, str, t_type, warn_item->name, &error);
/*
If str did not contain a valid date according to the current
SQL_MODE, get_date_from_str() has already thrown a warning,
@@ -979,7 +979,7 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg,
int Arg_comparator::compare_datetime()
{
bool a_is_null, b_is_null;
- ulonglong a_value, b_value;
+ longlong a_value, b_value;
/* Get DATE/DATETIME/TIME value of the 'a' item. */
a_value= (*get_value_func)(thd, &a, &a_cache, *b, &a_is_null);
@@ -1434,7 +1434,8 @@ bool Item_in_optimizer::fix_left(THD *thd, Item **ref)
}
not_null_tables_cache= args[0]->not_null_tables();
with_sum_func= args[0]->with_sum_func;
- const_item_cache= args[0]->const_item();
+ if ((const_item_cache= args[0]->const_item()))
+ cache->store(args[0]);
return 0;
}
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 1bd60ff37d9..db831c7030c 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -42,8 +42,8 @@ class Arg_comparator: public Sql_alloc
bool is_nulls_eq; // TRUE <=> compare for the EQUAL_FUNC
enum enum_date_cmp_type { CMP_DATE_DFLT= 0, CMP_DATE_WITH_DATE,
CMP_DATE_WITH_STR, CMP_STR_WITH_DATE };
- ulonglong (*get_value_func)(THD *thd, Item ***item_arg, Item **cache_arg,
- Item *warn_item, bool *is_null);
+ longlong (*get_value_func)(THD *thd, Item ***item_arg, Item **cache_arg,
+ Item *warn_item, bool *is_null);
public:
DTCollation cmp_collation;
@@ -1028,7 +1028,7 @@ public:
*/
class cmp_item_datetime :public cmp_item
{
- ulonglong value;
+ longlong value;
public:
THD *thd;
/* Item used for issuing warnings. */
diff --git a/sql/item_func.cc b/sql/item_func.cc
index e663e1fcf83..c0d08d9b213 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -1316,8 +1316,10 @@ my_decimal *Item_func_div::decimal_op(my_decimal *decimal_value)
void Item_func_div::result_precision()
{
- uint arg_prec= args[0]->decimal_precision() + prec_increment;
- uint precision=min(arg_prec, DECIMAL_MAX_PRECISION);
+ uint precision=min(args[0]->decimal_precision() +
+ args[1]->decimals + prec_increment,
+ DECIMAL_MAX_PRECISION);
+
/* 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;
@@ -2273,7 +2275,7 @@ void Item_func_min_max::fix_length_and_dec()
uint Item_func_min_max::cmp_datetimes(ulonglong *value)
{
- ulonglong min_max;
+ longlong min_max;
uint min_max_idx= 0;
LINT_INIT(min_max);
@@ -2281,7 +2283,7 @@ uint Item_func_min_max::cmp_datetimes(ulonglong *value)
{
Item **arg= args + i;
bool is_null;
- ulonglong res= get_datetime_value(thd, &arg, 0, datetime_item, &is_null);
+ longlong res= get_datetime_value(thd, &arg, 0, datetime_item, &is_null);
if ((null_value= args[i]->null_value))
return 0;
if (i == 0 || (res < min_max ? cmp_sign : -cmp_sign) > 0)
@@ -5022,7 +5024,9 @@ bool Item_func_match::fix_index()
for (keynr=0 ; keynr < table->s->keys ; keynr++)
{
if ((table->key_info[keynr].flags & HA_FULLTEXT) &&
- (table->s->keys_in_use.is_set(keynr)))
+ (flags & FT_BOOL ? table->keys_in_use_for_query.is_set(keynr) :
+ table->s->keys_in_use.is_set(keynr)))
+
{
ft_to_key[fts]=keynr;
ft_cnt[fts]=0;
diff --git a/sql/item_func.h b/sql/item_func.h
index 6dcf32cba07..89c841abb75 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -351,7 +351,10 @@ public:
Item_func_unsigned(Item *a) :Item_func_signed(a) {}
const char *func_name() const { return "cast_as_unsigned"; }
void fix_length_and_dec()
- { max_length=args[0]->max_length; unsigned_flag=1; }
+ {
+ max_length= min(args[0]->max_length, DECIMAL_MAX_PRECISION + 2);
+ unsigned_flag=1;
+ }
longlong val_int();
void print(String *str);
};
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 3648438a69b..23ac20a4017 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -516,8 +516,9 @@ public:
{
collation.set(default_charset());
uint char_length= args[0]->max_length/args[0]->collation.collation->mbmaxlen;
- max_length= ((char_length + (char_length-args[0]->decimals)/3) *
- collation.collation->mbmaxlen);
+ uint max_sep_count= char_length/3 + (decimals ? 1 : 0) + /*sign*/1;
+ max_length= (char_length + max_sep_count + decimals) *
+ collation.collation->mbmaxlen;
}
const char *func_name() const { return "format"; }
void print(String *);
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 91320d6b56b..d33d92a5238 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -370,6 +370,10 @@ Item_sum::Item_sum(List<Item> &list) :arg_count(list.elements),
args[i++]= item;
}
}
+ if (!(orig_args= (Item **) sql_alloc(sizeof(Item *) * arg_count)))
+ {
+ args= NULL;
+ }
mark_as_sum_func();
list.empty(); // Fields are used
}
@@ -380,18 +384,28 @@ Item_sum::Item_sum(List<Item> &list) :arg_count(list.elements),
*/
Item_sum::Item_sum(THD *thd, Item_sum *item):
- Item_result_field(thd, item), arg_count(item->arg_count),
+ Item_result_field(thd, item),
aggr_sel(item->aggr_sel),
nest_level(item->nest_level), aggr_level(item->aggr_level),
- quick_group(item->quick_group), used_tables_cache(item->used_tables_cache),
+ quick_group(item->quick_group),
+ arg_count(item->arg_count), orig_args(NULL),
+ used_tables_cache(item->used_tables_cache),
forced_const(item->forced_const)
{
if (arg_count <= 2)
+ {
args=tmp_args;
+ orig_args=tmp_orig_args;
+ }
else
+ {
if (!(args= (Item**) thd->alloc(sizeof(Item*)*arg_count)))
return;
+ if (!(orig_args= (Item**) thd->alloc(sizeof(Item*)*arg_count)))
+ return;
+ }
memcpy(args, item->args, sizeof(Item*)*arg_count);
+ memcpy(orig_args, item->orig_args, sizeof(Item*)*arg_count);
}
@@ -426,12 +440,13 @@ void Item_sum::make_field(Send_field *tmp_field)
void Item_sum::print(String *str)
{
+ Item **pargs= orig_args;
str->append(func_name());
for (uint i=0 ; i < arg_count ; i++)
{
if (i)
str->append(',');
- args[i]->print(str);
+ pargs[i]->print(str);
}
str->append(')');
}
@@ -532,6 +547,13 @@ void Item_sum::update_used_tables ()
}
+Item *Item_sum::set_arg(int i, THD *thd, Item *new_val)
+{
+ thd->change_item_tree(args + i, new_val);
+ return new_val;
+}
+
+
String *
Item_sum_num::val_str(String *str)
{
@@ -583,6 +605,7 @@ Item_sum_num::fix_fields(THD *thd, Item **ref)
if (check_sum_func(thd, ref))
return TRUE;
+ memcpy (orig_args, args, sizeof (Item *) * arg_count);
fixed= 1;
return FALSE;
}
@@ -670,6 +693,7 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
if (check_sum_func(thd, ref))
return TRUE;
+ orig_args[0]= args[0];
fixed= 1;
return FALSE;
}
@@ -3107,6 +3131,12 @@ Item_func_group_concat(Name_resolution_context *context_arg,
sizeof(ORDER*)*arg_count_order)))
return;
+ if (!(orig_args= (Item **) sql_alloc(sizeof(Item *) * arg_count)))
+ {
+ args= NULL;
+ return;
+ }
+
order= (ORDER**)(args + arg_count);
/* fill args items of show and sort */
@@ -3334,6 +3364,7 @@ Item_func_group_concat::fix_fields(THD *thd, Item **ref)
if (check_sum_func(thd, ref))
return TRUE;
+ memcpy (orig_args, args, sizeof (Item *) * arg_count);
fixed= 1;
return FALSE;
}
diff --git a/sql/item_sum.h b/sql/item_sum.h
index d39fc96e254..51a1eff9bbf 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -228,10 +228,8 @@ public:
VARIANCE_FUNC, SUM_BIT_FUNC, UDF_SUM_FUNC, GROUP_CONCAT_FUNC
};
- Item **args, *tmp_args[2];
Item **ref_by; /* pointer to a ref to the object used to register it */
Item_sum *next; /* next in the circular chain of registered objects */
- uint arg_count;
Item_sum *in_sum_func; /* embedding set function if any */
st_select_lex * aggr_sel; /* select where the function is aggregated */
int8 nest_level; /* number of the nesting level of the set function */
@@ -248,24 +246,32 @@ public:
List<Item_field> outer_fields;
protected:
+ uint arg_count;
+ Item **args, *tmp_args[2];
+ /*
+ Copy of the arguments list to hold the original set of arguments.
+ Used in EXPLAIN EXTENDED instead of the current argument list because
+ the current argument list can be altered by usage of temporary tables.
+ */
+ Item **orig_args, *tmp_orig_args[2];
table_map used_tables_cache;
bool forced_const;
public:
void mark_as_sum_func();
- Item_sum() :arg_count(0), quick_group(1), forced_const(FALSE)
+ Item_sum() :quick_group(1), arg_count(0), forced_const(FALSE)
{
mark_as_sum_func();
}
- Item_sum(Item *a) :args(tmp_args), arg_count(1), quick_group(1),
- forced_const(FALSE)
+ Item_sum(Item *a) :quick_group(1), arg_count(1), args(tmp_args),
+ orig_args(tmp_orig_args), forced_const(FALSE)
{
args[0]=a;
mark_as_sum_func();
}
- Item_sum( Item *a, Item *b ) :args(tmp_args), arg_count(2), quick_group(1),
- forced_const(FALSE)
+ Item_sum( Item *a, Item *b ) :quick_group(1), arg_count(2), args(tmp_args),
+ orig_args(tmp_orig_args), forced_const(FALSE)
{
args[0]=a; args[1]=b;
mark_as_sum_func();
@@ -374,6 +380,10 @@ public:
bool register_sum_func(THD *thd, Item **ref);
st_select_lex *depended_from()
{ return (nest_level == aggr_level ? 0 : aggr_sel); }
+
+ Item *get_arg(int i) { return args[i]; }
+ Item *set_arg(int i, THD *thd, Item *new_val);
+ uint get_arg_count() { return arg_count; }
};
@@ -981,6 +991,7 @@ public:
if (udf.fix_fields(thd, this, this->arg_count, this->args))
return TRUE;
+ memcpy (orig_args, args, sizeof (Item *) * arg_count);
return check_sum_func(thd, ref);
}
enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 0cb3c963dad..e9e92952908 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -2550,6 +2550,8 @@ void Item_char_typecast::fix_length_and_dec()
and thus avoid unnecessary character set conversion.
- If the argument is not a number, then from_cs is set to
the argument's charset.
+
+ Note (TODO): we could use repertoire technique here.
*/
from_cs= (args[0]->result_type() == INT_RESULT ||
args[0]->result_type() == DECIMAL_RESULT ||
@@ -2557,12 +2559,13 @@ void Item_char_typecast::fix_length_and_dec()
(cast_cs->mbminlen == 1 ? cast_cs : &my_charset_latin1) :
args[0]->collation.collation;
charset_conversion= (cast_cs->mbmaxlen > 1) ||
- !my_charset_same(from_cs, cast_cs) &&
- from_cs != &my_charset_bin &&
- cast_cs != &my_charset_bin;
+ (!my_charset_same(from_cs, cast_cs) &&
+ from_cs != &my_charset_bin &&
+ cast_cs != &my_charset_bin);
collation.set(cast_cs, DERIVATION_IMPLICIT);
- char_length= (cast_length >= 0) ? cast_length :
- args[0]->max_length/from_cs->mbmaxlen;
+ char_length= (cast_length >= 0) ?
+ cast_length :
+ args[0]->max_length / args[0]->collation.collation->mbmaxlen;
max_length= char_length * cast_cs->mbmaxlen;
}
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 7960c03d2e5..81a6c3e98bd 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -408,6 +408,7 @@ public:
{
return save_time_in_field(field);
}
+ bool result_as_longlong() { return TRUE; }
};
diff --git a/sql/log.cc b/sql/log.cc
index 5a1cfe46686..c411f7c8238 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -417,6 +417,7 @@ MYSQL_LOG::MYSQL_LOG()
index_file_name[0] = 0;
bzero((char*) &log_file,sizeof(log_file));
bzero((char*) &index_file, sizeof(index_file));
+ bzero((char*) &purge_temp, sizeof(purge_temp));
}
/* this is called only once */
@@ -1059,10 +1060,10 @@ err:
IMPLEMENTATION
- Protects index file with LOCK_index
+ - Read the next file name from the index file and store in rli->linfo
- Delete relevant relay log files
- Copy all file names after these ones to the front of the index file
- If the OS has truncate, truncate the file, else fill it with \n'
- - Read the next file name from the index file and store in rli->linfo
RETURN VALUES
0 ok
@@ -1076,6 +1077,7 @@ err:
int MYSQL_LOG::purge_first_log(struct st_relay_log_info* rli, bool included)
{
int error;
+ char *to_purge_if_included= NULL;
DBUG_ENTER("purge_first_log");
DBUG_ASSERT(is_open());
@@ -1083,36 +1085,20 @@ int MYSQL_LOG::purge_first_log(struct st_relay_log_info* rli, bool included)
DBUG_ASSERT(!strcmp(rli->linfo.log_file_name,rli->event_relay_log_name));
pthread_mutex_lock(&LOCK_index);
- pthread_mutex_lock(&rli->log_space_lock);
- rli->relay_log.purge_logs(rli->group_relay_log_name, included,
- 0, 0, &rli->log_space_total);
- // Tell the I/O thread to take the relay_log_space_limit into account
- rli->ignore_log_space_limit= 0;
- pthread_mutex_unlock(&rli->log_space_lock);
+ to_purge_if_included= my_strdup(rli->group_relay_log_name, MYF(0));
/*
- Ok to broadcast after the critical region as there is no risk of
- the mutex being destroyed by this thread later - this helps save
- context switches
- */
- pthread_cond_broadcast(&rli->log_space_cond);
-
- /*
Read the next log file name from the index file and pass it back to
- the caller
- If included is true, we want the first relay log;
- otherwise we want the one after event_relay_log_name.
+ the caller.
*/
- if ((included && (error=find_log_pos(&rli->linfo, NullS, 0))) ||
- (!included &&
- ((error=find_log_pos(&rli->linfo, rli->event_relay_log_name, 0)) ||
- (error=find_next_log(&rli->linfo, 0)))))
+ if((error=find_log_pos(&rli->linfo, rli->event_relay_log_name, 0)) ||
+ (error=find_next_log(&rli->linfo, 0)))
{
char buff[22];
sql_print_error("next log error: %d offset: %s log: %s included: %d",
error,
llstr(rli->linfo.index_file_offset,buff),
- rli->group_relay_log_name,
+ rli->event_relay_log_name,
included);
goto err;
}
@@ -1140,7 +1126,42 @@ int MYSQL_LOG::purge_first_log(struct st_relay_log_info* rli, bool included)
/* Store where we are in the new file for the execution thread */
flush_relay_log_info(rli);
+ DBUG_EXECUTE_IF("crash_before_purge_logs", abort(););
+
+ pthread_mutex_lock(&rli->log_space_lock);
+ rli->relay_log.purge_logs(to_purge_if_included, included,
+ 0, 0, &rli->log_space_total);
+ // Tell the I/O thread to take the relay_log_space_limit into account
+ rli->ignore_log_space_limit= 0;
+ pthread_mutex_unlock(&rli->log_space_lock);
+
+ /*
+ Ok to broadcast after the critical region as there is no risk of
+ the mutex being destroyed by this thread later - this helps save
+ context switches
+ */
+ pthread_cond_broadcast(&rli->log_space_cond);
+
+ /*
+ * Need to update the log pos because purge logs has been called
+ * after fetching initially the log pos at the begining of the method.
+ */
+ if((error=find_log_pos(&rli->linfo, rli->event_relay_log_name, 0)))
+ {
+ char buff[22];
+ sql_print_error("next log error: %d offset: %s log: %s included: %d",
+ error,
+ llstr(rli->linfo.index_file_offset,buff),
+ rli->group_relay_log_name,
+ included);
+ goto err;
+ }
+
+ /* If included was passed, rli->linfo should be the first entry. */
+ DBUG_ASSERT(!included || rli->linfo.index_file_start_offset == 0);
+
err:
+ my_free(to_purge_if_included, MYF(0));
pthread_mutex_unlock(&LOCK_index);
DBUG_RETURN(error);
}
@@ -1199,8 +1220,36 @@ int MYSQL_LOG::purge_logs(const char *to_log,
if (need_mutex)
pthread_mutex_lock(&LOCK_index);
- if ((error=find_log_pos(&log_info, to_log, 0 /*no mutex*/)))
+ if ((error=find_log_pos(&log_info, to_log, 0 /*no mutex*/)))
+ {
+ sql_print_error("MYSQL_LOG::purge_logs was called with file %s not "
+ "listed in the index.", to_log);
goto err;
+ }
+
+ /*
+ For crash recovery reasons the index needs to be updated before
+ any files are deleted. Move files to be deleted into a temp file
+ to be processed after the index is updated.
+ */
+ if (!my_b_inited(&purge_temp))
+ {
+ if ((error=open_cached_file(&purge_temp, mysql_tmpdir, TEMP_PREFIX,
+ DISK_BUFFER_SIZE, MYF(MY_WME))))
+ {
+ sql_print_error("MYSQL_LOG::purge_logs failed to open purge_temp");
+ goto err;
+ }
+ }
+ else
+ {
+ if ((error=reinit_io_cache(&purge_temp, WRITE_CACHE, 0, 0, 1)))
+ {
+ sql_print_error("MYSQL_LOG::purge_logs failed to reinit purge_temp "
+ "for write");
+ goto err;
+ }
+ }
/*
File name exists in index file; delete until we find this file
@@ -1211,6 +1260,59 @@ int MYSQL_LOG::purge_logs(const char *to_log,
while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) &&
!log_in_use(log_info.log_file_name))
{
+ if ((error=my_b_write(&purge_temp, (byte*)log_info.log_file_name,
+ strlen(log_info.log_file_name))) ||
+ (error=my_b_write(&purge_temp, (byte*)"\n", 1)))
+ {
+ sql_print_error("MYSQL_LOG::purge_logs failed to copy %s to purge_temp",
+ log_info.log_file_name);
+ goto err;
+ }
+
+ if (find_next_log(&log_info, 0) || exit_loop)
+ break;
+ }
+
+ /* We know how many files to delete. Update index file. */
+ if ((error=update_log_index(&log_info, need_update_threads)))
+ {
+ sql_print_error("MSYQL_LOG::purge_logs failed to update the index file");
+ goto err;
+ }
+
+ DBUG_EXECUTE_IF("crash_after_update_index", abort(););
+
+ /* Switch purge_temp for read. */
+ if ((error=reinit_io_cache(&purge_temp, READ_CACHE, 0, 0, 0)))
+ {
+ sql_print_error("MSYQL_LOG::purge_logs failed to reinit purge_temp "
+ "for read");
+ goto err;
+ }
+
+ /* Read each entry from purge_temp and delete the file. */
+ for (;;)
+ {
+ uint length;
+
+ if ((length=my_b_gets(&purge_temp, log_info.log_file_name,
+ FN_REFLEN)) <= 1)
+ {
+ if (purge_temp.error)
+ {
+ error= purge_temp.error;
+ sql_print_error("MSYQL_LOG::purge_logs error %d reading from "
+ "purge_temp", error);
+ goto err;
+ }
+
+ /* Reached EOF */
+ break;
+ }
+
+ /* Get rid of the trailing '\n' */
+ log_info.log_file_name[length-1]= 0;
+
MY_STAT s;
if (!my_stat(log_info.log_file_name, &s, MYF(0)))
{
@@ -1304,17 +1406,10 @@ int MYSQL_LOG::purge_logs(const char *to_log,
}
}
}
- if (find_next_log(&log_info, 0) || exit_loop)
- break;
}
-
- /*
- If we get killed -9 here, the sysadmin would have to edit
- the log index file after restart - otherwise, this should be safe
- */
- error= update_log_index(&log_info, need_update_threads);
err:
+ close_cached_file(&purge_temp);
if (need_mutex)
pthread_mutex_unlock(&LOCK_index);
DBUG_RETURN(error);
@@ -1326,7 +1421,6 @@ err:
SYNOPSIS
purge_logs_before_date()
- thd Thread pointer
before_date Delete all log files before given date.
NOTES
@@ -1343,6 +1437,7 @@ err:
int MYSQL_LOG::purge_logs_before_date(time_t purge_time)
{
int error;
+ char to_log[FN_REFLEN];
LOG_INFO log_info;
MY_STAT stat_area;
THD *thd= current_thd;
@@ -1350,12 +1445,8 @@ int MYSQL_LOG::purge_logs_before_date(time_t purge_time)
DBUG_ENTER("purge_logs_before_date");
pthread_mutex_lock(&LOCK_index);
+ to_log[0]= 0;
- /*
- Delete until we find curren file
- or a file that is used or a file
- that is older than purge_time.
- */
if ((error=find_log_pos(&log_info, NullS, 0 /*no mutex*/)))
goto err;
@@ -1405,54 +1496,18 @@ int MYSQL_LOG::purge_logs_before_date(time_t purge_time)
}
else
{
- if (stat_area.st_mtime >= purge_time)
+ if (stat_area.st_mtime < purge_time)
+ strmake(to_log,
+ log_info.log_file_name,
+ sizeof(log_info.log_file_name));
+ else
break;
- if (my_delete(log_info.log_file_name, MYF(0)))
- {
- if (my_errno == ENOENT)
- {
- /* It's not fatal even if we can't delete a log file */
- if (thd)
- {
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
- log_info.log_file_name);
- }
- sql_print_information("Failed to delete file '%s'",
- log_info.log_file_name);
- my_errno= 0;
- }
- else
- {
- if (thd)
- {
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
- ER_BINLOG_PURGE_FATAL_ERR,
- "a problem with deleting %s; "
- "consider examining correspondence "
- "of your binlog index file "
- "to the actual binlog files",
- log_info.log_file_name);
- }
- else
- {
- sql_print_information("Failed to delete log file '%s'",
- log_info.log_file_name);
- }
- error= LOG_INFO_FATAL;
- goto err;
- }
- }
}
if (find_next_log(&log_info, 0))
break;
}
- /*
- If we get killed -9 here, the sysadmin would have to edit
- the log index file after restart - otherwise, this should be safe
- */
- error= update_log_index(&log_info, 1);
+ error= (to_log[0] ? purge_logs(to_log, 1, 0, 1, (ulonglong *) 0) : 0);
err:
pthread_mutex_unlock(&LOCK_index);
diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc
index 31a5b09370a..a235edbd73c 100644
--- a/sql/my_decimal.cc
+++ b/sql/my_decimal.cc
@@ -216,7 +216,7 @@ my_decimal *date2my_decimal(MYSQL_TIME *ltime, my_decimal *dec)
date = (ltime->year*100L + ltime->month)*100L + ltime->day;
if (ltime->time_type > MYSQL_TIMESTAMP_DATE)
date= ((date*100L + ltime->hour)*100L+ ltime->minute)*100L + ltime->second;
- if (int2my_decimal(E_DEC_FATAL_ERROR, date, FALSE, dec))
+ if (int2my_decimal(E_DEC_FATAL_ERROR, ltime->neg ? -date : date, FALSE, dec))
return dec;
if (ltime->second_part)
{
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 1568f042b7e..520d97b5e9f 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -435,6 +435,7 @@ MY_LOCALE *my_locale_by_number(uint number);
#define UNCACHEABLE_PREPARE 16
/* For uncorrelated SELECT in an UNION with some correlated SELECTs */
#define UNCACHEABLE_UNITED 32
+#define UNCACHEABLE_CHECKOPTION 64
/* Used to check GROUP BY list in the MODE_ONLY_FULL_GROUP_BY mode */
#define UNDEF_POS (-1)
@@ -1556,8 +1557,8 @@ void make_date(const DATE_TIME_FORMAT *format, const MYSQL_TIME *l_time,
String *str);
void make_time(const DATE_TIME_FORMAT *format, const MYSQL_TIME *l_time,
String *str);
-ulonglong get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg,
- Item *warn_item, bool *is_null);
+longlong get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg,
+ Item *warn_item, bool *is_null);
int test_if_number(char *str,int *res,bool allow_wildcards);
void change_byte(byte *,uint,char,char);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index c3e5449b22b..8232cefc880 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -3035,12 +3035,14 @@ static int init_common_variables(const char *conf_file_name, int argc,
sys_init_connect.value_length= strlen(opt_init_connect);
else
sys_init_connect.value=my_strdup("",MYF(0));
+ sys_init_connect.is_os_charset= TRUE;
sys_init_slave.value_length= 0;
if ((sys_init_slave.value= opt_init_slave))
sys_init_slave.value_length= strlen(opt_init_slave);
else
sys_init_slave.value=my_strdup("",MYF(0));
+ sys_init_slave.is_os_charset= TRUE;
if (use_temp_pool && bitmap_init(&temp_pool,0,1024,1))
return 1;
@@ -3840,6 +3842,9 @@ we force server id to 2, but this MySQL server will not act as a slave.");
: mysqld_unix_port),
mysqld_port,
MYSQL_COMPILATION_COMMENT);
+#if defined(_WIN32) && !defined(EMBEDDED_LIBRARY)
+ Service.SetRunning();
+#endif
#if defined(__NT__) || defined(HAVE_SMEM)
handle_connections_methods();
diff --git a/sql/nt_servc.cc b/sql/nt_servc.cc
index a04f284a3de..e570898f373 100644
--- a/sql/nt_servc.cc
+++ b/sql/nt_servc.cc
@@ -245,10 +245,6 @@ void NTService::ServiceMain(DWORD argc, LPTSTR *argv)
if (!pService->StartService())
goto error;
- // Check that the service is now running.
- if (!pService->SetStatus(SERVICE_RUNNING,NO_ERROR, 0, 0, 0))
- goto error;
-
// wait for exit event
WaitForSingleObject (pService->hExitEvent, INFINITE);
@@ -264,6 +260,14 @@ error:
return;
}
+
+void NTService::SetRunning()
+{
+ if (pService)
+ pService->SetStatus(SERVICE_RUNNING,NO_ERROR, 0, 0, 0);
+}
+
+
/* ------------------------------------------------------------------------
StartService() - starts the appliaction thread
-------------------------------------------------------------------------- */
diff --git a/sql/nt_servc.h b/sql/nt_servc.h
index a3c12569114..9b689e434e1 100644
--- a/sql/nt_servc.h
+++ b/sql/nt_servc.h
@@ -56,7 +56,19 @@ class NTService
BOOL IsService(LPCSTR ServiceName);
BOOL got_service_option(char **argv, char *service_option);
BOOL is_super_user();
- void Stop(void); //to be called from app. to stop service
+
+ /*
+ SetRunning() is to be called by the application
+ when initialization completes and it can accept
+ stop request
+ */
+ void SetRunning(void);
+
+ /*
+ Stop() is to be called by the application to stop
+ the service
+ */
+ void Stop(void);
protected:
LPSTR ServiceName;
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 744415fa2fe..ebebfafb5d8 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -7738,7 +7738,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
DBUG_RETURN(NULL);
/* The argument of MIN/MAX. */
- Item *expr= min_max_item->args[0]->real_item();
+ Item *expr= min_max_item->get_arg(0)->real_item();
if (expr->type() == Item::FIELD_ITEM) /* Is it an attribute? */
{
if (! min_max_arg_item)
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index 3fc62d05ae5..39db1344588 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -160,7 +160,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
to the number of rows in the tables if this number is exact and
there are no outer joins.
*/
- if (!conds && !((Item_sum_count*) item)->args[0]->maybe_null &&
+ if (!conds && !((Item_sum_count*) item)->get_arg(0)->maybe_null &&
!outer_tables && is_exact_count)
{
((Item_sum_count*) item)->make_const(count);
@@ -176,7 +176,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
parts of the key is found in the COND, then we can use
indexes to find the key.
*/
- Item *expr=item_sum->args[0];
+ Item *expr=item_sum->get_arg(0);
if (expr->real_item()->type() == Item::FIELD_ITEM)
{
byte key_buff[MAX_KEY_LENGTH];
@@ -319,7 +319,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
parts of the key is found in the COND, then we can use
indexes to find the key.
*/
- Item *expr=item_sum->args[0];
+ Item *expr=item_sum->get_arg(0);
if (expr->real_item()->type() == Item::FIELD_ITEM)
{
byte key_buff[MAX_KEY_LENGTH];
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 6bc19f2e6eb..59741e5683d 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -138,7 +138,7 @@ sys_var_thd_ulong sys_auto_increment_offset("auto_increment_offset",
sys_var_bool_ptr sys_automatic_sp_privileges("automatic_sp_privileges",
&sp_automatic_privileges);
-sys_var_const_str sys_basedir("basedir", mysql_home);
+sys_var_const_os_str sys_basedir("basedir", mysql_home);
sys_var_long_ptr sys_binlog_cache_size("binlog_cache_size",
&binlog_cache_size);
sys_var_thd_ulong sys_bulk_insert_buff_size("bulk_insert_buffer_size",
@@ -151,6 +151,8 @@ sys_var_character_set_client sys_character_set_client("character_set_client");
sys_var_character_set_connection sys_character_set_connection("character_set_connection");
sys_var_character_set_results sys_character_set_results("character_set_results");
sys_var_character_set_filesystem sys_character_set_filesystem("character_set_filesystem");
+sys_var_const_os_str sys_character_sets_dir("character_sets_dir",
+ mysql_charsets_dir);
sys_var_thd_ulong sys_completion_type("completion_type",
&SV::completion_type,
check_completion_type,
@@ -162,7 +164,7 @@ sys_var_long_ptr sys_concurrent_insert("concurrent_insert",
&myisam_concurrent_insert);
sys_var_long_ptr sys_connect_timeout("connect_timeout",
&connect_timeout);
-sys_var_const_str sys_datadir("datadir", mysql_real_data_home);
+sys_var_const_os_str sys_datadir("datadir", mysql_real_data_home);
sys_var_enum sys_delay_key_write("delay_key_write",
&delay_key_write_options,
&delay_key_write_typelib,
@@ -311,6 +313,7 @@ sys_var_thd_ulong sys_optimizer_prune_level("optimizer_prune_level",
&SV::optimizer_prune_level);
sys_var_thd_ulong sys_optimizer_search_depth("optimizer_search_depth",
&SV::optimizer_search_depth);
+sys_var_const_os_str sys_plugin_dir("plugin_dir", opt_plugin_dir);
sys_var_thd_ulong sys_preload_buff_size("preload_buffer_size",
&SV::preload_buff_size);
sys_var_thd_ulong sys_read_buff_size("read_buffer_size",
@@ -338,7 +341,7 @@ sys_var_thd_ulong sys_query_alloc_block_size("query_alloc_block_size",
sys_var_thd_ulong sys_query_prealloc_size("query_prealloc_size",
&SV::query_prealloc_size,
0, fix_thd_mem_root);
-sys_var_readonly sys_tmpdir("tmpdir", OPT_GLOBAL, SHOW_CHAR, get_tmpdir);
+sys_var_readonly_os sys_tmpdir("tmpdir", OPT_GLOBAL, SHOW_CHAR, get_tmpdir);
sys_var_thd_ulong sys_trans_alloc_block_size("transaction_alloc_block_size",
&SV::trans_alloc_block_size,
0, fix_trans_mem_root);
@@ -363,9 +366,11 @@ sys_var_bool_ptr sys_secure_auth("secure_auth", &opt_secure_auth);
sys_var_const_str_ptr sys_secure_file_priv("secure_file_priv",
&opt_secure_file_priv);
sys_var_long_ptr sys_server_id("server_id", &server_id, fix_server_id);
+#ifdef HAVE_REPLICATION
sys_var_bool_ptr sys_slave_compressed_protocol("slave_compressed_protocol",
&opt_slave_compressed_protocol);
-#ifdef HAVE_REPLICATION
+sys_var_const_os_str_ptr sys_slave_load_tmpdir("slave_load_tmpdir",
+ &slave_load_tmpdir);
sys_var_long_ptr sys_slave_net_timeout("slave_net_timeout",
&slave_net_timeout);
sys_var_long_ptr sys_slave_trans_retries("slave_transaction_retries",
@@ -380,17 +385,17 @@ sys_var_thd_sql_mode sys_sql_mode("sql_mode",
#ifdef HAVE_OPENSSL
extern char *opt_ssl_ca, *opt_ssl_capath, *opt_ssl_cert, *opt_ssl_cipher,
*opt_ssl_key;
-sys_var_const_str_ptr sys_ssl_ca("ssl_ca", &opt_ssl_ca);
-sys_var_const_str_ptr sys_ssl_capath("ssl_capath", &opt_ssl_capath);
-sys_var_const_str_ptr sys_ssl_cert("ssl_cert", &opt_ssl_cert);
-sys_var_const_str_ptr sys_ssl_cipher("ssl_cipher", &opt_ssl_cipher);
-sys_var_const_str_ptr sys_ssl_key("ssl_key", &opt_ssl_key);
+sys_var_const_os_str_ptr sys_ssl_ca("ssl_ca", &opt_ssl_ca);
+sys_var_const_os_str_ptr sys_ssl_capath("ssl_capath", &opt_ssl_capath);
+sys_var_const_os_str_ptr sys_ssl_cert("ssl_cert", &opt_ssl_cert);
+sys_var_const_os_str_ptr sys_ssl_cipher("ssl_cipher", &opt_ssl_cipher);
+sys_var_const_os_str_ptr sys_ssl_key("ssl_key", &opt_ssl_key);
#else
-sys_var_const_str sys_ssl_ca("ssl_ca", NULL);
-sys_var_const_str sys_ssl_capath("ssl_capath", NULL);
-sys_var_const_str sys_ssl_cert("ssl_cert", NULL);
-sys_var_const_str sys_ssl_cipher("ssl_cipher", NULL);
-sys_var_const_str sys_ssl_key("ssl_key", NULL);
+sys_var_const_os_str sys_ssl_ca("ssl_ca", NULL);
+sys_var_const_os_str sys_ssl_capath("ssl_capath", NULL);
+sys_var_const_os_str sys_ssl_cert("ssl_cert", NULL);
+sys_var_const_os_str sys_ssl_cipher("ssl_cipher", NULL);
+sys_var_const_os_str sys_ssl_key("ssl_key", NULL);
#endif
sys_var_thd_enum
sys_updatable_views_with_limit("updatable_views_with_limit",
@@ -460,6 +465,14 @@ sys_var_long_ptr sys_innodb_commit_concurrency("innodb_commit_concurrency",
sys_var_long_ptr sys_innodb_flush_log_at_trx_commit(
"innodb_flush_log_at_trx_commit",
&srv_flush_log_at_trx_commit);
+sys_var_const_os_str_ptr sys_innodb_data_file_path("innodb_data_file_path",
+ &innobase_data_file_path);
+sys_var_const_os_str_ptr sys_innodb_data_home_dir("innodb_data_home_dir",
+ &innobase_data_home_dir);
+sys_var_const_os_str_ptr sys_innodb_log_arch_dir("innodb_log_arch_dir",
+ &innobase_log_arch_dir);
+sys_var_const_os_str_ptr sys_innodb_log_group_home_dir("innodb_log_group_home_dir",
+ &innobase_log_group_home_dir);
#endif
/* Condition pushdown to storage engine */
@@ -844,7 +857,7 @@ struct show_var_st init_vars[]= {
{sys_character_set_results.name,(char*) &sys_character_set_results, SHOW_SYS},
{sys_character_set_server.name, (char*) &sys_character_set_server,SHOW_SYS},
{sys_charset_system.name, (char*) &sys_charset_system, SHOW_SYS},
- {"character_sets_dir", mysql_charsets_dir, SHOW_CHAR},
+ {sys_character_sets_dir.name, (char *) &sys_character_sets_dir, SHOW_SYS},
{sys_collation_connection.name,(char*) &sys_collation_connection, SHOW_SYS},
{sys_collation_database.name,(char*) &sys_collation_database, SHOW_SYS},
{sys_collation_server.name,(char*) &sys_collation_server, SHOW_SYS},
@@ -905,8 +918,8 @@ struct show_var_st init_vars[]= {
{"innodb_checksums", (char*) &innobase_use_checksums, SHOW_MY_BOOL},
{sys_innodb_commit_concurrency.name, (char*) &sys_innodb_commit_concurrency, SHOW_SYS},
{sys_innodb_concurrency_tickets.name, (char*) &sys_innodb_concurrency_tickets, SHOW_SYS},
- {"innodb_data_file_path", (char*) &innobase_data_file_path, SHOW_CHAR_PTR},
- {"innodb_data_home_dir", (char*) &innobase_data_home_dir, SHOW_CHAR_PTR},
+ {sys_innodb_data_file_path.name, (char*) &sys_innodb_data_file_path, SHOW_SYS},
+ {sys_innodb_data_home_dir.name, (char*) &sys_innodb_data_home_dir, SHOW_SYS},
{"innodb_adaptive_hash_index", (char*) &innobase_adaptive_hash_index, SHOW_MY_BOOL},
{"innodb_doublewrite", (char*) &innobase_use_doublewrite, SHOW_MY_BOOL},
{sys_innodb_fast_shutdown.name,(char*) &sys_innodb_fast_shutdown, SHOW_SYS},
@@ -917,12 +930,12 @@ struct show_var_st init_vars[]= {
{"innodb_force_recovery", (char*) &innobase_force_recovery, SHOW_LONG },
{"innodb_lock_wait_timeout", (char*) &innobase_lock_wait_timeout, SHOW_LONG },
{"innodb_locks_unsafe_for_binlog", (char*) &innobase_locks_unsafe_for_binlog, SHOW_MY_BOOL},
- {"innodb_log_arch_dir", (char*) &innobase_log_arch_dir, SHOW_CHAR_PTR},
+ {sys_innodb_log_arch_dir.name, (char*) &sys_innodb_log_arch_dir, SHOW_SYS},
{"innodb_log_archive", (char*) &innobase_log_archive, SHOW_MY_BOOL},
{"innodb_log_buffer_size", (char*) &innobase_log_buffer_size, SHOW_LONG },
{"innodb_log_file_size", (char*) &innobase_log_file_size, SHOW_LONGLONG},
{"innodb_log_files_in_group", (char*) &innobase_log_files_in_group, SHOW_LONG},
- {"innodb_log_group_home_dir", (char*) &innobase_log_group_home_dir, SHOW_CHAR_PTR},
+ {sys_innodb_log_group_home_dir.name, (char*) &sys_innodb_log_group_home_dir, SHOW_SYS},
{sys_innodb_max_dirty_pages_pct.name, (char*) &sys_innodb_max_dirty_pages_pct, SHOW_SYS},
{sys_innodb_max_purge_lag.name, (char*) &sys_innodb_max_purge_lag, SHOW_SYS},
{"innodb_mirrored_log_groups", (char*) &innobase_mirrored_log_groups, SHOW_LONG},
@@ -1026,7 +1039,7 @@ struct show_var_st init_vars[]= {
{sys_optimizer_search_depth.name,(char*) &sys_optimizer_search_depth,
SHOW_SYS},
{"pid_file", (char*) pidfile_name, SHOW_CHAR},
- {"plugin_dir", (char*) opt_plugin_dir, SHOW_CHAR},
+ {sys_plugin_dir.name, (char*) &sys_plugin_dir, SHOW_SYS},
{"port", (char*) &mysqld_port, SHOW_INT},
{sys_preload_buff_size.name, (char*) &sys_preload_buff_size, SHOW_SYS},
{"protocol_version", (char*) &protocol_version, SHOW_INT},
@@ -1068,7 +1081,7 @@ struct show_var_st init_vars[]= {
#ifdef HAVE_REPLICATION
{sys_slave_compressed_protocol.name,
(char*) &sys_slave_compressed_protocol, SHOW_SYS},
- {"slave_load_tmpdir", (char*) &slave_load_tmpdir, SHOW_CHAR_PTR},
+ {sys_slave_load_tmpdir.name,(char*) &sys_slave_load_tmpdir, SHOW_SYS},
{sys_slave_net_timeout.name,(char*) &sys_slave_net_timeout, SHOW_SYS},
{"slave_skip_errors", (char*) &slave_error_mask, SHOW_SLAVE_SKIP_ERRORS},
{sys_slave_trans_retries.name,(char*) &sys_slave_trans_retries, SHOW_SYS},
@@ -1175,6 +1188,7 @@ bool update_sys_var_str(sys_var_str *var_str, rw_lock_t *var_mutex,
old_value= var_str->value;
var_str->value= res;
var_str->value_length= new_length;
+ var_str->is_os_charset= FALSE;
rw_unlock(var_mutex);
my_free(old_value, MYF(MY_ALLOW_ZERO_PTR));
return 0;
@@ -1914,11 +1928,11 @@ Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base)
char *str= (char*) value_ptr(thd, var_type, base);
if (str)
tmp= new Item_string(str, strlen(str),
- system_charset_info, DERIVATION_SYSCONST);
+ charset(thd), DERIVATION_SYSCONST);
else
{
tmp= new Item_null();
- tmp->collation.set(system_charset_info, DERIVATION_SYSCONST);
+ tmp->collation.set(charset(thd), DERIVATION_SYSCONST);
}
pthread_mutex_unlock(&LOCK_global_system_variables);
return tmp;
@@ -1930,6 +1944,13 @@ Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base)
}
+CHARSET_INFO *sys_var::charset(THD *thd)
+{
+ return is_os_charset ? thd->variables.character_set_filesystem :
+ system_charset_info;
+}
+
+
bool sys_var_thd_enum::update(THD *thd, set_var *var)
{
if (var->type == OPT_GLOBAL)
diff --git a/sql/set_var.h b/sql/set_var.h
index c37cc400e43..f43d3b75cee 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -46,9 +46,17 @@ public:
sys_after_update_func after_update;
bool no_support_one_shot;
+ /*
+ true if the value is in character_set_filesystem,
+ false otherwise.
+ Note that we can't use a pointer to the charset as the system var is
+ instantiated in global scope and the charset pointers are initialized
+ later.
+ */
+ bool is_os_charset;
sys_var(const char *name_arg, sys_after_update_func func= NULL)
:name(name_arg), after_update(func)
- , no_support_one_shot(1)
+ , no_support_one_shot(1), is_os_charset(FALSE)
{}
virtual ~sys_var() {}
virtual bool check(THD *thd, set_var *var);
@@ -68,6 +76,7 @@ public:
Item *item(THD *thd, enum_var_type type, LEX_STRING *base);
virtual bool is_struct() { return 0; }
virtual bool is_readonly() const { return 0; }
+ CHARSET_INFO *charset(THD *thd);
};
@@ -247,6 +256,17 @@ public:
};
+class sys_var_const_os_str: public sys_var_const_str
+{
+public:
+ sys_var_const_os_str(const char *name_arg, const char *value_arg)
+ :sys_var_const_str(name_arg, value_arg)
+ {
+ is_os_charset= TRUE;
+ }
+};
+
+
class sys_var_const_str_ptr :public sys_var
{
public:
@@ -276,6 +296,17 @@ public:
};
+class sys_var_const_os_str_ptr :public sys_var_const_str_ptr
+{
+public:
+ sys_var_const_os_str_ptr(const char *name_arg, char **value_arg)
+ :sys_var_const_str_ptr(name_arg, value_arg)
+ {
+ is_os_charset= TRUE;
+ }
+};
+
+
class sys_var_enum :public sys_var
{
uint *value;
@@ -791,6 +822,20 @@ public:
bool is_readonly() const { return 1; }
};
+
+class sys_var_readonly_os: public sys_var_readonly
+{
+public:
+ sys_var_readonly_os(const char *name_arg, enum_var_type type,
+ SHOW_TYPE show_type_arg,
+ sys_value_ptr_func value_ptr_func_arg)
+ :sys_var_readonly(name_arg, type, show_type_arg, value_ptr_func_arg)
+ {
+ is_os_charset= TRUE;
+ }
+};
+
+
class sys_var_thd_time_zone :public sys_var_thd
{
public:
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 873a3eac24e..881c6a421e8 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -2102,7 +2102,10 @@ bool reopen_table(TABLE *table,bool locked)
for (key=0 ; key < table->s->keys ; key++)
{
for (part=0 ; part < table->key_info[key].usable_key_parts ; part++)
+ {
table->key_info[key].key_part[part].field->table= table;
+ table->key_info[key].key_part[part].field->orig_table= table;
+ }
}
if (table->triggers)
table->triggers->set_table(table);
diff --git a/sql/sql_class.h b/sql/sql_class.h
index c8d42d44df7..cc7ef7809d4 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -205,6 +205,13 @@ class MYSQL_LOG: public TC_LOG
time_t last_time,query_start;
IO_CACHE log_file;
IO_CACHE index_file;
+ /*
+ purge_temp is a temp file used in purge_logs so that the index file
+ can be updated before deleting files from disk, yielding better crash
+ recovery. It is created on demand the first time purge_logs is called
+ and then reused for subsequent calls. It is cleaned up in cleanup().
+ */
+ IO_CACHE purge_temp;
char *name;
char time_buff[20],db[NAME_LEN+1];
char log_file_name[FN_REFLEN],index_file_name[FN_REFLEN];
diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc
index 16567765ba6..83c60814cf3 100644
--- a/sql/sql_cursor.cc
+++ b/sql/sql_cursor.cc
@@ -85,6 +85,7 @@ class Materialized_cursor: public Server_side_cursor
List<Item> item_list;
ulong fetch_limit;
ulong fetch_count;
+ bool is_rnd_inited;
public:
Materialized_cursor(select_result *result, TABLE *table);
@@ -191,7 +192,11 @@ int mysql_open_cursor(THD *thd, uint flags, select_result *result,
such command is SHOW VARIABLES or SHOW STATUS.
*/
if (rc)
+ {
+ if (result_materialize->materialized_cursor)
+ delete result_materialize->materialized_cursor;
goto err_open;
+ }
if (sensitive_cursor->is_open())
{
@@ -532,7 +537,8 @@ Materialized_cursor::Materialized_cursor(select_result *result_arg,
:Server_side_cursor(&table_arg->mem_root, result_arg),
table(table_arg),
fetch_limit(0),
- fetch_count(0)
+ fetch_count(0),
+ is_rnd_inited(0)
{
fake_unit.init_query();
fake_unit.thd= table->in_use;
@@ -589,11 +595,12 @@ int Materialized_cursor::open(JOIN *join __attribute__((unused)))
THD *thd= fake_unit.thd;
int rc;
Query_arena backup_arena;
-
thd->set_n_backup_active_arena(this, &backup_arena);
/* Create a list of fields and start sequential scan */
- rc= (result->prepare(item_list, &fake_unit) ||
- table->file->ha_rnd_init(TRUE));
+ rc= result->prepare(item_list, &fake_unit);
+ if (!rc && !(rc= table->file->ha_rnd_init(TRUE)))
+ is_rnd_inited= 1;
+
thd->restore_active_arena(this, &backup_arena);
if (rc == 0)
{
@@ -673,7 +680,8 @@ void Materialized_cursor::close()
{
/* Free item_list items */
free_items();
- (void) table->file->ha_rnd_end();
+ if (is_rnd_inited)
+ (void) table->file->ha_rnd_end();
/*
We need to grab table->mem_root to prevent free_tmp_table from freeing:
the cursor object was allocated in this memory.
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 428d1709f94..d2c469f99da 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -390,11 +390,21 @@ inline int setup_without_group(THD *thd, Item **ref_pointer_array,
{
int res;
nesting_map save_allow_sum_func=thd->lex->allow_sum_func ;
+ /*
+ Need to save the value, so we can turn off only the new NON_AGG_FIELD
+ additions coming from the WHERE
+ */
+ uint8 saved_flag= thd->lex->current_select->full_group_by_flag;
DBUG_ENTER("setup_without_group");
thd->lex->allow_sum_func&= ~(1 << thd->lex->current_select->nest_level);
res= setup_conds(thd, tables, leaves, conds);
+ /* it's not wrong to have non-aggregated columns in a WHERE */
+ if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY)
+ thd->lex->current_select->full_group_by_flag= saved_flag |
+ (thd->lex->current_select->full_group_by_flag & ~NON_AGG_FIELD_USED);
+
thd->lex->allow_sum_func|= 1 << thd->lex->current_select->nest_level;
res= res || setup_order(thd, ref_pointer_array, tables, fields, all_fields,
order);
@@ -1589,8 +1599,11 @@ JOIN::exec()
(zero_result_cause?zero_result_cause:"No tables used"));
else
{
- result->send_fields(*columns_list,
- Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
+ if (result->send_fields(*columns_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ {
+ DBUG_VOID_RETURN;
+ }
/*
We have to test for 'conds' here as the WHERE may not be constant
even if we don't have any tables for prepared statements or if
@@ -9434,11 +9447,11 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
}
if (type == Item::SUM_FUNC_ITEM && !group && !save_sum_fields)
{ /* Can't calc group yet */
- ((Item_sum*) item)->result_field=0;
- for (i=0 ; i < ((Item_sum*) item)->arg_count ; i++)
+ Item_sum *sum_item= (Item_sum *) item;
+ sum_item->result_field=0;
+ for (i=0 ; i < sum_item->get_arg_count() ; i++)
{
- Item **argp= ((Item_sum*) item)->args + i;
- Item *arg= *argp;
+ Item *arg= sum_item->get_arg(i);
if (!arg->const_item())
{
uint field_index= (uint) (reg_field - table->field);
@@ -9468,7 +9481,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
string_total_length+= new_field->pack_length();
}
thd->mem_root= mem_root_save;
- thd->change_item_tree(argp, new Item_field(new_field));
+ arg= sum_item->set_arg(i, thd, new Item_field(new_field));
thd->mem_root= &table->mem_root;
if (!(new_field->flags & NOT_NULL_FLAG))
{
@@ -9477,7 +9490,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
new_field->maybe_null() is still false, it will be
changed below. But we have to setup Item_field correctly
*/
- (*argp)->maybe_null=1;
+ arg->maybe_null=1;
}
new_field->query_id= thd->query_id;
}
@@ -13223,6 +13236,7 @@ join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count)
length=0;
for (i=0 ; i < table_count ; i++)
{
+ bool have_bit_fields= FALSE;
uint null_fields=0,used_fields;
Field **f_ptr,*field;
@@ -13237,13 +13251,16 @@ join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count)
length+=field->fill_cache_field(copy);
if (copy->blob_field)
(*blob_ptr++)=copy;
- if (field->maybe_null())
+ if (field->real_maybe_null())
null_fields++;
+ if (field->type() == MYSQL_TYPE_BIT &&
+ ((Field_bit*)field)->bit_len)
+ have_bit_fields= TRUE;
copy++;
}
}
/* Copy null bits from table */
- if (null_fields && tables[i].table->s->null_fields)
+ if (null_fields || have_bit_fields)
{ /* must copy null bits */
copy->str=(char*) tables[i].table->null_flags;
copy->length= tables[i].table->s->null_bytes;
@@ -13908,9 +13925,9 @@ count_field_types(SELECT_LEX *select_lex, TMP_TABLE_PARAM *param,
param->quick_group=0; // UDF SUM function
param->sum_func_count++;
- for (uint i=0 ; i < sum_item->arg_count ; i++)
+ for (uint i=0 ; i < sum_item->get_arg_count() ; i++)
{
- if (sum_item->args[0]->real_item()->type() == Item::FIELD_ITEM)
+ if (sum_item->get_arg(i)->real_item()->type() == Item::FIELD_ITEM)
param->field_count++;
else
param->func_count++;
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 5a4772e9847..59082e0a295 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -798,7 +798,7 @@ static bool get_field_default_value(THD *thd, TABLE *table,
{
bool has_default;
bool has_now_default;
-
+ enum enum_field_types field_type= field->type();
/*
We are using CURRENT_TIMESTAMP instead of NOW because it is
more standard
@@ -806,7 +806,7 @@ static bool get_field_default_value(THD *thd, TABLE *table,
has_now_default= table->timestamp_field == field &&
field->unireg_check != Field::TIMESTAMP_UN_FIELD;
- has_default= (field->type() != FIELD_TYPE_BLOB &&
+ has_default= (field_type != FIELD_TYPE_BLOB &&
!(field->flags & NO_DEFAULT_VALUE_FLAG) &&
field->unireg_check != Field::NEXT_NUMBER &&
!((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40))
@@ -821,7 +821,19 @@ static bool get_field_default_value(THD *thd, TABLE *table,
{ // Not null by default
char tmp[MAX_FIELD_WIDTH];
String type(tmp, sizeof(tmp), field->charset());
- field->val_str(&type);
+ if (field_type == MYSQL_TYPE_BIT)
+ {
+ longlong dec= field->val_int();
+ char *ptr= longlong2str(dec, tmp + 2, 2);
+ uint32 length= (uint32) (ptr - tmp);
+ tmp[0]= 'b';
+ tmp[1]= '\'';
+ tmp[length]= '\'';
+ type.length(length + 1);
+ quoted= 0;
+ }
+ else
+ field->val_str(&type);
if (type.length())
{
String def_val;
@@ -1441,6 +1453,7 @@ static bool show_status_array(THD *thd, const char *wild,
char name_buffer[80];
int len;
LEX_STRING null_lex_str;
+ CHARSET_INFO *charset= system_charset_info;
DBUG_ENTER("show_status_array");
null_lex_str.str= 0; // For sys_var->value_ptr()
@@ -1469,9 +1482,10 @@ static bool show_status_array(THD *thd, const char *wild,
long nr;
if (show_type == SHOW_SYS)
{
- show_type= ((sys_var*) value)->show_type();
- value= (char*) ((sys_var*) value)->value_ptr(thd, value_type,
- &null_lex_str);
+ sys_var *var= ((sys_var *) value);
+ show_type= var->show_type();
+ value= (char*) var->value_ptr(thd, value_type, &null_lex_str);
+ charset= var->charset(thd);
}
pos= end= buff;
@@ -1794,7 +1808,7 @@ static bool show_status_array(THD *thd, const char *wild,
restore_record(table, s->default_values);
table->field[0]->store(name_buffer, strlen(name_buffer),
system_charset_info);
- table->field[1]->store(pos, (uint32) (end - pos), system_charset_info);
+ table->field[1]->store(pos, (uint32) (end - pos), charset);
if (schema_table_store_record(thd, table))
DBUG_RETURN(TRUE);
}
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 8baeca9ccf7..eefe2a5596e 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -1535,7 +1535,9 @@ static bool prepare_blob_field(THD *thd, create_field *sql_field)
if ((sql_field->flags & BLOB_FLAG) && sql_field->length)
{
- if (sql_field->sql_type == FIELD_TYPE_BLOB)
+ if (sql_field->sql_type == FIELD_TYPE_BLOB ||
+ sql_field->sql_type == FIELD_TYPE_TINY_BLOB ||
+ sql_field->sql_type == FIELD_TYPE_MEDIUM_BLOB)
{
/* The user has given a length to the blob column */
sql_field->sql_type= get_blob_type_from_length(sql_field->length);
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index eb4e9b7ed73..f15db220a3b 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -1249,6 +1249,32 @@ multi_update::initialize_tables(JOIN *join)
}
}
+ /*
+ enable uncacheable flag if we update a view with check option
+ and check option has a subselect, otherwise, the check option
+ can be evaluated after the subselect was freed as independent
+ (See full_local in JOIN::join_free()).
+ */
+ if (table_ref->check_option && !join->select_lex->uncacheable)
+ {
+ SELECT_LEX_UNIT *tmp_unit;
+ SELECT_LEX *sl;
+ for (tmp_unit= join->select_lex->first_inner_unit();
+ tmp_unit;
+ tmp_unit= tmp_unit->next_unit())
+ {
+ for (sl= tmp_unit->first_select(); sl; sl= sl->next_select())
+ {
+ if (sl->master_unit()->item)
+ {
+ join->select_lex->uncacheable|= UNCACHEABLE_CHECKOPTION;
+ goto loop_end;
+ }
+ }
+ }
+ }
+loop_end:
+
if (table == first_table_for_update && table_ref->check_option)
{
table_map unupdated_tables= table_ref->check_option->used_tables() &
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index f65a62bed75..41a638b2618 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -980,13 +980,14 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
DBUG_RETURN(0);
}
- if (table->use_index || table->ignore_index)
+ List<String> *index_list= table->use_index ? table->use_index
+ : table->ignore_index;
+ if (index_list)
{
- my_error(ER_WRONG_USAGE, MYF(0),
- table->ignore_index ? "IGNORE INDEX" :
- (table->force_index ? "FORCE INDEX" : "USE INDEX"),
- "VIEW");
- DBUG_RETURN(TRUE);
+ DBUG_ASSERT(index_list->head()); // should never fail
+ my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), index_list->head()->c_ptr(),
+ table->table_name);
+ DBUG_RETURN(TRUE);
}
/* check loop via view definition */
diff --git a/sql/tztime.cc b/sql/tztime.cc
index 709e3b64752..d3d952e3c1e 100644
--- a/sql/tztime.cc
+++ b/sql/tztime.cc
@@ -1073,6 +1073,7 @@ Time_zone_system::gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const
localtime_r(&tmp_t, &tmp_tm);
localtime_to_TIME(tmp, &tmp_tm);
tmp->time_type= MYSQL_TIMESTAMP_DATETIME;
+ adjust_leap_second(tmp);
}
@@ -1157,6 +1158,7 @@ Time_zone_utc::gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const
gmtime_r(&tmp_t, &tmp_tm);
localtime_to_TIME(tmp, &tmp_tm);
tmp->time_type= MYSQL_TIMESTAMP_DATETIME;
+ adjust_leap_second(tmp);
}
@@ -1260,6 +1262,7 @@ void
Time_zone_db::gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const
{
::gmt_sec_to_TIME(tmp, t, tz_info);
+ adjust_leap_second(tmp);
}
@@ -2373,6 +2376,25 @@ Time_zone *my_tz_find_with_opening_tz_tables(THD *thd, const String *name)
DBUG_RETURN(tz);
}
+
+/**
+ Convert leap seconds into non-leap
+
+ This function will convert the leap seconds added by the OS to
+ non-leap seconds, e.g. 23:59:59, 23:59:60 -> 23:59:59, 00:00:01 ...
+ This check is not checking for years on purpose : although it's not a
+ complete check this way it doesn't require looking (and having installed)
+ the leap seconds table.
+
+ @param[in,out] broken down time structure as filled in by the OS
+*/
+
+void Time_zone::adjust_leap_second(MYSQL_TIME *t)
+{
+ if (t->second == 60 || t->second == 61)
+ t->second= 59;
+}
+
#endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */
diff --git a/sql/tztime.h b/sql/tztime.h
index 32a942a26e1..750b8dacbe1 100644
--- a/sql/tztime.h
+++ b/sql/tztime.h
@@ -55,6 +55,9 @@ public:
allocated on MEM_ROOT and should not require destruction.
*/
virtual ~Time_zone() {};
+
+protected:
+ static inline void adjust_leap_second(MYSQL_TIME *t);
};
extern Time_zone * my_tz_UTC;