summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSergei Golubchik <serg@mariadb.org>2017-10-24 14:53:18 +0200
committerSergei Golubchik <serg@mariadb.org>2017-10-24 14:53:18 +0200
commite0a1c745ec3ed1ec6c0375a2a624697c29f480a6 (patch)
tree24ded2c6ebe3ea3413ce56af89ea0f2f63bb3a39 /sql
parent4ec88ea9c3ec52d996b39167d12a61ab95fdeacc (diff)
parent2aa51f528fd5d23cc54eca8fbd07e88e7b2993c7 (diff)
downloadmariadb-git-e0a1c745ec3ed1ec6c0375a2a624697c29f480a6.tar.gz
Merge branch '10.1' into 10.2
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.cc16
-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.h10
-rw-r--r--sql/log_event.cc17
-rw-r--r--sql/opt_range.cc39
-rw-r--r--sql/opt_subselect.cc56
-rw-r--r--sql/slave.cc1
-rw-r--r--sql/sp_head.cc12
-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.cc45
-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.cc23
-rw-r--r--sql/sql_show.cc35
-rw-r--r--sql/sql_table.cc5
-rw-r--r--sql/sql_update.cc4
-rw-r--r--sql/sql_yacc.yy12
-rw-r--r--sql/table.h3
38 files changed, 380 insertions, 217 deletions
diff --git a/sql/events.cc b/sql/events.cc
index 1f2501646cb..07cfdf1028a 100644
--- a/sql/events.cc
+++ b/sql/events.cc
@@ -188,8 +188,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;
@@ -205,8 +205,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;
@@ -228,8 +228,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:
@@ -243,7 +243,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 6b3f836048f..bff936b7052 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
@@ -8913,13 +8913,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 a0fbdffec90..cc5521114f4 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
@@ -1933,7 +1933,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 2e499238dba..1f3df447f24 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -404,7 +404,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 *)
@@ -429,8 +429,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);
@@ -5200,6 +5200,7 @@ void Discovered_table_list::remove_duplicates()
{
LEX_STRING **src= tables->front();
LEX_STRING **dst= src;
+ sort();
while (++dst <= tables->back())
{
LEX_STRING *s= *src, *d= *dst;
@@ -5267,10 +5268,12 @@ int ha_discover_table_names(THD *thd, LEX_STRING *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
{
@@ -5283,8 +5286,6 @@ int ha_discover_table_names(THD *thd, LEX_STRING *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 910fdd06303..efd82d4f873 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -2248,6 +2248,9 @@ bool Item_func_or_sum::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};
/*
@@ -2263,7 +2266,6 @@ bool Item_func_or_sum::agg_item_set_converter(const DTCollation &coll,
safe_args[1]= args[item_sep];
}
- THD *thd= current_thd;
bool res= FALSE;
uint i;
@@ -6188,7 +6190,7 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table,
Field_string(max_length, maybe_null, name, collation.collation);
break;
}
- /* Fall through */
+ /* fall through */
case MYSQL_TYPE_ENUM:
case MYSQL_TYPE_SET:
case MYSQL_TYPE_VAR_STRING:
@@ -7000,6 +7002,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 ||
@@ -7355,7 +7358,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;
@@ -8529,7 +8536,6 @@ bool Item_direct_view_ref::send(Protocol *protocol, String *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 */
@@ -10597,7 +10603,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 76708fb3570..9b94a08c34e 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 cd58e15fe8b..d7326df04ce 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; };
void illegal_method_call(const char *);
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 29433be4af8..e6907747a8c 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -1448,6 +1448,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;
@@ -1471,6 +1475,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 2724bb63eda..01b07c00816 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -1852,9 +1852,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 dccccc479ef..354a54a5c1a 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -546,8 +546,16 @@ public:
{ return val_decimal_from_date(decimal_value); }
Field *create_field_for_create_select(TABLE *table)
{ return tmp_table_field_from_field_type(table, false, false); }
+#if MARIADB_VERSION_ID > 100300
+#error This code should be removed in 10.3, to use the derived save_in_field()
+#else
int save_in_field(Field *field, bool no_conversions)
- { return save_date_in_field(field); }
+ {
+ return field_type() == MYSQL_TYPE_TIME ?
+ save_time_in_field(field) :
+ save_date_in_field(field);
+ }
+#endif
void fix_length_and_dec();
};
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 8932d0f261d..8840861bfdc 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -8673,22 +8673,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= ((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 3d9c1aef4b8..04d2059eb62 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -8536,6 +8536,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
@@ -8591,14 +8619,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 f37db88957a..b16fec1de3e 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -1614,6 +1614,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;
@@ -1717,7 +1718,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
@@ -1731,26 +1733,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
@@ -3299,8 +3337,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++))
@@ -3311,7 +3349,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 1b1a597fa2a..19905841a2c 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 b3edcdca474..20c02fce752 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -119,7 +119,6 @@ sp_get_item_value(THD *thd, Item *item, String *str)
case DECIMAL_RESULT:
if (item->field_type() != MYSQL_TYPE_BIT)
return item->val_str(str);
- else {/* Bit type is handled as binary string */}
/* fall through */
case STRING_RESULT:
{
@@ -2545,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_type == TYPE_ENUM_PROCEDURE);
@@ -4327,4 +4334,3 @@ sp_add_to_query_tables(THD *thd, LEX *lex,
lex->add_to_query_tables(table);
return table;
}
-
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index af49eefa2a5..555865804f9 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -9194,6 +9194,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.
@@ -11198,7 +11208,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},
@@ -11214,6 +11223,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)
{
@@ -13599,4 +13645,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 daa36f6c32a..8d233fd3d0a 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 dd3c2694202..5222381270a 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 ea57e1d19c9..3f5af2985db 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -6994,13 +6994,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()));
@@ -7050,6 +7052,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 374ac56c3d8..9fb94e92d09 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);
@@ -364,7 +365,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 95960ac131a..c91992a9029 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 a30f9ae2a32..7b7a7e3f804 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -762,7 +762,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 a226ea17eb3..a94349527bf 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);
@@ -378,7 +379,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() &&
@@ -804,7 +805,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);
}
@@ -1529,13 +1531,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)
{
@@ -3525,7 +3527,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));
@@ -3578,7 +3581,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 9ab09c9fe7e..9ec9b5cdf95 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -783,6 +783,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 ea05d42673f..fbdc00433a6 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 7662cc404a7..bf5144bfda6 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1414,8 +1414,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");
@@ -1424,11 +1423,7 @@ static my_bool deny_updates_if_read_only_option(THD *thd,
LEX *lex= thd->lex;
- const my_bool user_is_super=
- ((ulong)(thd->security_ctx->master_access & SUPER_ACL) ==
- (ulong)SUPER_ACL);
-
- if (user_is_super)
+ if (thd->security_ctx->master_access & SUPER_ACL)
DBUG_RETURN(FALSE);
if (!(sql_command_flags[lex->sql_command] & CF_CHANGES_DATA))
@@ -1438,28 +1433,26 @@ static my_bool deny_updates_if_read_only_option(THD *thd,
if (lex->sql_command == SQLCOM_UPDATE_MULTI)
DBUG_RETURN(FALSE);
+ if (lex->sql_command == SQLCOM_CREATE_DB ||
+ lex->sql_command == SQLCOM_DROP_DB)
+ DBUG_RETURN(TRUE);
+
/*
a table-to-be-created is not in the temp table list yet,
so CREATE TABLE needs a special treatment
*/
- const bool update_real_tables= lex->sql_command == SQLCOM_CREATE_TABLE ?
- !lex->tmp_table() : some_non_temp_table_to_be_updated(thd, all_tables);
-
- const bool create_or_drop_databases=
- (lex->sql_command == SQLCOM_CREATE_DB) ||
- (lex->sql_command == SQLCOM_DROP_DB);
-
- if (update_real_tables || create_or_drop_databases)
- {
- /*
- An attempt was made to modify one or more non-temporary tables.
- */
- DBUG_RETURN(TRUE);
- }
+ 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);
- /* Assuming that only temporary tables are modified. */
- DBUG_RETURN(FALSE);
+ /* Now, check thd->temporary_tables list */
+ DBUG_RETURN(some_non_temp_table_to_be_updated(thd, all_tables));
}
@@ -3794,7 +3787,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;
@@ -4271,7 +4264,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);
@@ -4382,7 +4375,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 6e4da0fbbf2..3f06c950472 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 2d0ec788332..acca6f61f01 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 17b68750bc6..2f0a5eaf9c9 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);
@@ -944,15 +942,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
@@ -1147,7 +1147,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));
@@ -1247,7 +1246,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
@@ -1865,11 +1863,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
{
@@ -2341,64 +2339,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);
}
@@ -3525,7 +3514,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 6724346a490..19c714cfc01 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1379,7 +1379,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;
}
}
@@ -1470,7 +1471,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;
@@ -1482,7 +1483,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. */
@@ -1655,7 +1656,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 f4f0e46afed..46e1a912250 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -804,7 +804,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;
@@ -14708,10 +14708,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 579cbcd878e..c7ba6705cb0 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -139,6 +139,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);
@@ -278,7 +284,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);
@@ -986,13 +992,20 @@ find_files(THD *thd, Dynamic_array<LEX_STRING*> *files, LEX_STRING *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);
@@ -4137,7 +4150,7 @@ make_table_name_list(THD *thd, Dynamic_array<LEX_STRING*> *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;
@@ -5685,7 +5698,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);
}
@@ -5957,13 +5971,13 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
val_int() == TYPE_ENUM_PROCEDURE))
return 0;
- if ((lex->sql_command == SQLCOM_SHOW_STATUS_PROC &&
+ if (!is_show_command(thd) ||
+ (lex->sql_command == SQLCOM_SHOW_STATUS_PROC &&
proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() ==
TYPE_ENUM_PROCEDURE) ||
(lex->sql_command == SQLCOM_SHOW_STATUS_FUNC &&
proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() ==
- TYPE_ENUM_FUNCTION) ||
- (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0)
+ TYPE_ENUM_FUNCTION))
{
restore_record(table, s->default_values);
if (!wild || !wild[0] || !wild_case_compare(system_charset_info,
@@ -6088,6 +6102,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;
@@ -6123,6 +6141,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);
}
@@ -7706,7 +7725,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 db9340d7977..c112b01ba36 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -4141,7 +4141,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) &&
- !is_timestamp_type(sql_field->sql_type))
+ (!is_timestamp_type(sql_field->sql_type) ||
+ opt_explicit_defaults_for_timestamp))
{
sql_field->flags|= NO_DEFAULT_VALUE_FLAG;
sql_field->pack_flag|= FIELDFLAG_NO_DEFAULT;
@@ -4150,6 +4151,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 &&
is_timestamp_type(sql_field->sql_type) &&
+ !opt_explicit_defaults_for_timestamp &&
(sql_field->flags & NOT_NULL_FLAG) &&
(type == Field::NONE || type == Field::TIMESTAMP_UN_FIELD))
{
@@ -7051,7 +7053,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_update.cc b/sql/sql_update.cc
index b1069efbbc8..a2cfcbabc95 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -359,7 +359,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 */
@@ -1691,7 +1691,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 ded0332bc53..434cd10d1b9 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -4772,17 +4772,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.h b/sql/table.h
index 22846e05bde..7e3f94a60ff 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;
@@ -2560,7 +2561,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.