summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSergei Golubchik <serg@mariadb.org>2017-10-22 13:03:41 +0200
committerSergei Golubchik <serg@mariadb.org>2017-10-22 13:03:41 +0200
commit9d2e2d753323a934604d25144b9d1ecaf34b47d8 (patch)
tree051a721f7ea77c2278d09323e36088abe22aa66a /sql
parentd11af09865299033d5eef64531704f6ab8af5304 (diff)
parent2eb3c5e5420a724945a4cba914df25aa1e3744ce (diff)
downloadmariadb-git-9d2e2d753323a934604d25144b9d1ecaf34b47d8.tar.gz
Merge branch '10.0' into 10.1
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/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.cc15
-rw-r--r--sql/opt_range.cc39
-rw-r--r--sql/opt_subselect.cc56
-rw-r--r--sql/partition_info.cc3
-rw-r--r--sql/slave.cc1
-rw-r--r--sql/sp_head.cc12
-rw-r--r--sql/sql_acl.cc51
-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.cc14
-rw-r--r--sql/sql_lex.cc1
-rw-r--r--sql/sql_lex.h1
-rw-r--r--sql/sql_load.cc10
-rw-r--r--sql/sql_parse.cc45
-rw-r--r--sql/sql_partition.cc43
-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.cc10
-rw-r--r--sql/sql_table.cc1
-rw-r--r--sql/sql_update.cc4
-rw-r--r--sql/sql_yacc.yy12
-rw-r--r--sql/table.h3
39 files changed, 346 insertions, 206 deletions
diff --git a/sql/events.cc b/sql/events.cc
index 728d15e60f6..51f68ca4c03 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 6a28b38a612..1ffe2ce78ac 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
@@ -8902,13 +8902,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 6f3214bede2..0649d5d44aa 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
@@ -1929,7 +1929,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/item.cc b/sql/item.cc
index da1692ecbf8..ff172e69a04 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -2133,6 +2133,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};
/*
@@ -2148,7 +2151,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;
@@ -5835,7 +5837,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:
@@ -6640,6 +6642,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 ||
@@ -6821,7 +6824,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;
@@ -7994,7 +8001,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 */
@@ -9847,7 +9853,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 0ca2eaae97c..da2de2f25c5 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, 2016, MariaDB
+/* 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 b1575b81087..9c53d65b317 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 25c9ec7915b..640f27bfa1f 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 12230014f59..d923b28af5a 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -1439,6 +1439,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;
@@ -1462,6 +1466,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 d8a37b37315..4a94c3a5f89 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -1793,9 +1793,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 0e9329d501c..927ce12f079 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -502,8 +502,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 92885344cd6..2879b767af2 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -7857,21 +7857,6 @@ User_var_log_event(const char* buf, uint event_len,
we keep the flags set to UNDEF_F.
*/
uint 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));
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 1c41aa79af2..5377e4e4aea 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -8338,6 +8338,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
@@ -8393,14 +8421,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 3680dce8117..26e854cfbfd 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -1612,6 +1612,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;
@@ -1715,7 +1716,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
@@ -1729,26 +1731,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
@@ -3302,8 +3340,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++))
@@ -3314,7 +3352,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/partition_info.cc b/sql/partition_info.cc
index cd0ab970d76..ce9329e8f6a 100644
--- a/sql/partition_info.cc
+++ b/sql/partition_info.cc
@@ -39,9 +39,6 @@ partition_info *partition_info::get_clone(THD *thd)
{
MEM_ROOT *mem_root= thd->mem_root;
DBUG_ENTER("partition_info::get_clone");
-
- if (!this)
- DBUG_RETURN(NULL);
List_iterator<partition_element> part_it(partitions);
partition_element *part;
partition_info *clone= new (mem_root) partition_info();
diff --git a/sql/slave.cc b/sql/slave.cc
index db1c3305b98..da394ff711e 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -3188,7 +3188,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;
mysql_mutex_lock(&LOCK_thread_count);
thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
mysql_mutex_unlock(&LOCK_thread_count);
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index ae274ee8714..257a1d36a2a 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -141,7 +141,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:
{
@@ -2537,10 +2536,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);
@@ -4325,4 +4332,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 f72614790e1..0c7e3856e00 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -8473,6 +8473,17 @@ 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;
+}
+
/*
Initialize a TABLE_LIST array and open grant tables
@@ -10452,7 +10463,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},
@@ -10468,6 +10478,44 @@ 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)
{
@@ -12839,4 +12887,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 0893504b72d..c2ad9a649e5 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -406,6 +406,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 1f4426f2043..0888f012dda 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 1aaeb2a5584..d3d33e04d00 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -7853,13 +7853,15 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
bool setup_fields(THD *thd, Item **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));
@@ -7906,6 +7908,9 @@ bool setup_fields(THD *thd, Item **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 9e37a43aab8..c73ea374507 100644
--- a/sql/sql_base.h
+++ b/sql/sql_base.h
@@ -174,7 +174,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, Item** 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);
@@ -405,7 +406,7 @@ inline bool setup_fields_with_no_wrap(THD *thd, Item **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 3e23fc25bef..946cf13e2ae 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 c1011410970..bc067b667a6 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -766,7 +766,7 @@ send_nothing_and_leave:
DELETE_ACL, SELECT_ACL, TRUE))
DBUG_RETURN(TRUE);
if ((wild_num && setup_wild(thd, table_list, field_list, NULL, wild_num)) ||
- setup_fields(thd, NULL, field_list, MARK_COLUMNS_READ, NULL, 0) ||
+ setup_fields(thd, NULL, 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 9e58031f6a4..54850494ad0 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, 0, values, MARK_COLUMNS_NONE, 0, 0))
+ if (setup_fields(thd, 0, 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 721fff389e0..c39860593b6 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -258,7 +258,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
if (table_list->is_view())
unfix_fields(fields);
- res= setup_fields(thd, 0, fields, MARK_COLUMNS_WRITE, 0, 0);
+ res= setup_fields(thd, 0, fields, MARK_COLUMNS_WRITE, 0, NULL, 0);
/* Restore the current context. */
ctx_state.restore_state(context, table_list);
@@ -372,7 +372,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, 0, update_fields, MARK_COLUMNS_WRITE, 0, 0))
+ if (setup_fields(thd, 0, update_fields, MARK_COLUMNS_WRITE, 0, NULL, 0))
return -1;
if (insert_table_list->is_view() &&
@@ -794,7 +794,7 @@ 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, 0, *values, MARK_COLUMNS_READ, 0, 0))
+ if (setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, NULL, 0))
goto abort;
switch_to_nullable_trigger_fields(*values, table);
}
@@ -1509,12 +1509,12 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
table_list->next_local= 0;
context->resolve_in_table_list_only(table_list);
- res= (setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0) ||
+ res= (setup_fields(thd, 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, 0, update_values, MARK_COLUMNS_READ, 0, 0);
+ res= setup_fields(thd, 0, update_values, MARK_COLUMNS_READ, 0, NULL, 0);
if (!res && duplic == DUP_UPDATE)
{
@@ -3478,7 +3478,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
*/
lex->current_select= &lex->select_lex;
- res= (setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, 0) ||
+ res= (setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, NULL, 0) ||
check_insert_fields(thd, table_list, *fields, values,
!insert_into_view, 1, &map));
@@ -3531,7 +3531,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
ctx_state.get_first_name_resolution_table();
res= res || setup_fields(thd, 0, *info.update_values,
- MARK_COLUMNS_READ, 0, 0);
+ MARK_COLUMNS_READ, 0, NULL, 0);
if (!res)
{
/*
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index b3a30c69a03..8edd9b3fbd8 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -4861,4 +4861,3 @@ void binlog_unsafe_map_init()
BINLOG_DIRECT_OFF & TRX_CACHE_NOT_EMPTY);
}
#endif
-
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 240eb2373eb..116ac815ec0 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -743,6 +743,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 */
List<String> interval_list;
bool is_item_list_lookup;
/*
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 1ba9de297d4..45c5dc038fc 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -353,22 +353,22 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
Let us also prepare SET clause, altough it is probably empty
in this case.
*/
- if (setup_fields(thd, 0, set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
- setup_fields(thd, 0, set_values, MARK_COLUMNS_READ, 0, 0))
+ if (setup_fields(thd, 0, set_fields, MARK_COLUMNS_WRITE, 0, NULL, 0) ||
+ setup_fields(thd, 0, 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, 0, fields_vars, MARK_COLUMNS_WRITE, 0, 0) ||
- setup_fields(thd, 0, set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
+ if (setup_fields(thd, 0, fields_vars, MARK_COLUMNS_WRITE, 0, NULL, 0) ||
+ setup_fields(thd, 0, set_fields, MARK_COLUMNS_WRITE, 0, NULL, 0) ||
check_that_all_fields_are_given_values(thd, table, table_list))
DBUG_RETURN(TRUE);
/* Add all fields with default functions to table->write_set. */
if (table->default_field)
table->mark_default_fields_for_write();
/* Fix the expressions in SET clause */
- if (setup_fields(thd, 0, set_values, MARK_COLUMNS_READ, 0, 0))
+ if (setup_fields(thd, 0, 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 6f9e4677c0b..e14531a40f0 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1160,8 +1160,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");
@@ -1170,11 +1169,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))
@@ -1184,28 +1179,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));
}
@@ -3310,7 +3303,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;
@@ -3780,7 +3773,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);
@@ -3891,7 +3884,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 5c6174fbfac..dc5e7fe1a1a 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
@@ -4712,7 +4712,7 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
thd->work_part_info= thd->lex->part_info;
if (thd->work_part_info &&
- !(thd->work_part_info= thd->lex->part_info->get_clone(thd)))
+ !(thd->work_part_info= thd->work_part_info->get_clone(thd)))
DBUG_RETURN(TRUE);
/* ALTER_ADMIN_PARTITION is handled in mysql_admin_table */
@@ -6832,7 +6832,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;
@@ -8308,6 +8309,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)
@@ -8322,25 +8324,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,
@@ -8352,6 +8348,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 76f162920f1..6629537b2ae 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 5f503952828..f41d1e0fdbf 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;
@@ -322,7 +321,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);
@@ -943,15 +941,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
@@ -1146,7 +1146,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));
@@ -1240,7 +1239,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
@@ -1853,11 +1851,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
{
@@ -2315,64 +2313,55 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name,
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);
}
@@ -3491,7 +3480,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 e0dd04b08f6..e5b85c3be45 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1321,7 +1321,7 @@ 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, 0, *values, MARK_COLUMNS_NONE, 0, 0))
+ if (setup_fields(thd, 0, *values, MARK_COLUMNS_NONE, 0, NULL, 0))
goto error;
}
}
@@ -1411,7 +1411,7 @@ static int mysql_test_update(Prepared_statement *stmt,
table_list->register_want_access(want_privilege);
#endif
thd->lex->select_lex.no_wrap_view_item= TRUE;
- res= setup_fields(thd, 0, select->item_list, MARK_COLUMNS_READ, 0, 0);
+ res= setup_fields(thd, 0, select->item_list, MARK_COLUMNS_READ, 0, NULL, 0);
thd->lex->select_lex.no_wrap_view_item= FALSE;
if (res)
goto error;
@@ -1422,7 +1422,8 @@ static int mysql_test_update(Prepared_statement *stmt,
(SELECT_ACL & ~table_list->table->grant.privilege);
table_list->register_want_access(SELECT_ACL);
#endif
- if (setup_fields(thd, 0, stmt->lex->value_list, MARK_COLUMNS_NONE, 0, 0) ||
+ if (setup_fields(thd, 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. */
@@ -1592,7 +1593,7 @@ static bool mysql_test_do_fields(Prepared_statement *stmt,
if (open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL,
DT_PREPARE | DT_CREATE))
DBUG_RETURN(TRUE);
- DBUG_RETURN(setup_fields(thd, 0, *values, MARK_COLUMNS_NONE, 0, 0));
+ DBUG_RETURN(setup_fields(thd, 0, *values, MARK_COLUMNS_NONE, 0, NULL, 0));
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index f9da12aac29..9c6656d9e5d 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -797,7 +797,7 @@ JOIN::prepare(Item ***rref_pointer_array,
wild_num)) ||
select_lex->setup_ref_array(thd, real_og_num) ||
setup_fields(thd, (*rref_pointer_array), fields_list, MARK_COLUMNS_READ,
- &all_fields, 1) ||
+ &all_fields, &select_lex->pre_fix, 1) ||
setup_without_group(thd, (*rref_pointer_array), tables_list,
select_lex->leaf_tables, fields_list,
all_fields, &conds, order, group_list,
@@ -14639,10 +14639,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 53444ef9a02..2c02f9326db 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -271,7 +271,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);
@@ -5613,7 +5613,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);
}
@@ -6036,6 +6037,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;
@@ -6071,6 +6076,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);
}
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index fa5eb2a6796..24b86169d0f 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -6904,7 +6904,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 a87261aa34b..e1d22e6a1e9 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, 0, values, MARK_COLUMNS_READ, 0, 0))
+ if (setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, NULL, 0))
{
free_underlaid_joins(thd, select_lex);
DBUG_RETURN(1); /* purecov: inspected */
@@ -1711,7 +1711,7 @@ int multi_update::prepare(List<Item> &not_used_values,
reference tables
*/
- int error= setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0);
+ int error= setup_fields(thd, 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 b4c0c4d45c3..3fda8832f6b 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -4678,17 +4678,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 876f496a312..7d9b5292a06 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -35,6 +35,7 @@
/* Structs that defines the TABLE */
class Item; /* Needed by ORDER */
+typedef Item (*Item_ptr);
class Item_subselect;
class Item_field;
class GRANT_TABLE;
@@ -2528,7 +2529,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.