summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.org>2017-10-30 16:42:46 +0400
committerAlexander Barkov <bar@mariadb.org>2017-10-30 16:42:46 +0400
commit003cb2f42477772ae43228c0bc0f8492246b9340 (patch)
tree680314d232d55b5a41dc2b2f5b500677e4aff183 /sql
parent84ed288f6807a4602e0af8615bfb17080df15160 (diff)
parent58e0dcb93dc2b2bf49f76c754bd216dbdf875a0d (diff)
downloadmariadb-git-003cb2f42477772ae43228c0bc0f8492246b9340.tar.gz
Merge remote-tracking branch 'origin/10.2' into bb-10.2-ext
Diffstat (limited to 'sql')
-rw-r--r--sql/events.cc9
-rw-r--r--sql/field.cc14
-rw-r--r--sql/ha_partition.cc6
-rw-r--r--sql/handler.cc17
-rw-r--r--sql/item.cc14
-rw-r--r--sql/item.h4
-rw-r--r--sql/item_row.cc1
-rw-r--r--sql/item_row.h11
-rw-r--r--sql/item_subselect.cc8
-rw-r--r--sql/item_timefunc.cc15
-rw-r--r--sql/item_timefunc.h2
-rw-r--r--sql/log_event.cc17
-rw-r--r--sql/opt_range.cc46
-rw-r--r--sql/opt_subselect.cc56
-rw-r--r--sql/slave.cc1
-rw-r--r--sql/sp_head.cc10
-rw-r--r--sql/sql_acl.cc49
-rw-r--r--sql/sql_acl.h8
-rw-r--r--sql/sql_admin.cc1
-rw-r--r--sql/sql_base.cc7
-rw-r--r--sql/sql_base.h5
-rw-r--r--sql/sql_const.h13
-rw-r--r--sql/sql_delete.cc2
-rw-r--r--sql/sql_do.cc2
-rw-r--r--sql/sql_insert.cc17
-rw-r--r--sql/sql_lex.h1
-rw-r--r--sql/sql_load.cc12
-rw-r--r--sql/sql_parse.cc21
-rw-r--r--sql/sql_partition.cc41
-rw-r--r--sql/sql_partition.h3
-rw-r--r--sql/sql_plugin.cc64
-rw-r--r--sql/sql_prepare.cc9
-rw-r--r--sql/sql_select.cc31
-rw-r--r--sql/sql_show.cc33
-rw-r--r--sql/sql_table.cc5
-rw-r--r--sql/sql_test.cc8
-rw-r--r--sql/sql_update.cc4
-rw-r--r--sql/sql_yacc.yy12
-rw-r--r--sql/table.cc3
-rw-r--r--sql/table.h3
40 files changed, 381 insertions, 204 deletions
diff --git a/sql/events.cc b/sql/events.cc
index 6d71fcdcb39..0830fa7c611 100644
--- a/sql/events.cc
+++ b/sql/events.cc
@@ -189,8 +189,8 @@ common_1_lev_code:
expr= tmp_expr - (tmp_expr/60)*60;
/* the code after the switch will finish */
- }
break;
+ }
case INTERVAL_HOUR_SECOND:
{
ulonglong tmp_expr= expr;
@@ -206,8 +206,8 @@ common_1_lev_code:
expr= tmp_expr - (tmp_expr/60)*60;
/* the code after the switch will finish */
- }
break;
+ }
case INTERVAL_DAY_SECOND:
{
ulonglong tmp_expr= expr;
@@ -229,8 +229,8 @@ common_1_lev_code:
expr= tmp_expr - (tmp_expr/60)*60;
/* the code after the switch will finish */
- }
break;
+ }
case INTERVAL_DAY_MICROSECOND:
case INTERVAL_HOUR_MICROSECOND:
case INTERVAL_MINUTE_MICROSECOND:
@@ -244,7 +244,8 @@ common_1_lev_code:
break;
case INTERVAL_WEEK:
expr/= 7;
- /* fall through */
+ close_quote= FALSE;
+ break;
default:
close_quote= FALSE;
break;
diff --git a/sql/field.cc b/sql/field.cc
index 068a7285c8e..cfa9623fe17 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1,6 +1,6 @@
/*
- Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2008, 2013, Monty Program Ab.
+ Copyright (c) 2000, 2017, Oracle and/or its affiliates.
+ Copyright (c) 2008, 2017, MariaDB
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
@@ -8810,13 +8810,13 @@ String *Field_set::val_str(String *val_buffer,
ulonglong tmp=(ulonglong) Field_enum::val_int();
uint bitnr=0;
+ /*
+ Some callers expect *val_buffer to contain the result,
+ so we assign to it, rather than doing 'return &empty_set_string.
+ */
+ *val_buffer= empty_set_string;
if (tmp == 0)
{
- /*
- Some callers expect *val_buffer to contain the result,
- so we assign to it, rather than doing 'return &empty_set_string.
- */
- *val_buffer= empty_set_string;
return val_buffer;
}
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index 2076379cd61..ed3028451c5 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -1,6 +1,6 @@
/*
- Copyright (c) 2005, 2013, Oracle and/or its affiliates.
- Copyright (c) 2009, 2013, Monty Program Ab & SkySQL Ab
+ Copyright (c) 2005, 2017, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2017, MariaDB
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
@@ -1935,7 +1935,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
cleanup_new_partition(part_count);
DBUG_RETURN(error);
}
-
+
DBUG_PRINT("info", ("Add partition %s", part_name_buff));
if ((error= prepare_new_partition(table, create_info,
new_file_array[i],
diff --git a/sql/handler.cc b/sql/handler.cc
index 553daa7e7e7..5baec0ef9d8 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -405,7 +405,7 @@ static int ha_finish_errors(void)
}
static volatile int32 need_full_discover_for_existence= 0;
-static volatile int32 engines_with_discover_table_names= 0;
+static volatile int32 engines_with_discover_file_names= 0;
static volatile int32 engines_with_discover= 0;
static int full_discover_for_existence(handlerton *, const char *, const char *)
@@ -430,8 +430,8 @@ static void update_discovery_counters(handlerton *hton, int val)
if (hton->discover_table_existence == full_discover_for_existence)
my_atomic_add32(&need_full_discover_for_existence, val);
- if (hton->discover_table_names)
- my_atomic_add32(&engines_with_discover_table_names, val);
+ if (hton->discover_table_names && hton->tablefile_extensions[0])
+ my_atomic_add32(&engines_with_discover_file_names, val);
if (hton->discover_table)
my_atomic_add32(&engines_with_discover, val);
@@ -5217,6 +5217,7 @@ void Discovered_table_list::remove_duplicates()
{
LEX_CSTRING **src= tables->front();
LEX_CSTRING **dst= src;
+ sort();
while (++dst <= tables->back())
{
LEX_CSTRING *s= *src, *d= *dst;
@@ -5284,10 +5285,12 @@ int ha_discover_table_names(THD *thd, LEX_CSTRING *db, MY_DIR *dirp,
int error;
DBUG_ENTER("ha_discover_table_names");
- if (engines_with_discover_table_names == 0 && !reusable)
+ if (engines_with_discover_file_names == 0 && !reusable)
{
- error= ext_table_discovery_simple(dirp, result);
- result->sort();
+ st_discover_names_args args= {db, NULL, result, 0};
+ error= ext_table_discovery_simple(dirp, result) ||
+ plugin_foreach(thd, discover_names,
+ MYSQL_STORAGE_ENGINE_PLUGIN, &args);
}
else
{
@@ -5300,8 +5303,6 @@ int ha_discover_table_names(THD *thd, LEX_CSTRING *db, MY_DIR *dirp,
error= extension_based_table_discovery(dirp, reg_ext, result) ||
plugin_foreach(thd, discover_names,
MYSQL_STORAGE_ENGINE_PLUGIN, &args);
- result->sort();
-
if (args.possible_duplicates > 0)
result->remove_duplicates();
}
diff --git a/sql/item.cc b/sql/item.cc
index ea3123168b2..e5e1d83f228 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -2607,6 +2607,9 @@ bool Type_std_attributes::agg_item_set_converter(const DTCollation &coll,
Item **args, uint nargs,
uint flags, int item_sep)
{
+ THD *thd= current_thd;
+ if (thd->lex->is_ps_or_view_context_analysis())
+ return false;
Item **arg, *safe_args[2]= {NULL, NULL};
/*
@@ -2622,7 +2625,6 @@ bool Type_std_attributes::agg_item_set_converter(const DTCollation &coll,
safe_args[1]= args[item_sep];
}
- THD *thd= current_thd;
bool res= FALSE;
uint i;
@@ -7082,6 +7084,7 @@ bool Item::cache_const_expr_analyzer(uchar **arg)
*/
if (const_item() &&
!(basic_const_item() || item->basic_const_item() ||
+ item->type() == Item::NULL_ITEM || /* Item_name_const hack */
item->type() == Item::FIELD_ITEM ||
item->type() == SUBSELECT_ITEM ||
item->type() == CACHE_ITEM ||
@@ -7457,7 +7460,11 @@ public:
// Find which select the field is in. This is achieved by walking up
// the select tree and looking for the table of interest.
st_select_lex *sel;
- for (sel= current_select; sel; sel= sel->outer_select())
+ for (sel= current_select;
+ sel ;
+ sel= (sel->context.outer_context ?
+ sel->context.outer_context->select_lex:
+ NULL))
{
List_iterator<TABLE_LIST> li(sel->leaf_tables);
TABLE_LIST *tbl;
@@ -8631,7 +8638,6 @@ bool Item_direct_view_ref::send(Protocol *protocol, st_value *buffer)
bool Item_direct_view_ref::fix_fields(THD *thd, Item **reference)
{
- DBUG_ASSERT(1);
/* view fild reference must be defined */
DBUG_ASSERT(*ref);
/* (*ref)->check_cols() will be made in Item_direct_ref::fix_fields */
@@ -10201,7 +10207,7 @@ void Item_direct_view_ref::update_used_tables()
table_map Item_direct_view_ref::used_tables() const
{
- DBUG_ASSERT(null_ref_table);
+ DBUG_ASSERT(fixed);
if (get_depended_from())
return OUTER_REF_TABLE_BIT;
diff --git a/sql/item.h b/sql/item.h
index b9f8004278d..c128251dae9 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1,8 +1,8 @@
#ifndef SQL_ITEM_INCLUDED
#define SQL_ITEM_INCLUDED
-/* Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2009, 2017, MariaDB Corporation.
+/* Copyright (c) 2000, 2017, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2017, MariaDB
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/item_row.cc b/sql/item_row.cc
index fc484f560ee..6486bb66615 100644
--- a/sql/item_row.cc
+++ b/sql/item_row.cc
@@ -24,7 +24,6 @@
#include "sql_class.h" // THD, set_var.h: THD
#include "set_var.h"
-
void Item_row::illegal_method_call(const char *method)
{
DBUG_ENTER("Item_row::illegal_method_call");
diff --git a/sql/item_row.h b/sql/item_row.h
index 9c92e19caab..83e9743fede 100644
--- a/sql/item_row.h
+++ b/sql/item_row.h
@@ -47,13 +47,10 @@ public:
Item_row(THD *thd, List<Item> &list):
Item(thd), Item_args(thd, list), not_null_tables_cache(0), with_null(0)
{ }
- Item_row(THD *thd, Item_row *item):
- Item(thd),
- Item_args(item),
- Used_tables_and_const_cache(item),
- not_null_tables_cache(0),
- with_null(0)
- {}
+ Item_row(THD *thd, Item_row *row):
+ Item(thd), Item_args(thd, static_cast<Item_args*>(row)), Used_tables_and_const_cache(),
+ not_null_tables_cache(0), with_null(0)
+ { }
enum Type type() const { return ROW_ITEM; };
const Type_handler *type_handler() const { return &type_handler_row; }
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 71594c0478b..63d1fd99f62 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -1433,6 +1433,10 @@ Item_in_subselect::Item_in_subselect(THD *thd, Item * left_exp,
DBUG_ENTER("Item_in_subselect::Item_in_subselect");
DBUG_PRINT("info", ("in_strategy: %u", (uint)in_strategy));
left_expr_orig= left_expr= left_exp;
+ /* prepare to possible disassembling the item in convert_subq_to_sj() */
+ if (left_exp->type() == Item::ROW_ITEM)
+ left_expr_orig= new (thd->mem_root)
+ Item_row(thd, static_cast<Item_row*>(left_exp));
func= &eq_creator;
init(select_lex, new (thd->mem_root) select_exists_subselect(thd, this));
max_columns= UINT_MAX;
@@ -1456,6 +1460,10 @@ Item_allany_subselect::Item_allany_subselect(THD *thd, Item * left_exp,
{
DBUG_ENTER("Item_allany_subselect::Item_allany_subselect");
left_expr_orig= left_expr= left_exp;
+ /* prepare to possible disassembling the item in convert_subq_to_sj() */
+ if (left_exp->type() == Item::ROW_ITEM)
+ left_expr_orig= new (thd->mem_root)
+ Item_row(thd, static_cast<Item_row*>(left_exp));
func= func_creator(all_arg);
init(select_lex, new (thd->mem_root) select_exists_subselect(thd, this));
max_columns= 1;
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 885db3a64f1..f0d7cd1c54c 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -1825,9 +1825,18 @@ overflow:
ltime->hour= TIME_MAX_HOUR+1;
check_time_range(ltime, decimals, &unused);
- make_truncated_value_warning(current_thd, Sql_condition::WARN_LEVEL_WARN,
- err->ptr(), err->length(),
- MYSQL_TIMESTAMP_TIME, NullS);
+ if (!err)
+ {
+ ErrConvInteger err2(sec, unsigned_flag);
+ make_truncated_value_warning(current_thd, Sql_condition::WARN_LEVEL_WARN,
+ &err2, MYSQL_TIMESTAMP_TIME, NullS);
+ }
+ else
+ {
+ ErrConvString err2(err);
+ make_truncated_value_warning(current_thd, Sql_condition::WARN_LEVEL_WARN,
+ &err2, MYSQL_TIMESTAMP_TIME, NullS);
+ }
return 0;
}
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 94794c6789d..9c102e8a666 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -574,8 +574,6 @@ public:
bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date) { DBUG_ASSERT(0); return 1; }
my_decimal *val_decimal(my_decimal *decimal_value)
{ return val_decimal_from_date(decimal_value); }
- int save_in_field(Field *field, bool no_conversions)
- { return save_date_in_field(field, no_conversions); }
};
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 7b234b285c9..d1cfb4fe814 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -8675,22 +8675,7 @@ User_var_log_event(const char* buf, uint event_len,
Old events will not have this extra byte, thence,
we keep the flags set to UNDEF_F.
*/
- size_t bytes_read= ((val + val_len) - buf_start);
-#ifndef DBUG_OFF
- bool old_pre_checksum_fd= description_event->is_version_before_checksum(
- &description_event->server_version_split);
-#endif
- DBUG_ASSERT((bytes_read == data_written -
- (old_pre_checksum_fd ||
- (description_event->checksum_alg ==
- BINLOG_CHECKSUM_ALG_OFF)) ?
- 0 : BINLOG_CHECKSUM_LEN)
- ||
- (bytes_read == data_written -1 -
- (old_pre_checksum_fd ||
- (description_event->checksum_alg ==
- BINLOG_CHECKSUM_ALG_OFF)) ?
- 0 : BINLOG_CHECKSUM_LEN));
+ uint bytes_read= (uint)((val + val_len) - buf_start);
if ((data_written - bytes_read) > 0)
{
flags= (uint) *(buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 024bb9dd933..c2d46d62200 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -4643,6 +4643,7 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge,
double roru_index_costs;
ha_rows roru_total_records;
double roru_intersect_part= 1.0;
+ size_t n_child_scans;
DBUG_ENTER("get_best_disjunct_quick");
DBUG_PRINT("info", ("Full table scan cost: %g", read_time));
@@ -4659,7 +4660,7 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge,
}
}
- size_t n_child_scans= imerge->trees_next - imerge->trees;
+ n_child_scans= imerge->trees_next - imerge->trees;
if (!n_child_scans)
DBUG_RETURN(NULL);
@@ -4877,8 +4878,8 @@ skip_to_ror_scan:
(TIME_FOR_COMPARE_ROWID * M_LN2) +
get_sweep_read_cost(param, roru_total_records);
- DBUG_PRINT("info", ("ROR-union: cost %g, %d members", roru_total_cost,
- n_child_scans));
+ DBUG_PRINT("info", ("ROR-union: cost %g, %zu members",
+ roru_total_cost, n_child_scans));
TRP_ROR_UNION* roru;
if (roru_total_cost < read_time)
{
@@ -8557,6 +8558,34 @@ bool sel_trees_can_be_ored(RANGE_OPT_PARAM* param,
}
/*
+ Check whether the key parts inf_init..inf_end-1 of one index can compose
+ an infix for the key parts key_init..key_end-1 of another index
+*/
+
+static
+bool is_key_infix(KEY_PART *key_init, KEY_PART *key_end,
+ KEY_PART *inf_init, KEY_PART *inf_end)
+{
+ KEY_PART *key_part, *inf_part;
+ for (key_part= key_init; key_part < key_end; key_part++)
+ {
+ if (key_part->field->eq(inf_init->field))
+ break;
+ }
+ if (key_part == key_end)
+ return false;
+ for (key_part++, inf_part= inf_init + 1;
+ key_part < key_end && inf_part < inf_end;
+ key_part++, inf_part++)
+ {
+ if (!key_part->field->eq(inf_part->field))
+ return false;
+ }
+ return inf_part == inf_end;
+}
+
+
+/*
Check whether range parts of two trees must be ored for some indexes
SYNOPSIS
@@ -8612,14 +8641,9 @@ bool sel_trees_must_be_ored(RANGE_OPT_PARAM* param,
KEY_PART *key2_init= param->key[idx2]+tree2->keys[idx2]->part;
KEY_PART *key2_end= param->key[idx2]+tree2->keys[idx2]->max_part_no;
- KEY_PART *part1, *part2;
- for (part1= key1_init, part2= key2_init;
- part1 < key1_end && part2 < key2_end;
- part1++, part2++)
- {
- if (!part1->field->eq(part2->field))
- DBUG_RETURN(FALSE);
- }
+ if (!is_key_infix(key1_init, key1_end, key2_init, key2_end) &&
+ !is_key_infix(key2_init, key2_end, key1_init, key1_end))
+ DBUG_RETURN(FALSE);
}
}
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index 4024ae26b8b..cc9cfbd127f 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -1589,6 +1589,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
sj-nest.
*/
st_select_lex *subq_lex= subq_pred->unit->first_select();
+ DBUG_ASSERT(subq_lex->next_select() == NULL);
nested_join->join_list.empty();
List_iterator_fast<TABLE_LIST> li(subq_lex->top_join_list);
TABLE_LIST *tl;
@@ -1692,7 +1693,8 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
if (subq_pred->left_expr->cols() == 1)
{
- nested_join->sj_outer_expr_list.push_back(subq_pred->left_expr,
+ /* add left = select_list_element */
+ nested_join->sj_outer_expr_list.push_back(&subq_pred->left_expr,
thd->mem_root);
/*
Create Item_func_eq. Note that
@@ -1706,26 +1708,62 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
Item_func_eq *item_eq=
new (thd->mem_root) Item_func_eq(thd, subq_pred->left_expr_orig,
subq_lex->ref_pointer_array[0]);
+ if (!item_eq)
+ DBUG_RETURN(TRUE);
if (subq_pred->left_expr_orig != subq_pred->left_expr)
thd->change_item_tree(item_eq->arguments(), subq_pred->left_expr);
item_eq->in_equality_no= 0;
sj_nest->sj_on_expr= and_items(thd, sj_nest->sj_on_expr, item_eq);
}
- else
+ else if (subq_pred->left_expr->type() == Item::ROW_ITEM)
{
+ /*
+ disassemple left expression and add
+ left1 = select_list_element1 and left2 = select_list_element2 ...
+ */
for (uint i= 0; i < subq_pred->left_expr->cols(); i++)
{
- nested_join->sj_outer_expr_list.push_back(subq_pred->left_expr->
- element_index(i),
+ nested_join->sj_outer_expr_list.push_back(subq_pred->left_expr->addr(i),
thd->mem_root);
- Item_func_eq *item_eq=
+ Item_func_eq *item_eq=
new (thd->mem_root)
- Item_func_eq(thd, subq_pred->left_expr->element_index(i),
+ Item_func_eq(thd, subq_pred->left_expr_orig->element_index(i),
subq_lex->ref_pointer_array[i]);
+ if (!item_eq)
+ DBUG_RETURN(TRUE);
+ DBUG_ASSERT(subq_pred->left_expr->element_index(i)->fixed);
+ if (subq_pred->left_expr_orig->element_index(i) !=
+ subq_pred->left_expr->element_index(i))
+ thd->change_item_tree(item_eq->arguments(),
+ subq_pred->left_expr->element_index(i));
item_eq->in_equality_no= i;
sj_nest->sj_on_expr= and_items(thd, sj_nest->sj_on_expr, item_eq);
}
}
+ else
+ {
+ /*
+ add row operation
+ left = (select_list_element1, select_list_element2, ...)
+ */
+ Item_row *row= new (thd->mem_root) Item_row(thd, subq_lex->pre_fix);
+ /* fix fields on subquery was call so they should be the same */
+ DBUG_ASSERT(subq_pred->left_expr->cols() == row->cols());
+ if (!row)
+ DBUG_RETURN(TRUE);
+ nested_join->sj_outer_expr_list.push_back(&subq_pred->left_expr);
+ Item_func_eq *item_eq=
+ new (thd->mem_root) Item_func_eq(thd, subq_pred->left_expr_orig, row);
+ if (!item_eq)
+ DBUG_RETURN(TRUE);
+ for (uint i= 0; i < row->cols(); i++)
+ {
+ if (row->element_index(i) != subq_lex->ref_pointer_array[i])
+ thd->change_item_tree(row->addr(i), subq_lex->ref_pointer_array[i]);
+ }
+ item_eq->in_equality_no= 0;
+ sj_nest->sj_on_expr= and_items(thd, sj_nest->sj_on_expr, item_eq);
+ }
/*
Fix the created equality and AND
@@ -3274,8 +3312,8 @@ void restore_prev_sj_state(const table_map remaining_tables,
ulonglong get_bound_sj_equalities(TABLE_LIST *sj_nest,
table_map remaining_tables)
{
- List_iterator<Item> li(sj_nest->nested_join->sj_outer_expr_list);
- Item *item;
+ List_iterator<Item_ptr> li(sj_nest->nested_join->sj_outer_expr_list);
+ Item **item;
uint i= 0;
ulonglong res= 0;
while ((item= li++))
@@ -3286,7 +3324,7 @@ ulonglong get_bound_sj_equalities(TABLE_LIST *sj_nest,
class and see if there is an element that is bound?
(this is an optional feature)
*/
- if (!(item->used_tables() & remaining_tables))
+ if (!(item[0]->used_tables() & remaining_tables))
{
res |= 1ULL << i;
}
diff --git a/sql/slave.cc b/sql/slave.cc
index 86675b4f19c..c6ac31677cf 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -3213,7 +3213,6 @@ static int init_slave_thread(THD* thd, Master_info *mi,
thd->variables.sql_log_slow= opt_log_slow_slave_statements;
thd->variables.log_slow_filter= global_system_variables.log_slow_filter;
set_slave_thread_options(thd);
- thd->client_capabilities = CLIENT_LOCAL_FILES;
if (thd_type == SLAVE_THD_SQL)
THD_STAGE_INFO(thd, stage_waiting_for_the_next_event_in_relay_log);
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 82123c6ad6e..73ce5403f38 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -2544,10 +2544,18 @@ bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access)
*full_access= ((!check_table_access(thd, SELECT_ACL, &tables, FALSE,
1, TRUE) &&
(tables.grant.privilege & SELECT_ACL) != 0) ||
+ /* Check if user owns the routine. */
(!strcmp(sp->m_definer.user.str,
thd->security_ctx->priv_user) &&
!strcmp(sp->m_definer.host.str,
- thd->security_ctx->priv_host)));
+ thd->security_ctx->priv_host)) ||
+ /* Check if current role or any of the sub-granted roles
+ own the routine. */
+ (sp->m_definer.host.length == 0 &&
+ (!strcmp(sp->m_definer.user.str,
+ thd->security_ctx->priv_role) ||
+ check_role_is_granted(thd->security_ctx->priv_role, NULL,
+ sp->m_definer.user.str))));
if (!*full_access)
return check_some_routine_access(thd, sp->m_db.str, sp->m_name.str,
sp->m_handler);
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 2c192d661f4..7e95abead67 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -9234,6 +9234,16 @@ void get_mqh(const char *user, const char *host, USER_CONN *uc)
mysql_mutex_unlock(&acl_cache->lock);
}
+static int check_role_is_granted_callback(ACL_USER_BASE *grantee, void *data)
+{
+ LEX_CSTRING *rolename= static_cast<LEX_CSTRING *>(data);
+ if (rolename->length == grantee->user.length &&
+ !strcmp(rolename->str, grantee->user.str))
+ return -1; // End search, we've found our role.
+
+ /* Keep looking, we haven't found our role yet. */
+ return 0;
+}
/*
Modify a privilege table.
@@ -11254,7 +11264,6 @@ bool check_grant(THD *, ulong, TABLE_LIST *, bool, uint, bool)
}
#endif /*NO_EMBEDDED_ACCESS_CHECKS */
-
SHOW_VAR acl_statistics[] = {
#ifndef NO_EMBEDDED_ACCESS_CHECKS
{"column_grants", (char*)show_column_grants, SHOW_SIMPLE_FUNC},
@@ -11270,6 +11279,43 @@ SHOW_VAR acl_statistics[] = {
{NullS, NullS, SHOW_LONG},
};
+/* Check if a role is granted to a user/role. We traverse the role graph
+ and return true if we find a match.
+
+ hostname == NULL means we are looking for a role as a starting point,
+ otherwise a user.
+*/
+bool check_role_is_granted(const char *username,
+ const char *hostname,
+ const char *rolename)
+{
+ DBUG_ENTER("check_role_is_granted");
+ bool result= false;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ ACL_USER_BASE *root;
+ mysql_mutex_lock(&acl_cache->lock);
+ if (hostname)
+ root= find_user_exact(username, hostname);
+ else
+ root= find_acl_role(username);
+
+ LEX_CSTRING role_lex;
+ role_lex.str= rolename;
+ role_lex.length= strlen(rolename);
+
+ if (root && /* No grantee, nothing to search. */
+ traverse_role_graph_down(root, &role_lex, check_role_is_granted_callback,
+ NULL) == -1)
+ {
+ /* We have found the role during our search. */
+ result= true;
+ }
+
+ /* We haven't found the role or we had no initial grantee to start from. */
+ mysql_mutex_unlock(&acl_cache->lock);
+#endif
+ DBUG_RETURN(result);
+}
int fill_schema_enabled_roles(THD *thd, TABLE_LIST *tables, COND *cond)
{
@@ -13659,4 +13705,3 @@ maria_declare_plugin(mysql_password)
MariaDB_PLUGIN_MATURITY_STABLE /* Maturity */
}
maria_declare_plugin_end;
-
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index 6164c6fa57d..cf844653134 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -409,6 +409,14 @@ int acl_set_default_role(THD *thd, const char *host, const char *user,
extern SHOW_VAR acl_statistics[];
+/* Check if a role is granted to a user/role.
+
+ If hostname == NULL, search for a role as the starting grantee.
+*/
+bool check_role_is_granted(const char *username,
+ const char *hostname,
+ const char *rolename);
+
#ifndef DBUG_OFF
extern ulong role_global_merges, role_db_merges, role_table_merges,
role_column_merges, role_routine_merges;
diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc
index 1e46fc44c5e..c1c053670af 100644
--- a/sql/sql_admin.cc
+++ b/sql/sql_admin.cc
@@ -66,7 +66,6 @@ static bool admin_recreate_table(THD *thd, TABLE_LIST *table_list)
if (thd->get_stmt_da()->is_ok())
thd->get_stmt_da()->reset_diagnostics_area();
table_list->table= NULL;
- result_code= result_code ? HA_ADMIN_FAILED : HA_ADMIN_OK;
DBUG_RETURN(result_code);
}
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 9c5fc23af8e..87ef4e0c03d 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -7061,13 +7061,15 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array,
List<Item> &fields, enum_mark_columns mark_used_columns,
- List<Item> *sum_func_list, bool allow_sum_func)
+ List<Item> *sum_func_list, List<Item> *pre_fix,
+ bool allow_sum_func)
{
reg2 Item *item;
enum_mark_columns save_mark_used_columns= thd->mark_used_columns;
nesting_map save_allow_sum_func= thd->lex->allow_sum_func;
List_iterator<Item> it(fields);
bool save_is_item_list_lookup;
+ bool make_pre_fix= (pre_fix && (pre_fix->elements == 0));
DBUG_ENTER("setup_fields");
DBUG_PRINT("enter", ("ref_pointer_array: %p", ref_pointer_array.array()));
@@ -7117,6 +7119,9 @@ bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array,
thd->lex->current_select->cur_pos_in_select_list= 0;
while ((item= it++))
{
+ if (make_pre_fix)
+ pre_fix->push_back(item, thd->stmt_arena->mem_root);
+
if ((!item->fixed && item->fix_fields(thd, it.ref())) ||
(item= *(it.ref()))->check_cols(1))
{
diff --git a/sql/sql_base.h b/sql/sql_base.h
index 7a8d27c9147..bb33af66590 100644
--- a/sql/sql_base.h
+++ b/sql/sql_base.h
@@ -159,7 +159,8 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
List<Item> *sum_func_list, uint wild_num);
bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array,
List<Item> &item, enum_mark_columns mark_used_columns,
- List<Item> *sum_func_list, bool allow_sum_func);
+ List<Item> *sum_func_list, List<Item> *pre_fix,
+ bool allow_sum_func);
void unfix_fields(List<Item> &items);
bool fill_record(THD * thd, TABLE *table_arg, List<Item> &fields,
List<Item> &values, bool ignore_errors, bool update);
@@ -366,7 +367,7 @@ inline bool setup_fields_with_no_wrap(THD *thd, Ref_ptr_array ref_pointer_array,
bool res;
thd->lex->select_lex.no_wrap_view_item= TRUE;
res= setup_fields(thd, ref_pointer_array, item, mark_used_columns,
- sum_func_list, allow_sum_func);
+ sum_func_list, NULL, allow_sum_func);
thd->lex->select_lex.no_wrap_view_item= FALSE;
return res;
}
diff --git a/sql/sql_const.h b/sql/sql_const.h
index 8d5f56de6b0..a5756aa1f39 100644
--- a/sql/sql_const.h
+++ b/sql/sql_const.h
@@ -45,7 +45,18 @@
#define MAX_MBWIDTH 3 /* Max multibyte sequence */
#define MAX_FILENAME_MBWIDTH 5
#define MAX_FIELD_CHARLENGTH 255
-#define MAX_FIELD_VARCHARLENGTH 65535
+/*
+ In MAX_FIELD_VARCHARLENGTH we reserve extra bytes for the overhead:
+ - 2 bytes for the length
+ - 1 byte for NULL bits
+ to avoid the "Row size too large" error for these three corner definitions:
+ CREATE TABLE t1 (c VARBINARY(65533));
+ CREATE TABLE t1 (c VARBINARY(65534));
+ CREATE TABLE t1 (c VARBINARY(65535));
+ Like VARCHAR(65536), they will be converted to BLOB automatically
+ in non-sctict mode.
+*/
+#define MAX_FIELD_VARCHARLENGTH (65535-2-1)
#define MAX_FIELD_BLOBLENGTH UINT_MAX32 /* cf field_blob::get_length() */
#define CONVERT_IF_BIGGER_TO_BLOB 512 /* Threshold *in characters* */
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 17e2404fdf1..9b1f755a02c 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -821,7 +821,7 @@ l
DBUG_RETURN(TRUE);
if ((wild_num && setup_wild(thd, table_list, field_list, NULL, wild_num)) ||
setup_fields(thd, Ref_ptr_array(),
- field_list, MARK_COLUMNS_READ, NULL, 0) ||
+ field_list, MARK_COLUMNS_READ, NULL, NULL, 0) ||
setup_conds(thd, table_list, select_lex->leaf_tables, conds) ||
setup_ftfuncs(select_lex))
DBUG_RETURN(TRUE);
diff --git a/sql/sql_do.cc b/sql/sql_do.cc
index 6d86ece6a9f..da7dfe0c137 100644
--- a/sql/sql_do.cc
+++ b/sql/sql_do.cc
@@ -29,7 +29,7 @@ bool mysql_do(THD *thd, List<Item> &values)
List_iterator<Item> li(values);
Item *value;
DBUG_ENTER("mysql_do");
- if (setup_fields(thd, Ref_ptr_array(), values, MARK_COLUMNS_NONE, 0, 0))
+ if (setup_fields(thd, Ref_ptr_array(), values, MARK_COLUMNS_NONE, 0, NULL, 0))
DBUG_RETURN(TRUE);
while ((value = li++))
(void) value->is_null();
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 3d81ab35373..98e0da1ddbe 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -268,7 +268,8 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
if (table_list->is_view())
unfix_fields(fields);
- res= setup_fields(thd, Ref_ptr_array(), fields, MARK_COLUMNS_WRITE, 0, 0);
+ res= setup_fields(thd, Ref_ptr_array(),
+ fields, MARK_COLUMNS_WRITE, 0, NULL, 0);
/* Restore the current context. */
ctx_state.restore_state(context, table_list);
@@ -380,7 +381,7 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list,
/* Check the fields we are going to modify */
if (setup_fields(thd, Ref_ptr_array(),
- update_fields, MARK_COLUMNS_WRITE, 0, 0))
+ update_fields, MARK_COLUMNS_WRITE, 0, NULL, 0))
return -1;
if (insert_table_list->is_view() &&
@@ -806,7 +807,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter);
goto abort;
}
- if (setup_fields(thd, Ref_ptr_array(), *values, MARK_COLUMNS_READ, 0, 0))
+ if (setup_fields(thd, Ref_ptr_array(),
+ *values, MARK_COLUMNS_READ, 0, NULL, 0))
goto abort;
switch_to_nullable_trigger_fields(*values, table);
}
@@ -1531,13 +1533,13 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
context->resolve_in_table_list_only(table_list);
res= (setup_fields(thd, Ref_ptr_array(),
- *values, MARK_COLUMNS_READ, 0, 0) ||
+ *values, MARK_COLUMNS_READ, 0, NULL, 0) ||
check_insert_fields(thd, context->table_list, fields, *values,
!insert_into_view, 0, &map));
if (!res)
res= setup_fields(thd, Ref_ptr_array(),
- update_values, MARK_COLUMNS_READ, 0, 0);
+ update_values, MARK_COLUMNS_READ, 0, NULL, 0);
if (!res && duplic == DUP_UPDATE)
{
@@ -3527,7 +3529,8 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
*/
lex->current_select= &lex->select_lex;
- res= (setup_fields(thd, Ref_ptr_array(), values, MARK_COLUMNS_READ, 0, 0) ||
+ res= (setup_fields(thd, Ref_ptr_array(),
+ values, MARK_COLUMNS_READ, 0, NULL, 0) ||
check_insert_fields(thd, table_list, *fields, values,
!insert_into_view, 1, &map));
@@ -3580,7 +3583,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
ctx_state.get_first_name_resolution_table();
res= res || setup_fields(thd, Ref_ptr_array(), *info.update_values,
- MARK_COLUMNS_READ, 0, 0);
+ MARK_COLUMNS_READ, 0, NULL, 0);
if (!res)
{
/*
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 8ace65aedf7..9caf1b905ca 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -868,6 +868,7 @@ public:
Group_list_ptrs *group_list_ptrs;
List<Item> item_list; /* list of fields & expressions */
+ List<Item> pre_fix; /* above list before fix_fields */
bool is_item_list_lookup;
/*
Usualy it is pointer to ftfunc_list_alloc, but in union used to create fake
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 4d5d1a4d943..5e11794f139 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -387,21 +387,23 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
in this case.
*/
if (setup_fields(thd, Ref_ptr_array(),
- set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
- setup_fields(thd, Ref_ptr_array(), set_values, MARK_COLUMNS_READ, 0, 0))
+ set_fields, MARK_COLUMNS_WRITE, 0, NULL, 0) ||
+ setup_fields(thd, Ref_ptr_array(),
+ set_values, MARK_COLUMNS_READ, 0, NULL, 0))
DBUG_RETURN(TRUE);
}
else
{ // Part field list
/* TODO: use this conds for 'WITH CHECK OPTIONS' */
if (setup_fields(thd, Ref_ptr_array(),
- fields_vars, MARK_COLUMNS_WRITE, 0, 0) ||
+ fields_vars, MARK_COLUMNS_WRITE, 0, NULL, 0) ||
setup_fields(thd, Ref_ptr_array(),
- set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
+ set_fields, MARK_COLUMNS_WRITE, 0, NULL, 0) ||
check_that_all_fields_are_given_values(thd, table, table_list))
DBUG_RETURN(TRUE);
/* Fix the expressions in SET clause */
- if (setup_fields(thd, Ref_ptr_array(), set_values, MARK_COLUMNS_READ, 0, 0))
+ if (setup_fields(thd, Ref_ptr_array(),
+ set_values, MARK_COLUMNS_READ, 0, NULL, 0))
DBUG_RETURN(TRUE);
}
switch_to_nullable_trigger_fields(fields_vars, table);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index ae654553b78..738d59fd401 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1424,8 +1424,7 @@ out:
@retval FALSE The statement isn't updating any relevant tables.
*/
-static my_bool deny_updates_if_read_only_option(THD *thd,
- TABLE_LIST *all_tables)
+static bool deny_updates_if_read_only_option(THD *thd, TABLE_LIST *all_tables)
{
DBUG_ENTER("deny_updates_if_read_only_option");
@@ -1447,10 +1446,20 @@ static my_bool deny_updates_if_read_only_option(THD *thd,
if (lex->sql_command == SQLCOM_UPDATE_MULTI)
DBUG_RETURN(FALSE);
- /* a table-to-create is not in the temp table list, needs a special check */
+ /*
+ a table-to-be-created is not in the temp table list yet,
+ so CREATE TABLE needs a special treatment
+ */
if (lex->sql_command == SQLCOM_CREATE_TABLE)
DBUG_RETURN(!lex->tmp_table());
+ /*
+ a table-to-be-dropped might not exist (DROP TEMPORARY TABLE IF EXISTS),
+ cannot use the temp table list either.
+ */
+ if (lex->sql_command == SQLCOM_DROP_TABLE && lex->tmp_table())
+ DBUG_RETURN(FALSE);
+
/* Check if we created or dropped databases */
if ((sql_command_flags[lex->sql_command] & CF_DB_CHANGE))
DBUG_RETURN(TRUE);
@@ -4034,7 +4043,7 @@ mysql_execute_command(THD *thd)
#ifdef WITH_PARTITION_STORAGE_ENGINE
{
partition_info *part_info= thd->lex->part_info;
- if (part_info && !(part_info= thd->lex->part_info->get_clone(thd)))
+ if (part_info && !(part_info= part_info->get_clone(thd)))
{
res= -1;
goto end_with_restore_list;
@@ -4511,7 +4520,7 @@ end_with_restore_list:
if (up_result != 2)
break;
}
- /* Fall through */
+ /* fall through */
case SQLCOM_UPDATE_MULTI:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
@@ -4623,7 +4632,7 @@ end_with_restore_list:
DBUG_PRINT("debug", ("Just after generate_incident()"));
}
#endif
- /* fall through */
+ /* fall through */
case SQLCOM_INSERT:
{
WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE);
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index c9e78964e2a..006b3c49a86 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2005, 2014, Oracle and/or its affiliates.
- Copyright (c) 2009, 2014, SkySQL Ab.
+/* Copyright (c) 2005, 2017, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2017, 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
@@ -6561,7 +6561,8 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
lpt->alter_info= alter_info;
lpt->create_info= create_info;
lpt->db_options= create_info->table_options;
- if (create_info->row_type == ROW_TYPE_DYNAMIC)
+ if (create_info->row_type != ROW_TYPE_FIXED &&
+ create_info->row_type != ROW_TYPE_DEFAULT)
lpt->db_options|= HA_OPTION_PACK_RECORD;
lpt->table= table;
lpt->key_info_buffer= 0;
@@ -8073,6 +8074,7 @@ int create_partition_name(char *out, size_t outlen, const char *in1,
}
else
transl_part= in2;
+
if (name_variant == NORMAL_PART_NAME)
end= strxnmov(out, outlen-1, in1, "#P#", transl_part, NullS);
else if (name_variant == TEMP_PART_NAME)
@@ -8087,25 +8089,19 @@ int create_partition_name(char *out, size_t outlen, const char *in1,
return 0;
}
-
-/*
- Create subpartition name
-
- SYNOPSIS
- create_subpartition_name()
- out:out The buffer for the created partition name string
- must be *at least* of FN_REFLEN+1 bytes
- in1 First part
- in2 Second part
- in3 Third part
- name_variant Normal, temporary or renamed partition name
-
- RETURN VALUE
- 0 if ok, error if name too long
-
- DESCRIPTION
- This method is used to calculate the subpartition name, service routine to
- the del_ren_cre_table method.
+/**
+ Create subpartition name. This method is used to calculate the
+ subpartition name, service routine to the del_ren_cre_table method.
+ The output buffer size should be FN_REFLEN + 1(terminating '\0').
+
+ @param [out] out Created partition name string
+ @param in1 First part
+ @param in2 Second part
+ @param in3 Third part
+ @param name_variant Normal, temporary or renamed partition name
+
+ @retval true Error.
+ @retval false Success.
*/
int create_subpartition_name(char *out, size_t outlen,
@@ -8117,6 +8113,7 @@ int create_subpartition_name(char *out, size_t outlen,
tablename_to_filename(in2, transl_part_name, FN_REFLEN);
tablename_to_filename(in3, transl_subpart_name, FN_REFLEN);
+
if (name_variant == NORMAL_PART_NAME)
end= strxnmov(out, outlen-1, in1, "#P#", transl_part_name,
"#SP#", transl_subpart_name, NullS);
diff --git a/sql/sql_partition.h b/sql/sql_partition.h
index b0dede7487e..992229afb05 100644
--- a/sql/sql_partition.h
+++ b/sql/sql_partition.h
@@ -1,7 +1,8 @@
#ifndef SQL_PARTITION_INCLUDED
#define SQL_PARTITION_INCLUDED
-/* Copyright (c) 2006, 2013, Oracle and/or its affiliates.
+/* Copyright (c) 2006, 2017, Oracle and/or its affiliates.
+ Copyright (c) 2011, 2017, MariaDB
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_plugin.cc b/sql/sql_plugin.cc
index 89ac8559a62..978188199c5 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -228,7 +228,6 @@ static DYNAMIC_ARRAY plugin_array;
static HASH plugin_hash[MYSQL_MAX_PLUGIN_TYPE_NUM];
static MEM_ROOT plugin_mem_root;
static bool reap_needed= false;
-static int plugin_array_version=0;
static bool initialized= 0;
ulong dlopen_count;
@@ -323,7 +322,6 @@ static void unlock_variables(THD *thd, struct system_variables *vars);
static void cleanup_variables(struct system_variables *vars);
static void plugin_vars_free_values(sys_var *vars);
static void restore_ptr_backup(uint n, st_ptr_backup *backup);
-static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref plugin);
static void intern_plugin_unlock(LEX *lex, plugin_ref plugin);
static void reap_plugins(void);
@@ -947,15 +945,17 @@ SHOW_COMP_OPTION plugin_status(const char *name, size_t len, int type)
}
-static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref rc)
+static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref rc,
+ uint state_mask= PLUGIN_IS_READY |
+ PLUGIN_IS_UNINITIALIZED |
+ PLUGIN_IS_DELETED)
{
st_plugin_int *pi= plugin_ref_to_int(rc);
DBUG_ENTER("intern_plugin_lock");
mysql_mutex_assert_owner(&LOCK_plugin);
- if (pi->state & (PLUGIN_IS_READY | PLUGIN_IS_UNINITIALIZED |
- PLUGIN_IS_DELETED))
+ if (pi->state & state_mask)
{
plugin_ref plugin;
#ifdef DBUG_OFF
@@ -1150,7 +1150,6 @@ static bool plugin_add(MEM_ROOT *tmp_root,
if (!(tmp_plugin_ptr= plugin_insert_or_reuse(&tmp)))
goto err;
- plugin_array_version++;
if (my_hash_insert(&plugin_hash[plugin->type], (uchar*)tmp_plugin_ptr))
tmp_plugin_ptr->state= PLUGIN_IS_FREED;
init_alloc_root(&tmp_plugin_ptr->mem_root, 4096, 4096, MYF(0));
@@ -1250,7 +1249,6 @@ static void plugin_del(struct st_plugin_int *plugin)
my_hash_delete(&plugin_hash[plugin->plugin->type], (uchar*)plugin);
plugin_dl_del(plugin->plugin_dl);
plugin->state= PLUGIN_IS_FREED;
- plugin_array_version++;
free_root(&plugin->mem_root, MYF(0));
}
else
@@ -1869,11 +1867,11 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, const char *list)
switch ((*(p++)= *(list++))) {
case '\0':
list= NULL; /* terminate the loop */
-#ifndef __WIN__
/* fall through */
+ case ';':
+#ifndef __WIN__
case ':': /* can't use this as delimiter as it may be drive letter */
#endif
- case ';':
str->str[str->length]= '\0';
if (str == &name) // load all plugins in named module
{
@@ -2347,64 +2345,55 @@ error:
bool plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func,
int type, uint state_mask, void *arg)
{
- uint idx, total;
- struct st_plugin_int *plugin, **plugins;
- int version=plugin_array_version;
+ uint idx, total= 0;
+ struct st_plugin_int *plugin;
+ plugin_ref *plugins;
+ my_bool res= FALSE;
DBUG_ENTER("plugin_foreach_with_mask");
if (!initialized)
DBUG_RETURN(FALSE);
- state_mask= ~state_mask; // do it only once
-
mysql_mutex_lock(&LOCK_plugin);
- total= type == MYSQL_ANY_PLUGIN ? plugin_array.elements
- : plugin_hash[type].records;
/*
Do the alloca out here in case we do have a working alloca:
- leaving the nested stack frame invalidates alloca allocation.
+ leaving the nested stack frame invalidates alloca allocation.
*/
- plugins=(struct st_plugin_int **)my_alloca(total*sizeof(plugin));
if (type == MYSQL_ANY_PLUGIN)
{
- for (idx= 0; idx < total; idx++)
+ plugins= (plugin_ref*) my_alloca(plugin_array.elements * sizeof(plugin_ref));
+ for (idx= 0; idx < plugin_array.elements; idx++)
{
plugin= *dynamic_element(&plugin_array, idx, struct st_plugin_int **);
- plugins[idx]= !(plugin->state & state_mask) ? plugin : NULL;
+ if ((plugins[total]= intern_plugin_lock(0, plugin_int_to_ref(plugin),
+ state_mask)))
+ total++;
}
}
else
{
HASH *hash= plugin_hash + type;
- for (idx= 0; idx < total; idx++)
+ plugins= (plugin_ref*) my_alloca(hash->records * sizeof(plugin_ref));
+ for (idx= 0; idx < hash->records; idx++)
{
plugin= (struct st_plugin_int *) my_hash_element(hash, idx);
- plugins[idx]= !(plugin->state & state_mask) ? plugin : NULL;
+ if ((plugins[total]= intern_plugin_lock(0, plugin_int_to_ref(plugin),
+ state_mask)))
+ total++;
}
}
mysql_mutex_unlock(&LOCK_plugin);
for (idx= 0; idx < total; idx++)
{
- if (unlikely(version != plugin_array_version))
- {
- mysql_mutex_lock(&LOCK_plugin);
- for (uint i=idx; i < total; i++)
- if (plugins[i] && plugins[i]->state & state_mask)
- plugins[i]=0;
- mysql_mutex_unlock(&LOCK_plugin);
- }
- plugin= plugins[idx];
/* It will stop iterating on first engine error when "func" returns TRUE */
- if (plugin && func(thd, plugin_int_to_ref(plugin), arg))
- goto err;
+ if ((res= func(thd, plugins[idx], arg)))
+ break;
}
+ plugin_unlock_list(0, plugins, total);
my_afree(plugins);
- DBUG_RETURN(FALSE);
-err:
- my_afree(plugins);
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(res);
}
@@ -3531,7 +3520,6 @@ bool sys_var_pluginvar::global_update(THD *thd, set_var *var)
options->max_value= getopt_double2ulonglong((opt)->max_val); \
options->block_size= (long) (opt)->blk_sz;
-
void plugin_opt_set_limits(struct my_option *options,
const struct st_mysql_sys_var *opt)
{
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 793f9fae17b..df44c5e4119 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1391,7 +1391,8 @@ static bool mysql_test_insert(Prepared_statement *stmt,
my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter);
goto error;
}
- if (setup_fields(thd, Ref_ptr_array(), *values, MARK_COLUMNS_NONE, 0, 0))
+ if (setup_fields(thd, Ref_ptr_array(),
+ *values, MARK_COLUMNS_NONE, 0, NULL, 0))
goto error;
}
}
@@ -1485,7 +1486,7 @@ static int mysql_test_update(Prepared_statement *stmt,
#endif
thd->lex->select_lex.no_wrap_view_item= TRUE;
res= setup_fields(thd, Ref_ptr_array(),
- select->item_list, MARK_COLUMNS_READ, 0, 0);
+ select->item_list, MARK_COLUMNS_READ, 0, NULL, 0);
thd->lex->select_lex.no_wrap_view_item= FALSE;
if (res)
goto error;
@@ -1497,7 +1498,7 @@ static int mysql_test_update(Prepared_statement *stmt,
table_list->register_want_access(SELECT_ACL);
#endif
if (setup_fields(thd, Ref_ptr_array(),
- stmt->lex->value_list, MARK_COLUMNS_NONE, 0, 0) ||
+ stmt->lex->value_list, MARK_COLUMNS_NONE, 0, NULL, 0) ||
check_unique_table(thd, table_list))
goto error;
/* TODO: here we should send types of placeholders to the client. */
@@ -1672,7 +1673,7 @@ static bool mysql_test_do_fields(Prepared_statement *stmt,
DT_PREPARE | DT_CREATE))
DBUG_RETURN(TRUE);
DBUG_RETURN(setup_fields(thd, Ref_ptr_array(),
- *values, MARK_COLUMNS_NONE, 0, 0));
+ *values, MARK_COLUMNS_NONE, 0, NULL, 0));
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 90bd191a79b..8cd4ec36a55 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -807,7 +807,7 @@ JOIN::prepare(TABLE_LIST *tables_init,
thd->lex->current_select->context_analysis_place;
thd->lex->current_select->context_analysis_place= SELECT_LIST;
if (setup_fields(thd, ref_ptrs, fields_list, MARK_COLUMNS_READ,
- &all_fields, 1))
+ &all_fields, &select_lex->pre_fix, 1))
DBUG_RETURN(-1);
thd->lex->current_select->context_analysis_place= save_place;
@@ -8190,9 +8190,11 @@ best_extension_by_limited_search(JOIN *join,
best_access_path(join, s, remaining_tables, idx, disable_jbuf,
record_count, join->positions + idx, &loose_scan_pos);
- /* Compute the cost of extending the plan with 's' */
-
- current_record_count= record_count * position->records_read;
+ /* Compute the cost of extending the plan with 's', avoid overflow */
+ if (position->records_read < DBL_MAX / record_count)
+ current_record_count= record_count * position->records_read;
+ else
+ current_record_count= DBL_MAX;
current_read_time=read_time + position->read_time +
current_record_count / (double) TIME_FOR_COMPARE;
@@ -15005,10 +15007,23 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top,
nested_join= table->nested_join;
if (table->sj_on_expr && !in_sj)
{
- /*
- If this is a semi-join that is not contained within another semi-join,
- leave it intact (otherwise it is flattened)
- */
+ /*
+ If this is a semi-join that is not contained within another semi-join
+ leave it intact (otherwise it is flattened)
+ */
+ /*
+ Make sure that any semi-join appear in
+ the join->select_lex->sj_nests list only once
+ */
+ List_iterator_fast<TABLE_LIST> sj_it(join->select_lex->sj_nests);
+ TABLE_LIST *sj_nest;
+ while ((sj_nest= sj_it++))
+ {
+ if (table == sj_nest)
+ break;
+ }
+ if (sj_nest)
+ continue;
join->select_lex->sj_nests.push_back(table, join->thd->mem_root);
/*
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 1e529d9fed8..f012350d471 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -142,6 +142,12 @@ bool get_lookup_field_values(THD *, COND *, TABLE_LIST *, LOOKUP_FIELD_VALUES *)
** List all table types supported
***************************************************************************/
+
+static bool is_show_command(THD *thd)
+{
+ return sql_command_flags[thd->lex->sql_command] & CF_STATUS_COMMAND;
+}
+
static int make_version_string(char *buf, int buf_length, uint version)
{
return my_snprintf(buf, buf_length, "%d.%d", version>>8,version&0xff);
@@ -281,7 +287,7 @@ int fill_plugins(THD *thd, TABLE_LIST *tables, COND *cond)
TABLE *table= tables->table;
if (plugin_foreach_with_mask(thd, show_plugins, MYSQL_ANY_PLUGIN,
- ~PLUGIN_IS_FREED, table))
+ ~(PLUGIN_IS_FREED | PLUGIN_IS_DYING), table))
DBUG_RETURN(1);
DBUG_RETURN(0);
@@ -989,13 +995,20 @@ find_files(THD *thd, Dynamic_array<LEX_CSTRING*> *files, LEX_CSTRING *db,
if (tl.add_file(file->name))
goto err;
}
- tl.sort();
}
else
{
if (ha_discover_table_names(thd, db, dirp, &tl, false))
goto err;
}
+#if MYSQL_VERSION_ID < 100300
+ /* incomplete optimization, but a less drastic change in GA version */
+ if (!thd->lex->select_lex.order_list.elements &&
+ !thd->lex->select_lex.group_list.elements)
+#else
+ if (is_show_command(thd))
+#endif
+ tl.sort();
DBUG_PRINT("info",("found: %zu files", files->elements()));
my_dirend(dirp);
@@ -4230,7 +4243,7 @@ make_table_name_list(THD *thd, Dynamic_array<LEX_CSTRING*> *table_names,
*/
if (res == FIND_FILES_DIR)
{
- if (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND)
+ if (is_show_command(thd))
return 1;
thd->clear_error();
return 2;
@@ -5771,7 +5784,8 @@ int fill_schema_engines(THD *thd, TABLE_LIST *tables, COND *cond)
DBUG_ENTER("fill_schema_engines");
if (plugin_foreach_with_mask(thd, iter_schema_engines,
MYSQL_STORAGE_ENGINE_PLUGIN,
- ~PLUGIN_IS_FREED, tables->table))
+ ~(PLUGIN_IS_FREED | PLUGIN_IS_DYING),
+ tables->table))
DBUG_RETURN(1);
DBUG_RETURN(0);
}
@@ -6031,8 +6045,8 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
check_some_routine_access(thd, db.str, name.str, sph))
return 0;
- if (sph == Sp_handler::handler(lex->sql_command)||
- (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0)
+ if (!is_show_command(thd) ||
+ sph == Sp_handler::handler(lex->sql_command))
{
restore_record(table, s->default_values);
if (!wild || !wild[0] || !wild_case_compare(system_charset_info,
@@ -6158,6 +6172,10 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond)
DBUG_RETURN(1);
}
+ /* Disable padding temporarily so it doesn't break the query */
+ ulonglong sql_mode_was = thd->variables.sql_mode;
+ thd->variables.sql_mode &= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
+
if (proc_table->file->ha_index_init(0, 1))
{
res= 1;
@@ -6193,6 +6211,7 @@ err:
(void) proc_table->file->ha_index_end();
close_system_tables(thd, &open_tables_state_backup);
+ thd->variables.sql_mode = sql_mode_was;
DBUG_RETURN(res);
}
@@ -7781,7 +7800,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
tmp_table_param->field_count= field_count;
tmp_table_param->schema_table= 1;
SELECT_LEX *select_lex= thd->lex->current_select;
- bool keep_row_order= sql_command_flags[thd->lex->sql_command] & CF_STATUS_COMMAND;
+ bool keep_row_order= is_show_command(thd);
if (!(table= create_tmp_table(thd, tmp_table_param,
field_list, (ORDER*) 0, 0, 0,
(select_lex->options | thd->variables.option_bits |
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index c85a8be85ab..c9057849ed5 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -4037,7 +4037,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
if (!sql_field->default_value &&
!sql_field->has_default_function() &&
(sql_field->flags & NOT_NULL_FLAG) &&
- !sql_field->is_timestamp_type())
+ (!sql_field->is_timestamp_type() ||
+ opt_explicit_defaults_for_timestamp))
{
sql_field->flags|= NO_DEFAULT_VALUE_FLAG;
sql_field->pack_flag|= FIELDFLAG_NO_DEFAULT;
@@ -4046,6 +4047,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
if (thd->variables.sql_mode & MODE_NO_ZERO_DATE &&
!sql_field->default_value && !sql_field->vcol_info &&
sql_field->is_timestamp_type() &&
+ !opt_explicit_defaults_for_timestamp &&
(sql_field->flags & NOT_NULL_FLAG) &&
(type == Field::NONE || type == Field::TIMESTAMP_UN_FIELD))
{
@@ -6930,7 +6932,6 @@ bool alter_table_manage_keys(TABLE *table, int indexes_were_disabled,
case Alter_info::LEAVE_AS_IS:
if (!indexes_were_disabled)
break;
- /* disabled indexes */
/* fall through */
case Alter_info::DISABLE:
error= table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
diff --git a/sql/sql_test.cc b/sql/sql_test.cc
index 39693de80ae..56d10ddaa13 100644
--- a/sql/sql_test.cc
+++ b/sql/sql_test.cc
@@ -85,8 +85,9 @@ static my_bool print_cached_tables_callback(TDC_element *element,
while ((entry= it++))
{
THD *in_use= entry->in_use;
- printf("%-14.14s %-32s%6ld%8ld%6d %s\n",
- entry->s->db.str, entry->s->table_name.str, element->version,
+ printf("%-14.14s %-32s%6lu%8ld%6d %s\n",
+ entry->s->db.str, entry->s->table_name.str,
+ (ulong) element->version,
in_use ? (long) in_use->thread_id : (long) 0,
entry->db_stat ? 1 : 0,
in_use ? lock_descriptions[(int)entry->reginfo.lock_type] :
@@ -106,7 +107,8 @@ static void print_cached_tables(void)
tdc_iterate(0, (my_hash_walk_action) print_cached_tables_callback, NULL, true);
- printf("\nCurrent refresh version: %ld\n", tdc_refresh_version());
+ printf("\nCurrent refresh version: %ld\n",
+ (long) tdc_refresh_version());
fflush(stdout);
/* purecov: end */
return;
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 83c2e105f07..9d69f8edcff 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -362,7 +362,7 @@ int mysql_update(THD *thd,
table_list->grant.want_privilege= table->grant.want_privilege=
(SELECT_ACL & ~table->grant.privilege);
#endif
- if (setup_fields(thd, Ref_ptr_array(), values, MARK_COLUMNS_READ, 0, 0))
+ if (setup_fields(thd, Ref_ptr_array(), values, MARK_COLUMNS_READ, 0, NULL, 0))
{
free_underlaid_joins(thd, select_lex);
DBUG_RETURN(1); /* purecov: inspected */
@@ -1683,7 +1683,7 @@ int multi_update::prepare(List<Item> &not_used_values,
*/
int error= setup_fields(thd, Ref_ptr_array(),
- *values, MARK_COLUMNS_READ, 0, 0);
+ *values, MARK_COLUMNS_READ, 0, NULL, 0);
ti.rewind();
while ((table_ref= ti++))
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 8c6c6bb58e8..c43edc8a513 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -4760,17 +4760,11 @@ size_number:
switch (end_ptr[0])
{
case 'g':
- case 'G':
- text_shift_number+=10;
- /* fall through */
+ case 'G': text_shift_number+=30; break;
case 'm':
- case 'M':
- text_shift_number+=10;
- /* fall through */
+ case 'M': text_shift_number+=20; break;
case 'k':
- case 'K':
- text_shift_number+=10;
- break;
+ case 'K': text_shift_number+=10; break;
default:
my_yyabort_error((ER_WRONG_SIZE_NUMBER, MYF(0)));
}
diff --git a/sql/table.cc b/sql/table.cc
index 593c0eda3a8..5173cc7250e 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -5732,7 +5732,8 @@ Item *Field_iterator_table::create_item(THD *thd)
Item_field *item= new (thd->mem_root) Item_field(thd, &select->context, *ptr);
DBUG_ASSERT(strlen(item->name.str) == item->name.length);
if (item && thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY &&
- !thd->lex->in_sum_func && select->cur_pos_in_select_list != UNDEF_POS)
+ !thd->lex->in_sum_func && select->cur_pos_in_select_list != UNDEF_POS &&
+ select->join)
{
select->join->non_agg_fields.push_back(item);
item->marker= select->cur_pos_in_select_list;
diff --git a/sql/table.h b/sql/table.h
index 77a75335f75..3444e6da0c1 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -36,6 +36,7 @@
/* Structs that defines the TABLE */
class Item; /* Needed by ORDER */
+typedef Item (*Item_ptr);
class Item_subselect;
class Item_field;
class GRANT_TABLE;
@@ -2566,7 +2567,7 @@ typedef struct st_nested_join
table_map sj_depends_on;
/* Outer non-trivially correlated tables */
table_map sj_corr_tables;
- List<Item> sj_outer_expr_list;
+ List<Item_ptr> sj_outer_expr_list;
/**
True if this join nest node is completely covered by the query execution
plan. This means two things.