summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.org>2017-05-05 16:12:54 +0400
committerAlexander Barkov <bar@mariadb.org>2017-05-05 16:12:54 +0400
commitac53b49b1be807f588aebd83883ec93b764f5d54 (patch)
treec86cbdb535eefb15e2077a7ac2ffaeff9d76955e /sql
parent583b68e89961c35fa95a06c38988f82e33c73f4a (diff)
parentdb0917f68f2681882974afd53935aa8cba29c6b8 (diff)
downloadmariadb-git-ac53b49b1be807f588aebd83883ec93b764f5d54.tar.gz
Merge remote-tracking branch 'origin/10.2' into bb-10.2-ext
Diffstat (limited to 'sql')
-rw-r--r--sql/field.h27
-rw-r--r--sql/handler.h5
-rw-r--r--sql/item.cc20
-rw-r--r--sql/item.h54
-rw-r--r--sql/item_func.cc12
-rw-r--r--sql/item_func.h10
-rw-r--r--sql/item_geofunc.cc4
-rw-r--r--sql/item_jsonfunc.cc14
-rw-r--r--sql/item_subselect.cc45
-rw-r--r--sql/item_subselect.h8
-rw-r--r--sql/log_event.cc5
-rw-r--r--sql/mysqld.cc8
-rw-r--r--sql/opt_sum.cc2
-rw-r--r--sql/rpl_parallel.cc3
-rw-r--r--sql/share/errmsg-utf8.txt2
-rw-r--r--sql/slave.cc3
-rw-r--r--sql/sql_cte.cc72
-rw-r--r--sql/sql_cte.h21
-rw-r--r--sql/sql_derived.cc20
-rw-r--r--sql/sql_derived.h4
-rw-r--r--sql/sql_load.cc61
-rw-r--r--sql/sql_select.cc62
-rw-r--r--sql/sql_select.h2
-rw-r--r--sql/sql_union.cc14
-rw-r--r--sql/sql_window.cc7
-rw-r--r--sql/sys_vars.cc15
-rw-r--r--sql/table.cc25
-rw-r--r--sql/table.h2
-rw-r--r--sql/wsrep_hton.cc2
-rw-r--r--sql/wsrep_mysqld.h1
-rw-r--r--sql/wsrep_thd.cc33
31 files changed, 436 insertions, 127 deletions
diff --git a/sql/field.h b/sql/field.h
index ccc116f7a25..1333c924fa5 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -518,7 +518,10 @@ inline bool is_temporal_type(enum_field_types type)
enum enum_vcol_info_type
{
VCOL_GENERATED_VIRTUAL, VCOL_GENERATED_STORED,
- VCOL_DEFAULT, VCOL_CHECK_FIELD, VCOL_CHECK_TABLE
+ VCOL_DEFAULT, VCOL_CHECK_FIELD, VCOL_CHECK_TABLE,
+ /* Additional types should be added here */
+ /* Following is the highest value last */
+ VCOL_TYPE_NONE = 127 // Since the 0 value is already in use
};
static inline const char *vcol_type_name(enum_vcol_info_type type)
@@ -533,6 +536,8 @@ static inline const char *vcol_type_name(enum_vcol_info_type type)
case VCOL_CHECK_FIELD:
case VCOL_CHECK_TABLE:
return "CHECK";
+ case VCOL_TYPE_NONE:
+ return "UNTYPED";
}
return 0;
}
@@ -546,7 +551,8 @@ static inline const char *vcol_type_name(enum_vcol_info_type type)
#define VCOL_NON_DETERMINISTIC 2
#define VCOL_SESSION_FUNC 4 /* uses session data, e.g. USER or DAYNAME */
#define VCOL_TIME_FUNC 8
-#define VCOL_IMPOSSIBLE 16
+#define VCOL_AUTO_INC 16
+#define VCOL_IMPOSSIBLE 32
#define VCOL_NOT_STRICTLY_DETERMINISTIC \
(VCOL_NON_DETERMINISTIC | VCOL_TIME_FUNC | VCOL_SESSION_FUNC)
@@ -564,6 +570,7 @@ static inline const char *vcol_type_name(enum_vcol_info_type type)
class Virtual_column_info: public Sql_alloc
{
private:
+ enum_vcol_info_type vcol_type; /* Virtual column expression type */
/*
The following data is only updated by the parser and read
when a Create_field object is created/initialized.
@@ -581,7 +588,8 @@ public:
uint flags;
Virtual_column_info()
- : field_type((enum enum_field_types)MYSQL_TYPE_VIRTUAL),
+ : vcol_type((enum_vcol_info_type)VCOL_TYPE_NONE),
+ field_type((enum enum_field_types)MYSQL_TYPE_VIRTUAL),
in_partitioning_expr(FALSE), stored_in_db(FALSE),
utf8(TRUE), expr(NULL), flags(0)
{
@@ -589,6 +597,19 @@ public:
name.length= 0;
};
~Virtual_column_info() {}
+ enum_vcol_info_type get_vcol_type() const
+ {
+ return vcol_type;
+ }
+ void set_vcol_type(enum_vcol_info_type v_type)
+ {
+ vcol_type= v_type;
+ }
+ const char *get_vcol_type_name() const
+ {
+ DBUG_ASSERT(vcol_type != VCOL_TYPE_NONE);
+ return vcol_type_name(vcol_type);
+ }
enum_field_types get_real_type() const
{
return field_type;
diff --git a/sql/handler.h b/sql/handler.h
index b379f4e8b4d..7966351d02d 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -2889,10 +2889,9 @@ public:
bool keyread_enabled() { return keyread < MAX_KEY; }
int ha_start_keyread(uint idx)
{
- if (keyread_enabled())
- return 0;
+ int res= keyread_enabled() ? 0 : extra(HA_EXTRA_KEYREAD);
keyread= idx;
- return extra(HA_EXTRA_KEYREAD);
+ return res;
}
int ha_end_keyread()
{
diff --git a/sql/item.cc b/sql/item.cc
index bf962777a48..bb3dd1a1c6a 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -604,8 +604,9 @@ void Item::print_value(String *str)
str->append("NULL");
else
{
- switch (result_type()) {
+ switch (cmp_type()) {
case STRING_RESULT:
+ case TIME_RESULT:
append_unescaped(str, ptr->ptr(), ptr->length());
break;
case DECIMAL_RESULT:
@@ -614,7 +615,6 @@ void Item::print_value(String *str)
str->append(*ptr);
break;
case ROW_RESULT:
- case TIME_RESULT:
DBUG_ASSERT(0);
}
}
@@ -956,7 +956,7 @@ bool Item_field::register_field_in_write_map(void *arg)
This means:
- For default fields we can't access the same field or a field after
itself that doesn't have a non-constant default value.
- - A virtual fields can't access itself or a virtual field after itself.
+ - A virtual field can't access itself or a virtual field after itself.
- user-specified values will not see virtual fields or default expressions,
as in INSERT t1 (a) VALUES (b);
- no virtual fields can access auto-increment values
@@ -4279,7 +4279,7 @@ Item_param::eq(const Item *item, bool binary_cmp) const
void Item_param::print(String *str, enum_query_type query_type)
{
- if (state == NO_VALUE || query_type & QT_NO_DATA_EXPANSION)
+ if (state == NO_VALUE)
{
str->append('?');
}
@@ -9303,6 +9303,14 @@ void Item_cache::store(Item *item)
void Item_cache::print(String *str, enum_query_type query_type)
{
+ if (example && // There is a cached item
+ (query_type & QT_NO_DATA_EXPANSION)) // Caller is show-create-table
+ {
+ // Instead of "cache" or the cached value, print the cached item name
+ example->print(str, query_type);
+ return;
+ }
+
if (value_cached)
{
print_value(str);
@@ -9538,7 +9546,7 @@ int Item_cache_temporal::save_in_field(Field *field, bool no_conversions)
void Item_cache_temporal::store_packed(longlong val_arg, Item *example_arg)
{
- /* An explicit values is given, save it. */
+ /* An explicit value is given, save it. */
store(example_arg);
value_cached= true;
value= val_arg;
@@ -10362,7 +10370,7 @@ void Virtual_column_info::print(String *str)
(enum_query_type)(QT_ITEM_ORIGINAL_FUNC_NULLIF |
QT_ITEM_IDENT_SKIP_DB_NAMES |
QT_ITEM_IDENT_SKIP_TABLE_NAMES |
- QT_ITEM_CACHE_WRAPPER_SKIP_DETAILS |
+ QT_NO_DATA_EXPANSION |
QT_TO_SYSTEM_CHARSET),
LOWEST_PRECEDENCE);
}
diff --git a/sql/item.h b/sql/item.h
index 5b85664bf73..c24ac19e439 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -337,6 +337,19 @@ typedef struct replace_equal_field_arg
struct st_join_table *context_tab;
} REPLACE_EQUAL_FIELD_ARG;
+
+class Load_data_out_param
+{
+public:
+ Load_data_out_param() { }
+ virtual ~Load_data_out_param() { }
+ virtual void load_data_set_null_value(CHARSET_INFO *cs) = 0;
+ virtual void load_data_set_value(const char *str, uint length,
+ CHARSET_INFO *cs) = 0;
+ virtual void load_data_print(THD *thd, String *str) = 0;
+};
+
+
class Settable_routine_parameter
{
public:
@@ -1448,6 +1461,7 @@ public:
/*========= Item processors, to be used with Item::walk() ========*/
virtual bool remove_dependence_processor(void *arg) { return 0; }
virtual bool cleanup_processor(void *arg);
+ virtual bool cleanup_excluding_fields_processor(void *arg) { return cleanup_processor(arg); }
virtual bool cleanup_excluding_const_fields_processor(void *arg) { return cleanup_processor(arg); }
virtual bool collect_item_field_processor(void *arg) { return 0; }
virtual bool collect_outer_ref_processor(void *arg) {return 0; }
@@ -1689,6 +1703,14 @@ public:
delete this;
}
+ virtual Load_data_out_param *get_load_data_out_param() { return 0; }
+ Load_data_out_param *get_load_data_out_param_or_error()
+ {
+ Load_data_out_param *res= get_load_data_out_param();
+ if (!res)
+ my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), full_name());
+ return res;
+ }
virtual Item_splocal *get_item_splocal() { return 0; }
virtual Rewritable_query_parameter *get_rewritable_query_parameter()
{ return 0; }
@@ -2763,6 +2785,11 @@ public:
bool check_vcol_func_processor(void *arg)
{
context= 0;
+ if (field && (field->unireg_check == Field::NEXT_NUMBER))
+ {
+ // Auto increment fields are unsupported
+ return mark_unsupported_function(field_name.str, arg, VCOL_FIELD_REF | VCOL_AUTO_INC);
+ }
return mark_unsupported_function(field_name.str, arg, VCOL_FIELD_REF);
}
void cleanup();
@@ -2781,6 +2808,8 @@ public:
virtual void print(String *str, enum_query_type query_type);
bool exclusive_dependence_on_table_processor(void *map);
bool exclusive_dependence_on_grouping_fields_processor(void *arg);
+ bool cleanup_excluding_fields_processor(void *arg)
+ { return field ? 0 : cleanup_processor(arg); }
bool cleanup_excluding_const_fields_processor(void *arg)
{ return field && const_item() ? 0 : cleanup_processor(arg); }
@@ -4427,6 +4456,14 @@ public:
{ return depended_from != NULL; }
bool exclusive_dependence_on_grouping_fields_processor(void *arg)
{ return depended_from != NULL; }
+ bool cleanup_excluding_fields_processor(void *arg)
+ {
+ Item *item= real_item();
+ if (item && item->type() == FIELD_ITEM &&
+ ((Item_field *)item)->field)
+ return 0;
+ return cleanup_processor(arg);
+ }
bool cleanup_excluding_const_fields_processor(void *arg)
{
Item *item= real_item();
@@ -5566,8 +5603,25 @@ public:
}
bool check_vcol_func_processor(void *arg)
{
+ if (example)
+ {
+ Item::vcol_func_processor_result *res= (Item::vcol_func_processor_result*)arg;
+ example->check_vcol_func_processor(arg);
+ /*
+ Item_cache of a non-deterministic function requires re-fixing
+ even if the function itself doesn't (e.g. CURRENT_TIMESTAMP)
+ */
+ if (res->errors & VCOL_NOT_STRICTLY_DETERMINISTIC)
+ res->errors|= VCOL_SESSION_FUNC;
+ return false;
+ }
return mark_unsupported_function("cache", arg, VCOL_IMPOSSIBLE);
}
+ void cleanup()
+ {
+ clear();
+ Item_basic_constant::cleanup();
+ }
/**
Check if saved item has a non-NULL value.
Will cache value of saved item if not already done.
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 9fc626b54f5..684b5a4f67d 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -4425,7 +4425,10 @@ bool Item_func_set_user_var::fix_fields(THD *thd, Item **ref)
for (derived= unit->derived;
derived;
derived= derived->select_lex->master_unit()->derived)
+ {
derived->set_materialized_derived();
+ derived->prohibit_cond_pushdown= true;
+ }
}
return FALSE;
@@ -5400,14 +5403,15 @@ bool Item_user_var_as_out_param::fix_fields(THD *thd, Item **ref)
}
-void Item_user_var_as_out_param::set_null_value(CHARSET_INFO* cs)
+void Item_user_var_as_out_param::load_data_set_null_value(CHARSET_INFO* cs)
{
::update_hash(entry, TRUE, 0, 0, STRING_RESULT, cs, 0 /* unsigned_arg */);
}
-void Item_user_var_as_out_param::set_value(const char *str, uint length,
- CHARSET_INFO* cs)
+void Item_user_var_as_out_param::load_data_set_value(const char *str,
+ uint length,
+ CHARSET_INFO* cs)
{
::update_hash(entry, FALSE, (void*)str, length, STRING_RESULT, cs,
0 /* unsigned_arg */);
@@ -5442,7 +5446,7 @@ my_decimal* Item_user_var_as_out_param::val_decimal(my_decimal *decimal_buffer)
}
-void Item_user_var_as_out_param::print_for_load(THD *thd, String *str)
+void Item_user_var_as_out_param::load_data_print(THD *thd, String *str)
{
str->append('@');
append_identifier(thd, str, name.str, name.length);
diff --git a/sql/item_func.h b/sql/item_func.h
index 33726cd2d84..3fcde96b81a 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -2339,7 +2339,8 @@ public:
in List<Item> and desire to place this code somewhere near other functions
working with user variables.
*/
-class Item_user_var_as_out_param :public Item
+class Item_user_var_as_out_param :public Item,
+ public Load_data_out_param
{
LEX_CSTRING name;
user_var_entry *entry;
@@ -2355,9 +2356,10 @@ public:
my_decimal *val_decimal(my_decimal *decimal_buffer);
/* fix_fields() binds variable name with its entry structure */
bool fix_fields(THD *thd, Item **ref);
- void print_for_load(THD *thd, String *str);
- void set_null_value(CHARSET_INFO* cs);
- void set_value(const char *str, uint length, CHARSET_INFO* cs);
+ Load_data_out_param *get_load_data_out_param() { return this; }
+ void load_data_print(THD *thd, String *str);
+ void load_data_set_null_value(CHARSET_INFO* cs);
+ void load_data_set_value(const char *str, uint length, CHARSET_INFO* cs);
enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; }
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_user_var_as_out_param>(thd, mem_root, this); }
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index 8a61ab583c9..f2162e08323 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -1063,11 +1063,11 @@ Item_func_spatial_rel::get_mm_leaf(RANGE_OPT_PARAM *param,
tree->max_flag= NO_MAX_RANGE;
break;
case SP_WITHIN_FUNC:
- tree->min_flag= GEOM_FLAG | HA_READ_MBR_WITHIN;// NEAR_MIN;//512;
+ tree->min_flag= GEOM_FLAG | HA_READ_MBR_CONTAIN;// NEAR_MIN;//512;
tree->max_flag= NO_MAX_RANGE;
break;
case SP_CONTAINS_FUNC:
- tree->min_flag= GEOM_FLAG | HA_READ_MBR_CONTAIN;// NEAR_MIN;//512;
+ tree->min_flag= GEOM_FLAG | HA_READ_MBR_WITHIN;// NEAR_MIN;//512;
tree->max_flag= NO_MAX_RANGE;
break;
case SP_OVERLAPS_FUNC:
diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc
index b8471dc8244..c7639bc2513 100644
--- a/sql/item_jsonfunc.cc
+++ b/sql/item_jsonfunc.cc
@@ -444,6 +444,7 @@ void Item_func_json_value::fix_length_and_dec()
collation.set(args[0]->collation);
max_length= args[0]->max_length;
path.set_constant_flag(args[1]->const_item());
+ maybe_null= 1;
}
@@ -582,6 +583,7 @@ void Item_func_json_unquote::fix_length_and_dec()
{
collation.set(&my_charset_utf8_general_ci);
max_length= args[0]->max_length;
+ maybe_null= 1;
}
@@ -683,6 +685,7 @@ void Item_func_json_extract::fix_length_and_dec()
max_length= args[0]->max_length * (arg_count - 1);
mark_constant_paths(paths, args+1, arg_count-1);
+ maybe_null= 1;
}
@@ -884,6 +887,7 @@ void Item_func_json_contains::fix_length_and_dec()
{
a2_constant= args[1]->const_item();
a2_parsed= FALSE;
+ maybe_null= 1;
if (arg_count > 2)
path.set_constant_flag(args[2]->const_item());
Item_int_func::fix_length_and_dec();
@@ -1129,6 +1133,7 @@ void Item_func_json_contains_path::fix_length_and_dec()
{
ooa_constant= args[1]->const_item();
ooa_parsed= FALSE;
+ maybe_null= 1;
mark_constant_paths(paths, args+2, arg_count-2);
Item_int_func::fix_length_and_dec();
}
@@ -2042,6 +2047,7 @@ void Item_func_json_length::fix_length_and_dec()
{
if (arg_count > 1)
path.set_constant_flag(args[1]->const_item());
+ maybe_null= 1;
}
@@ -2178,6 +2184,7 @@ void Item_func_json_type::fix_length_and_dec()
{
collation.set(&my_charset_utf8_general_ci);
max_length= 12;
+ maybe_null= 1;
}
@@ -2245,6 +2252,7 @@ void Item_func_json_insert::fix_length_and_dec()
}
fix_char_length_ulonglong(char_length);
+ maybe_null= 1;
}
@@ -2491,6 +2499,7 @@ void Item_func_json_remove::fix_length_and_dec()
max_length= args[0]->max_length;
mark_constant_paths(paths, args+1, arg_count-1);
+ maybe_null= 1;
}
@@ -2674,6 +2683,7 @@ void Item_func_json_keys::fix_length_and_dec()
{
collation.set(args[0]->collation);
max_length= args[0]->max_length;
+ maybe_null= 1;
if (arg_count > 1)
path.set_constant_flag(args[1]->const_item());
}
@@ -2815,6 +2825,7 @@ void Item_func_json_search::fix_length_and_dec()
if (arg_count > 4)
mark_constant_paths(paths, args+4, arg_count-4);
+ maybe_null= 1;
}
@@ -2898,7 +2909,7 @@ String *Item_func_json_search::val_str(String *str)
json_path_with_flags *c_path= paths + n_arg - 4;
if (!c_path->parsed)
{
- String *s_p= args[n_arg]->val_str(tmp_paths + (n_arg-1));
+ String *s_p= args[n_arg]->val_str(tmp_paths + (n_arg-4));
if (s_p &&
json_path_setup(&c_path->p,s_p->charset(),(const uchar *) s_p->ptr(),
(const uchar *) s_p->ptr() + s_p->length()))
@@ -2996,6 +3007,7 @@ void Item_func_json_format::fix_length_and_dec()
{
decimals= 0;
max_length= args[0]->max_length;
+ maybe_null= 1;
}
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 8c2afe79d9b..b38bdcb7d4f 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -40,6 +40,7 @@
#include "set_var.h"
#include "sql_select.h"
#include "sql_parse.h" // check_stack_overrun
+#include "sql_cte.h"
#include "sql_test.h"
double get_post_group_estimate(JOIN* join, double join_op_rows);
@@ -311,7 +312,8 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref)
else
goto end;
- if ((uncacheable= engine->uncacheable() & ~UNCACHEABLE_EXPLAIN))
+ if ((uncacheable= engine->uncacheable() & ~UNCACHEABLE_EXPLAIN) ||
+ with_recursive_reference)
{
const_item_cache= 0;
if (uncacheable & UNCACHEABLE_RAND)
@@ -916,7 +918,7 @@ table_map Item_subselect::used_tables() const
bool Item_subselect::const_item() const
{
DBUG_ASSERT(thd);
- return (thd->lex->context_analysis_only ?
+ return (thd->lex->context_analysis_only || with_recursive_reference ?
FALSE :
forced_const || const_item_cache);
}
@@ -936,7 +938,8 @@ void Item_subselect::update_used_tables()
if (!(engine->uncacheable() & ~UNCACHEABLE_EXPLAIN))
{
// did all used tables become static?
- if (!(used_tables_cache & ~engine->upper_select_const_tables()))
+ if (!(used_tables_cache & ~engine->upper_select_const_tables()) &&
+ ! with_recursive_reference)
const_item_cache= 1;
}
}
@@ -1739,7 +1742,7 @@ bool Item_in_subselect::val_bool()
if (forced_const)
return value;
DBUG_ASSERT((engine->uncacheable() & ~UNCACHEABLE_EXPLAIN) ||
- ! engine->is_executed());
+ ! engine->is_executed() || with_recursive_reference);
null_value= was_null= FALSE;
if (exec())
{
@@ -2393,7 +2396,8 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
&list_ref));
Item *col_item= new (thd->mem_root)
Item_cond_or(thd, item_eq, item_isnull);
- if (!abort_on_null && left_expr->element_index(i)->maybe_null)
+ if (!abort_on_null && left_expr->element_index(i)->maybe_null &&
+ get_cond_guard(i))
{
disable_cond_guard_for_const_null_left_expr(i);
if (!(col_item= new (thd->mem_root)
@@ -2411,7 +2415,8 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
ref_pointer_array[i],
(char *)"<no matter>",
&list_ref));
- if (!abort_on_null && left_expr->element_index(i)->maybe_null)
+ if (!abort_on_null && left_expr->element_index(i)->maybe_null &&
+ get_cond_guard(i) )
{
disable_cond_guard_for_const_null_left_expr(i);
if (!(item_nnull_test=
@@ -2471,7 +2476,7 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
(char *)"<no matter>",
&list_ref));
item= new (thd->mem_root) Item_cond_or(thd, item, item_isnull);
- if (left_expr->element_index(i)->maybe_null)
+ if (left_expr->element_index(i)->maybe_null && get_cond_guard(i))
{
disable_cond_guard_for_const_null_left_expr(i);
if (!(item= new (thd->mem_root)
@@ -2483,7 +2488,8 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
}
*having_item= and_items(thd, *having_item, having_col_item);
}
- if (!abort_on_null && left_expr->element_index(i)->maybe_null)
+ if (!abort_on_null && left_expr->element_index(i)->maybe_null &&
+ get_cond_guard(i))
{
if (!(item= new (thd->mem_root)
Item_func_trig_cond(thd, item, get_cond_guard(i))))
@@ -2835,7 +2841,8 @@ bool Item_exists_subselect::exists2in_processor(void *opt_arg)
join->having ||
first_select->with_sum_func ||
!first_select->leaf_tables.elements||
- !join->conds)
+ !join->conds ||
+ with_recursive_reference)
DBUG_RETURN(FALSE);
DBUG_ASSERT(first_select->order_list.elements == 0 &&
@@ -3487,6 +3494,11 @@ int subselect_single_select_engine::get_identifier()
return select_lex->select_number;
}
+void subselect_single_select_engine::force_reexecution()
+{
+ executed= false;
+}
+
void subselect_single_select_engine::cleanup()
{
DBUG_ENTER("subselect_single_select_engine::cleanup");
@@ -3515,6 +3527,11 @@ bool subselect_union_engine::is_executed() const
return unit->executed;
}
+void subselect_union_engine::force_reexecution()
+{
+ unit->executed= false;
+}
+
/*
Check if last execution of the subquery engine produced any rows
@@ -3831,7 +3848,8 @@ int subselect_single_select_engine::exec()
tab->read_record.read_record= tab->save_read_record;
}
executed= 1;
- if (!(uncacheable() & ~UNCACHEABLE_EXPLAIN))
+ if (!(uncacheable() & ~UNCACHEABLE_EXPLAIN) &&
+ !item->with_recursive_reference)
item->make_const();
thd->where= save_where;
thd->lex->current_select= save_select;
@@ -6678,6 +6696,13 @@ void subselect_table_scan_engine::cleanup()
}
+void Item_subselect::register_as_with_rec_ref(With_element *with_elem)
+{
+ with_elem->sq_with_rec_ref.link_in_list(this, &this->next_with_rec_ref);
+ with_recursive_reference= true;
+}
+
+
/*
Create an execution tracker for the expression cache we're using for this
subselect; add the tracker to the query plan.
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index 22fc48391de..4c4af25edf5 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -32,6 +32,7 @@ class subselect_engine;
class subselect_hash_sj_engine;
class Item_bool_func2;
class Comp_creator;
+class With_element;
typedef class st_select_lex SELECT_LEX;
@@ -135,6 +136,9 @@ public:
*/
bool with_recursive_reference;
+ /* To link Item_subselects containing references to the same recursive CTE */
+ Item_subselect *next_with_rec_ref;
+
enum subs_type {UNKNOWN_SUBS, SINGLEROW_SUBS,
EXISTS_SUBS, IN_SUBS, ALL_SUBS, ANY_SUBS};
@@ -256,6 +260,7 @@ public:
return TRUE;
}
+ void register_as_with_rec_ref(With_element *with_elem);
void init_expr_cache_tracker(THD *thd);
Item* build_clone(THD *thd, MEM_ROOT *mem_root) { return 0; }
@@ -831,6 +836,7 @@ public:
virtual bool no_rows() = 0;
virtual enum_engine_type engine_type() { return ABSTRACT_ENGINE; }
virtual int get_identifier() { DBUG_ASSERT(0); return 0; }
+ virtual void force_reexecution() {}
protected:
void set_row(List<Item> &item_list, Item_cache **row);
};
@@ -864,6 +870,7 @@ public:
bool no_rows();
virtual enum_engine_type engine_type() { return SINGLE_SELECT_ENGINE; }
int get_identifier();
+ void force_reexecution();
friend class subselect_hash_sj_engine;
friend class Item_in_subselect;
@@ -894,6 +901,7 @@ public:
bool temp= FALSE);
bool no_tables();
bool is_executed() const;
+ void force_reexecution();
bool no_rows();
virtual enum_engine_type engine_type() { return UNION_ENGINE; }
};
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 1dca656ee08..383972d1a54 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -8403,6 +8403,11 @@ int Xid_log_event::do_apply_event(rpl_group_info *rgi)
Record any GTID in the same transaction, so slave state is transactionally
consistent.
*/
+#ifdef WITH_WSREP
+ /*Set wsrep_affected_rows = 0 */
+ thd->wsrep_affected_rows= 0;
+#endif
+
if (rgi->gtid_pending)
{
sub_id= rgi->gtid_sub_id;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 915387d6ba9..065f4d83367 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -9445,14 +9445,6 @@ static int get_options(int *argc_ptr, char ***argv_ptr)
between options, setting of multiple variables, etc.
Do them here.
*/
-
- if ((opt_log_slow_admin_statements || opt_log_queries_not_using_indexes ||
- opt_log_slow_slave_statements) &&
- !global_system_variables.sql_log_slow)
- sql_print_information("options --log-slow-admin-statements, "
- "--log-queries-not-using-indexes and "
- "--log-slow-slave-statements have no "
- "effect if --log-slow-queries is not set");
if (global_system_variables.net_buffer_length >
global_system_variables.max_allowed_packet)
{
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index e7bf4658d5c..9bc21ab3ac3 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -461,7 +461,7 @@ int opt_sum_query(THD *thd,
{
if (recalc_const_item)
item->update_used_tables();
- if (!item->const_item())
+ if (!item->const_item() && item->type() != Item::WINDOW_FUNC_ITEM)
const_result= 0;
}
}
diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc
index 6788f422cbd..aaa72da29db 100644
--- a/sql/rpl_parallel.cc
+++ b/sql/rpl_parallel.cc
@@ -1164,7 +1164,8 @@ handle_rpl_parallel_thread(void *arg)
thd->wait_for_commit_ptr= &rgi->commit_orderer;
- if (opt_gtid_ignore_duplicates)
+ if (opt_gtid_ignore_duplicates &&
+ rgi->rli->mi->using_gtid != Master_info::USE_GTID_NO)
{
int res=
rpl_global_gtid_slave_state->check_duplicate_gtid(&rgi->current_gtid,
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index b2e895b0775..97a6421ec5c 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -7453,6 +7453,8 @@ ER_JSON_PATH_EMPTY
eng "Path expression '$' is not allowed in argument %d to function '%s'."
ER_SLAVE_SAME_ID
eng "A slave with the same server_uuid/server_id as this slave has connected to the master"
+ER_FLASHBACK_NOT_SUPPORTED
+ eng "Flashback does not support %s %s"
ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
eng "Illegal parameter data types %s and %s for operation '%s'"
ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
diff --git a/sql/slave.cc b/sql/slave.cc
index 3ebd1b2ec46..b28bc1d8dc5 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -3977,7 +3977,8 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli,
DBUG_RETURN(1);
}
- if (opt_gtid_ignore_duplicates)
+ if (opt_gtid_ignore_duplicates &&
+ rli->mi->using_gtid != Master_info::USE_GTID_NO)
{
int res= rpl_global_gtid_slave_state->check_duplicate_gtid
(&serial_rgi->current_gtid, serial_rgi);
diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc
index 7c2a8cf9e65..c163044547f 100644
--- a/sql/sql_cte.cc
+++ b/sql/sql_cte.cc
@@ -141,7 +141,7 @@ bool With_clause::check_dependencies()
/*
Mark those elements where tables are defined with direct or indirect
- make recursion.
+ recursion.
*/
for (With_element *with_elem= with_list.first;
with_elem;
@@ -342,6 +342,8 @@ void With_element::check_dependencies_in_select(st_select_lex *sl,
tbl->with_internal_reference_map= get_elem_map();
if (in_subq)
sq_dep_map|= tbl->with->get_elem_map();
+ else
+ top_level_dep_map|= tbl->with->get_elem_map();
}
}
/* Now look for the dependencies in the subqueries of sl */
@@ -353,6 +355,53 @@ void With_element::check_dependencies_in_select(st_select_lex *sl,
/**
@brief
+ Find a recursive reference to this with element in subqueries of a select
+
+ @param sel The select in whose subqueries the reference
+ to be looked for
+
+ @details
+ The function looks for a recursive reference to this with element in
+ subqueries of select sl. When the first such reference is found
+ it is returned as the result.
+ The function assumes that the identification of all CTE references
+ has been performed earlier.
+
+ @retval
+ Pointer to the found recursive reference if the search succeeded
+ NULL - otherwise
+*/
+
+TABLE_LIST *With_element::find_first_sq_rec_ref_in_select(st_select_lex *sel)
+{
+ TABLE_LIST *rec_ref= NULL;
+ st_select_lex_unit *inner_unit= sel->first_inner_unit();
+ for (; inner_unit; inner_unit= inner_unit->next_unit())
+ {
+ st_select_lex *sl= inner_unit->first_select();
+ for (; sl; sl= sl->next_select())
+ {
+ for (TABLE_LIST *tbl= sl->table_list.first; tbl; tbl= tbl->next_local)
+ {
+ if (tbl->derived || tbl->nested_join)
+ continue;
+ if (tbl->with && tbl->with->owner== this->owner &&
+ (tbl->with_internal_reference_map & mutually_recursive))
+ {
+ rec_ref= tbl;
+ return rec_ref;
+ }
+ }
+ if ((rec_ref= find_first_sq_rec_ref_in_select(sl)))
+ return rec_ref;
+ }
+ }
+ return 0;
+}
+
+
+/**
+ @brief
Find the dependencies of this element on its siblings in a unit
@param unit The unit where to look for the dependencies
@@ -602,6 +651,10 @@ void With_clause::move_anchors_ahead()
@details
If the specification of this with element contains anchors the method
moves them at the very beginning of the specification.
+ Additionally for the other selects of the specification if none of them
+ contains a recursive reference to this with element or a mutually recursive
+ one the method looks for the first such reference in the first recursive
+ select and set a pointer to it in this->sq_rec_ref.
*/
void With_element::move_anchors_ahead()
@@ -618,6 +671,11 @@ void With_element::move_anchors_ahead()
sl->move_node(new_pos);
new_pos= sl->next_select();
}
+ else if (!sq_rec_ref && no_rec_ref_on_top_level())
+ {
+ sq_rec_ref= find_first_sq_rec_ref_in_select(sl);
+ DBUG_ASSERT(sq_rec_ref != NULL);
+ }
last_sl= sl;
}
if (spec->union_distinct)
@@ -967,6 +1025,17 @@ With_element *st_select_lex::find_table_def_in_with_clauses(TABLE_LIST *table)
bool TABLE_LIST::set_as_with_table(THD *thd, With_element *with_elem)
{
+ if (table)
+ {
+ /*
+ This table was prematurely identified as a temporary table.
+ We correct it here, but it's not a nice solution in the case
+ when the temporary table with this name is not used anywhere
+ else in the query.
+ */
+ thd->mark_tmp_table_as_free_for_reuse(table);
+ table= 0;
+ }
with= with_elem;
if (!with_elem->is_referenced() || with_elem->is_recursive)
derived= with_elem->spec;
@@ -1228,6 +1297,7 @@ bool st_select_lex::check_subqueries_with_recursive_references()
continue;
Item_subselect *subq= (Item_subselect *) sl_master->item;
subq->with_recursive_reference= true;
+ subq->register_as_with_rec_ref(tbl->with);
}
}
return false;
diff --git a/sql/sql_cte.h b/sql/sql_cte.h
index a87c1b8acbd..85676df9d39 100644
--- a/sql/sql_cte.h
+++ b/sql/sql_cte.h
@@ -46,6 +46,16 @@ private:
/* Dependency map of with elements mutually recursive with this with element */
table_map mutually_recursive;
/*
+ Dependency map built only for the top level references i.e. for those that
+ are encountered in from lists of the selects of the specification unit
+ */
+ table_map top_level_dep_map;
+ /*
+ Points to a recursive reference in subqueries.
+ Used only for specifications without recursive references on the top level.
+ */
+ TABLE_LIST *sq_rec_ref;
+ /*
The next with element from the circular chain of the with elements
mutually recursive with this with element.
(If This element is simply recursive than next_mutually_recursive contains
@@ -119,11 +129,15 @@ public:
*/
select_union_recursive *rec_result;
+ /* List of Item_subselects containing recursive references to this CTE */
+ SQL_I_List<Item_subselect> sq_with_rec_ref;
+
With_element(LEX_CSTRING *name,
List <LEX_CSTRING> list,
st_select_lex_unit *unit)
: next(NULL), base_dep_map(0), derived_dep_map(0),
sq_dep_map(0), work_dep_map(0), mutually_recursive(0),
+ top_level_dep_map(0), sq_rec_ref(NULL),
next_mutually_recursive(NULL), references(0),
query_name(name), column_list(list), spec(unit),
is_recursive(false), with_anchor(false),
@@ -151,6 +165,8 @@ public:
bool check_dependency_on(With_element *with_elem)
{ return base_dep_map & with_elem->get_elem_map(); }
+ TABLE_LIST *find_first_sq_rec_ref_in_select(st_select_lex *sel);
+
bool set_unparsed_spec(THD *thd, char *spec_start, char *spec_end);
st_select_lex_unit *clone_parsed_spec(THD *thd, TABLE_LIST *with_table);
@@ -174,11 +190,16 @@ public:
bool contains_sq_with_recursive_reference()
{ return sq_dep_map & mutually_recursive; }
+ bool no_rec_ref_on_top_level()
+ { return !(top_level_dep_map & mutually_recursive); }
+
table_map get_mutually_recursive() { return mutually_recursive; }
With_element *get_next_mutually_recursive()
{ return next_mutually_recursive; }
+ TABLE_LIST *get_sq_rec_ref() { return sq_rec_ref; }
+
bool is_anchor(st_select_lex *sel);
void move_anchors_ahead();
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 827fb21edf4..cd8540eb072 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -646,6 +646,23 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
SELECT_LEX *first_select= unit->first_select();
+ if (derived->is_recursive_with_table() &&
+ !derived->is_with_table_recursive_reference() &&
+ !derived->with->rec_result && derived->with->get_sq_rec_ref())
+ {
+ /*
+ This is a non-recursive reference to a recursive CTE whose
+ specification unit has not been prepared at the regular processing of
+ derived table references. This can happen only in the case when
+ the specification unit has no recursive references at the top level.
+ Force the preparation of the specification unit. Use a recursive
+ table reference from a subquery for this.
+ */
+ DBUG_ASSERT(derived->with->get_sq_rec_ref());
+ if (mysql_derived_prepare(lex->thd, lex, derived->with->get_sq_rec_ref()))
+ DBUG_RETURN(TRUE);
+ }
+
if (unit->prepared && derived->is_recursive_with_table() &&
!derived->table)
{
@@ -1148,6 +1165,9 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived)
st_select_lex_unit *unit= derived->get_unit();
st_select_lex *sl= unit->first_select();
+ if (derived->prohibit_cond_pushdown)
+ DBUG_RETURN(false);
+
/* Do not push conditions into constant derived */
if (unit->executed)
DBUG_RETURN(false);
diff --git a/sql/sql_derived.h b/sql/sql_derived.h
index c451e423032..f098cf39083 100644
--- a/sql/sql_derived.h
+++ b/sql/sql_derived.h
@@ -39,10 +39,6 @@ bool mysql_derived_cleanup(THD *thd, LEX *lex, TABLE_LIST *derived);
Item *delete_not_needed_parts(THD *thd, Item *cond);
-#if 0
-bool pushdown_cond_for_derived(THD *thd, Item **cond, TABLE_LIST *derived);
-#else
bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived);
-#endif
#endif /* SQL_DERIVED_INCLUDED */
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index b430aea4c0b..1a5fac30536 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -431,7 +431,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
else
tot_length+= field->field_length;
}
- else if (item->type() == Item::STRING_ITEM)
+ else if (item->get_load_data_out_param())
use_vars= 1;
}
if (use_blobs && !ex->line_term->length() && !field_term->length())
@@ -814,11 +814,7 @@ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex,
if (item->real_type() == Item::FIELD_ITEM)
append_identifier(thd, &query_str, item->name.str, item->name.length);
else
- {
- /* Actually Item_user_var_as_out_param despite claiming STRING_ITEM. */
- DBUG_ASSERT(item->type() == Item::STRING_ITEM);
- ((Item_user_var_as_out_param *)item)->print_for_load(thd, &query_str);
- }
+ item->get_load_data_out_param()->load_data_print(thd, &query_str);
}
query_str.append(")");
}
@@ -1062,6 +1058,7 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
uint length;
uchar *pos;
Item *real_item;
+ Load_data_out_param *out_param;
if (read_info.read_field())
break;
@@ -1104,18 +1101,11 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
}
/* Do not auto-update this field. */
field->set_has_explicit_value();
- }
- else if (item->type() == Item::STRING_ITEM)
- {
- ((Item_user_var_as_out_param *)item)->set_null_value(
- read_info.read_charset);
}
+ else if ((out_param= item->get_load_data_out_param_or_error()))
+ out_param->load_data_set_null_value(read_info.read_charset);
else
- {
- my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name());
DBUG_RETURN(1);
- }
-
continue;
}
@@ -1129,16 +1119,11 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
field->store((char*) pos, length, read_info.read_charset);
field->set_has_explicit_value();
}
- else if (item->type() == Item::STRING_ITEM)
- {
- ((Item_user_var_as_out_param *)item)->set_value((char*) pos, length,
- read_info.read_charset);
- }
+ else if ((out_param= item->get_load_data_out_param_or_error()))
+ out_param->load_data_set_value((const char *) pos, length,
+ read_info.read_charset);
else
- {
- my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name());
DBUG_RETURN(1);
- }
}
if (thd->is_error())
@@ -1158,6 +1143,7 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
break;
for (; item ; item= it++)
{
+ Load_data_out_param *out_param;
Item *real_item= item->real_item();
if (real_item->type() == Item::FIELD_ITEM)
{
@@ -1183,16 +1169,10 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
ER_THD(thd, ER_WARN_TOO_FEW_RECORDS),
thd->get_stmt_da()->current_row_for_warning());
}
- else if (item->type() == Item::STRING_ITEM)
- {
- ((Item_user_var_as_out_param *)item)->set_null_value(
- read_info.read_charset);
- }
+ else if ((out_param= item->get_load_data_out_param_or_error()))
+ out_param->load_data_set_null_value(read_info.read_charset);
else
- {
- my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name());
DBUG_RETURN(1);
- }
}
}
@@ -1288,6 +1268,7 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
while ((item= it++))
{
+ Load_data_out_param *out_param;
/* If this line is to be skipped we don't want to fill field or var */
if (skip_lines)
continue;
@@ -1319,14 +1300,15 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
/* Do not auto-update this field. */
field->set_has_explicit_value();
}
+ else if ((out_param= item->get_load_data_out_param_or_error()))
+ out_param->load_data_set_null_value(cs);
else
- ((Item_user_var_as_out_param *) item)->set_null_value(cs);
+ DBUG_RETURN(1);
continue;
}
if (item->type() == Item::FIELD_ITEM)
{
-
Field *field= ((Item_field *)item)->field;
field->set_notnull();
if (field == table->next_number_field)
@@ -1334,10 +1316,12 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
field->store((char *) tag->value.ptr(), tag->value.length(), cs);
field->set_has_explicit_value();
}
+ else if ((out_param= item->get_load_data_out_param_or_error()))
+ out_param->load_data_set_value((const char *) tag->value.ptr(),
+ tag->value.length(), cs);
else
- ((Item_user_var_as_out_param *) item)->set_value(
- (char *) tag->value.ptr(),
- tag->value.length(), cs);
+ DBUG_RETURN(1);
+
}
if (read_info.error)
@@ -1357,6 +1341,7 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
for ( ; item; item= it++)
{
+ Load_data_out_param *out_param;
if (item->type() == Item::FIELD_ITEM)
{
/*
@@ -1371,8 +1356,10 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
ER_THD(thd, ER_WARN_TOO_FEW_RECORDS),
thd->get_stmt_da()->current_row_for_warning());
}
+ else if ((out_param= item->get_load_data_out_param_or_error()))
+ out_param->load_data_set_null_value(cs);
else
- ((Item_user_var_as_out_param *)item)->set_null_value(cs);
+ DBUG_RETURN(1);
}
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index b3c427bf043..280849b8b33 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -868,7 +868,8 @@ JOIN::prepare(TABLE_LIST *tables_init,
select_lex->check_unrestricted_recursive(
thd->variables.only_standard_compliant_cte))
DBUG_RETURN(-1);
- select_lex->check_subqueries_with_recursive_references();
+ if (select_lex->first_execution)
+ select_lex->check_subqueries_with_recursive_references();
int res= check_and_do_in_subquery_rewrites(this);
@@ -1091,7 +1092,7 @@ int JOIN::optimize()
!skip_sort_order && !no_order && (order || group_list),
select_distinct);
uint select_nr= select_lex->select_number;
- JOIN_TAB *curr_tab= join_tab + top_join_tab_count;
+ JOIN_TAB *curr_tab= join_tab + exec_join_tab_cnt();
for (uint i= 0; i < aggr_tables; i++, curr_tab++)
{
if (select_nr == INT_MAX)
@@ -1445,7 +1446,8 @@ JOIN::optimize_inner()
}
DBUG_PRINT("info",("Select tables optimized away"));
- zero_result_cause= "Select tables optimized away";
+ if (!select_lex->have_window_funcs())
+ zero_result_cause= "Select tables optimized away";
tables_list= 0; // All tables resolved
const_tables= top_join_tab_count= table_count;
/*
@@ -2238,13 +2240,14 @@ bool JOIN::make_aggr_tables_info()
bool implicit_grouping_with_window_funcs= implicit_grouping &&
select_lex->have_window_funcs();
-
+ bool implicit_grouping_without_tables= implicit_grouping &&
+ !tables_list;
/*
Setup last table to provide fields and all_fields lists to the next
node in the plan.
*/
- if (join_tab && top_join_tab_count)
+ if (join_tab && top_join_tab_count && tables_list)
{
join_tab[top_join_tab_count - 1].fields= &fields_list;
join_tab[top_join_tab_count - 1].all_fields= &all_fields;
@@ -2290,7 +2293,7 @@ bool JOIN::make_aggr_tables_info()
order= query.order_by;
aggr_tables++;
- curr_tab= join_tab + top_join_tab_count;
+ curr_tab= join_tab + exec_join_tab_cnt();
bzero(curr_tab, sizeof(JOIN_TAB));
curr_tab->ref.key= -1;
curr_tab->join= this;
@@ -2368,7 +2371,7 @@ bool JOIN::make_aggr_tables_info()
single table queries, thus it is sufficient to test only the first
join_tab element of the plan for its access method.
*/
- if (join_tab && top_join_tab_count &&
+ if (join_tab && top_join_tab_count && tables_list &&
join_tab->is_using_loose_index_scan())
tmp_table_param.precomputed_group_by=
!join_tab->is_using_agg_loose_index_scan();
@@ -2378,7 +2381,7 @@ bool JOIN::make_aggr_tables_info()
if (need_tmp)
{
aggr_tables++;
- curr_tab= join_tab + top_join_tab_count;
+ curr_tab= join_tab + exec_join_tab_cnt();
bzero(curr_tab, sizeof(JOIN_TAB));
curr_tab->ref.key= -1;
if (only_const_tables())
@@ -2437,8 +2440,9 @@ bool JOIN::make_aggr_tables_info()
/* Change sum_fields reference to calculated fields in tmp_table */
items1= ref_ptr_array_slice(2);
- if (sort_and_group || curr_tab->table->group ||
- tmp_table_param.precomputed_group_by)
+ if ((sort_and_group || curr_tab->table->group ||
+ tmp_table_param.precomputed_group_by) &&
+ !implicit_grouping_without_tables)
{
if (change_to_use_tmp_fields(thd, items1,
tmp_fields_list1, tmp_all_fields1,
@@ -2778,7 +2782,7 @@ bool JOIN::make_aggr_tables_info()
- duplicate value removal
Both of these operations are done after window function computation step.
*/
- curr_tab= join_tab + top_join_tab_count + aggr_tables - 1;
+ curr_tab= join_tab + exec_join_tab_cnt() + aggr_tables - 1;
if (select_lex->window_funcs.elements)
{
curr_tab->window_funcs_step= new Window_funcs_computation;
@@ -2793,7 +2797,7 @@ bool JOIN::make_aggr_tables_info()
// Reset before execution
set_items_ref_array(items0);
if (join_tab)
- join_tab[top_join_tab_count + aggr_tables - 1].next_select=
+ join_tab[exec_join_tab_cnt() + aggr_tables - 1].next_select=
setup_end_select_func(this, NULL);
group= has_group_by;
@@ -2834,7 +2838,7 @@ JOIN::create_postjoin_aggr_table(JOIN_TAB *tab, List<Item> *table_fields,
tmp_table_param.using_outer_summary_function=
tab->tmp_table_param->using_outer_summary_function;
tab->join= this;
- DBUG_ASSERT(tab > join_tab || select_lex->have_window_funcs());
+ DBUG_ASSERT(tab > tab->join->join_tab || !top_join_tab_count || !tables_list);
if (tab > join_tab)
(tab - 1)->next_select= sub_select_postjoin_aggr;
tab->aggr= new (thd->mem_root) AGGR_OP(tab);
@@ -2861,7 +2865,8 @@ JOIN::create_postjoin_aggr_table(JOIN_TAB *tab, List<Item> *table_fields,
if (make_sum_func_list(all_fields, fields_list, true))
goto err;
if (prepare_sum_aggregators(sum_funcs,
- !join_tab->is_using_agg_loose_index_scan()))
+ !(tables_list &&
+ join_tab->is_using_agg_loose_index_scan())))
goto err;
if (setup_sum_funcs(thd, sum_funcs))
goto err;
@@ -3122,7 +3127,7 @@ JOIN::reinit()
if (aggr_tables)
{
- JOIN_TAB *curr_tab= join_tab + top_join_tab_count;
+ JOIN_TAB *curr_tab= join_tab + exec_join_tab_cnt();
JOIN_TAB *end_tab= curr_tab + aggr_tables;
for ( ; curr_tab < end_tab; curr_tab++)
{
@@ -3249,7 +3254,7 @@ void JOIN::save_explain_data(Explain_query *output, bool can_overwrite,
Explain_union *eu= output->get_union(nr);
explain= &eu->fake_select_lex_explain;
join_tab[0].tracker= eu->get_fake_select_lex_tracker();
- for (uint i=0 ; i < top_join_tab_count + aggr_tables; i++)
+ for (uint i=0 ; i < exec_join_tab_cnt() + aggr_tables; i++)
{
if (join_tab[i].filesort)
{
@@ -3318,7 +3323,8 @@ void JOIN::exec_inner()
if (result->prepare2())
DBUG_VOID_RETURN;
- if (!tables_list && (table_count || !select_lex->with_sum_func))
+ if (!tables_list && (table_count || !select_lex->with_sum_func) &&
+ !select_lex->have_window_funcs())
{ // Only test of functions
if (select_options & SELECT_DESCRIBE)
select_describe(this, FALSE, FALSE, FALSE,
@@ -12010,7 +12016,7 @@ void JOIN::cleanup(bool full)
w/o tables: they don't have some members initialized and
WALK_OPTIMIZATION_TABS may not work correctly for them.
*/
- if (table_count)
+ if (top_join_tab_count && tables_list)
{
for (tab= first_breadth_first_tab(); tab;
tab= next_breadth_first_tab(first_breadth_first_tab(),
@@ -12024,7 +12030,7 @@ void JOIN::cleanup(bool full)
cleaned= true;
//psergey2: added (Q: why not in the above loop?)
{
- JOIN_TAB *curr_tab= join_tab + top_join_tab_count;
+ JOIN_TAB *curr_tab= join_tab + exec_join_tab_cnt();
for (uint i= 0; i < aggr_tables; i++, curr_tab++)
{
if (curr_tab->aggr)
@@ -17785,7 +17791,7 @@ void set_postjoin_aggr_write_func(JOIN_TAB *tab)
}
}
else if (join->sort_and_group && !tmp_tbl->precomputed_group_by &&
- !join->sort_and_group_aggr_tab)
+ !join->sort_and_group_aggr_tab && join->tables_list)
{
DBUG_PRINT("info",("Using end_write_group"));
aggr->set_write_func(end_write_group);
@@ -17877,7 +17883,8 @@ do_select(JOIN *join, Procedure *procedure)
if (join->pushdown_query->store_data_in_temp_table)
{
- JOIN_TAB *last_tab= join->join_tab + join->table_count;
+ JOIN_TAB *last_tab= join->join_tab + join->table_count -
+ join->exec_join_tab_cnt();
last_tab->next_select= end_send;
enum_nested_loop_state state= last_tab->aggr->end_send();
@@ -17948,7 +17955,8 @@ do_select(JOIN *join, Procedure *procedure)
dbug_serve_apcs(join->thd, 1);
);
- JOIN_TAB *join_tab= join->join_tab + join->const_tables;
+ JOIN_TAB *join_tab= join->join_tab +
+ (join->tables_list ? join->const_tables : 0);
if (join->outer_ref_cond && !join->outer_ref_cond->val_int())
error= NESTED_LOOP_NO_MORE_ROWS;
else
@@ -23188,8 +23196,11 @@ change_refs_to_tmp_fields(THD *thd, Ref_ptr_array ref_pointer_array,
uint i, border= all_fields.elements - elements;
for (i= 0; (item= it++); i++)
{
- res_all_fields.push_back(new_item= item->get_tmp_table_item(thd),
- thd->mem_root);
+ if (item->type() == Item::SUM_FUNC_ITEM && item->const_item())
+ new_item= item;
+ else
+ new_item= item->get_tmp_table_item(thd);
+ res_all_fields.push_back(new_item, thd->mem_root);
ref_pointer_array[((i < border)? all_fields.elements-i-1 : i-border)]=
new_item;
}
@@ -24444,7 +24455,7 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta,
void save_agg_explain_data(JOIN *join, Explain_select *xpl_sel)
{
- JOIN_TAB *join_tab=join->join_tab + join->top_join_tab_count;
+ JOIN_TAB *join_tab=join->join_tab + join->exec_join_tab_cnt();
Explain_aggr_node *prev_node;
Explain_aggr_node *node= xpl_sel->aggr_tree;
bool is_analyze= join->thd->lex->analyze_stmt;
@@ -24536,6 +24547,7 @@ int JOIN::save_explain_data_intern(Explain_query *output,
if (select_lex->master_unit()->derived)
explain->connection_type= Explain_node::EXPLAIN_NODE_DERIVED;
+ save_agg_explain_data(this, explain);
output->add_node(explain);
}
else if (pushdown_query)
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 86b8a56fb43..96764fd7f00 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -1492,6 +1492,8 @@ public:
/* True if the plan guarantees that it will be returned zero or one row */
bool only_const_tables() { return const_tables == table_count; }
+ /* Number of tables actually joined at the top level */
+ uint exec_join_tab_cnt() { return tables_list ? top_join_tab_count : 0; }
int prepare(TABLE_LIST *tables, uint wind_num,
COND *conds, uint og_num, ORDER *order, bool skip_order_by,
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index ff455e680f7..bf25c0be74e 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -302,7 +302,8 @@ int select_union_recursive::send_data(List<Item> &values)
{
int rc= select_unit::send_data(values);
- if (write_err != HA_ERR_FOUND_DUPP_KEY)
+ if (write_err != HA_ERR_FOUND_DUPP_KEY &&
+ write_err != HA_ERR_FOUND_DUPP_UNIQUE)
{
int err;
if ((err= incr_table->file->ha_write_tmp_row(table->record[0])))
@@ -1205,7 +1206,8 @@ bool st_select_lex_unit::exec()
if (executed && !uncacheable && !describe)
DBUG_RETURN(FALSE);
executed= 1;
- if (!(uncacheable & ~UNCACHEABLE_EXPLAIN) && item)
+ if (!(uncacheable & ~UNCACHEABLE_EXPLAIN) && item &&
+ !item->with_recursive_reference)
item->make_const();
saved_error= optimize();
@@ -1537,9 +1539,15 @@ bool st_select_lex_unit::exec_recursive()
!is_unrestricted);
if (!with_element->rec_result->first_rec_table_to_update)
with_element->rec_result->first_rec_table_to_update= rec_table;
- if (with_element->level == 1)
+ if (with_element->level == 1 && rec_table->reginfo.join_tab)
rec_table->reginfo.join_tab->preread_init_done= true;
}
+ for (Item_subselect *sq= with_element->sq_with_rec_ref.first;
+ sq;
+ sq= sq->next_with_rec_ref)
+ {
+ sq->engine->force_reexecution();
+ }
thd->lex->current_select= lex_select_save;
err:
diff --git a/sql/sql_window.cc b/sql/sql_window.cc
index ac70d3d0f32..74e1ad25183 100644
--- a/sql/sql_window.cc
+++ b/sql/sql_window.cc
@@ -2761,7 +2761,7 @@ bool Window_func_runner::exec(THD *thd, TABLE *tbl, SORT_INFO *filesort_result)
bool Window_funcs_sort::exec(JOIN *join)
{
THD *thd= join->thd;
- JOIN_TAB *join_tab= &join->join_tab[join->top_join_tab_count];
+ JOIN_TAB *join_tab= join->join_tab + join->exec_join_tab_cnt();
/* Sort the table based on the most specific sorting criteria of
the window functions. */
@@ -2841,11 +2841,6 @@ bool Window_funcs_sort::setup(THD *thd, SQL_SELECT *sel,
sort_order= order;
}
filesort= new (thd->mem_root) Filesort(sort_order, HA_POS_ERROR, true, NULL);
- if (!join_tab->join->top_join_tab_count)
- {
- filesort->tracker=
- new (thd->mem_root) Filesort_tracker(thd->lex->analyze_stmt);
- }
/* Apply the same condition that the subsequent sort has. */
filesort->select= sel;
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index b4583b1c187..e5fe26c6b94 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -456,11 +456,22 @@ static bool binlog_format_check(sys_var *self, THD *thd, set_var *var)
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
"MariaDB Galera and flashback do not support binlog format: %s",
binlog_format_names[var->save_result.ulonglong_value]);
+ /*
+ We allow setting up binlog_format other then ROW for session scope when
+ wsrep/flasback is enabled.This is done because of 2 reasons
+ 1. User might want to run pt-table-checksum.
+ 2. SuperUser knows what is doing :-)
+ For refrence:- MDEV-7322
+ */
if (var->type == OPT_GLOBAL)
{
- WSREP_ERROR("MariaDB Galera and flashback do not support binlog format: %s",
- binlog_format_names[var->save_result.ulonglong_value]);
+ if (WSREP(thd))
+ WSREP_ERROR("MariaDB Galera does not support binlog format: %s",
+ binlog_format_names[var->save_result.ulonglong_value]);
+ else
+ my_error(ER_FLASHBACK_NOT_SUPPORTED,MYF(0),"binlog_format",
+ binlog_format_names[var->save_result.ulonglong_value]);
return true;
}
}
diff --git a/sql/table.cc b/sql/table.cc
index eac12578b15..fa8ed3c2587 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -1980,6 +1980,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
unireg_check == Field::TIMESTAMP_DN_FIELD)
{
reg_field->default_value= new (&share->mem_root) Virtual_column_info();
+ reg_field->default_value->set_vcol_type(VCOL_DEFAULT);
reg_field->default_value->stored_in_db= 1;
share->default_expressions++;
}
@@ -2378,6 +2379,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
if (!(vcol_info= new (&share->mem_root) Virtual_column_info()))
goto err;
+
/* The following can only be true for check_constraints */
if (field_nr != UINT_MAX16)
@@ -2387,6 +2389,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
}
vcol_screen_pos+= FRM_VCOL_NEW_HEADER_SIZE;
+ vcol_info->set_vcol_type((enum_vcol_info_type) type);
if (name_length)
{
vcol_info->name.str= strmake_root(&share->mem_root,
@@ -2739,7 +2742,7 @@ bool fix_session_vcol_expr(THD *thd, Virtual_column_info *vcol)
if (!(vcol->flags & (VCOL_TIME_FUNC|VCOL_SESSION_FUNC)))
DBUG_RETURN(0);
- vcol->expr->cleanup();
+ vcol->expr->walk(&Item::cleanup_excluding_fields_processor, 0, 0);
DBUG_ASSERT(!vcol->expr->fixed);
DBUG_RETURN(fix_vcol_expr(thd, vcol));
}
@@ -2823,9 +2826,24 @@ static bool fix_and_check_vcol_expr(THD *thd, TABLE *table,
int error= func_expr->walk(&Item::check_vcol_func_processor, 0, &res);
if (error || (res.errors & VCOL_IMPOSSIBLE))
- { // this can only happen if the frm was corrupted
+ {
+ // this can only happen if the frm was corrupted
my_error(ER_VIRTUAL_COLUMN_FUNCTION_IS_NOT_ALLOWED, MYF(0), res.name,
- "???", "?????");
+ vcol->get_vcol_type_name(), vcol->name.str);
+ DBUG_RETURN(1);
+ }
+ else if (res.errors & VCOL_AUTO_INC)
+ {
+ /*
+ An auto_increment field may not be used in an expression for
+ a check constraint, a default value or a generated column
+
+ Note that this error condition is not detected during parsing
+ of the statement because the field item does not have a field
+ pointer at that time
+ */
+ my_error(ER_VIRTUAL_COLUMN_FUNCTION_IS_NOT_ALLOWED, MYF(0),
+ "AUTO_INCREMENT", vcol->get_vcol_type_name(), res.name);
DBUG_RETURN(1);
}
vcol->flags= res.errors;
@@ -2896,6 +2914,7 @@ unpack_vcol_info_from_frm(THD *thd, MEM_ROOT *mem_root, TABLE *table,
if (error)
goto end;
+ vcol_storage.vcol_info->set_vcol_type(vcol->get_vcol_type());
vcol_storage.vcol_info->stored_in_db= vcol->stored_in_db;
vcol_storage.vcol_info->name= vcol->name;
vcol_storage.vcol_info->utf8= vcol->utf8;
diff --git a/sql/table.h b/sql/table.h
index ebe5ced5bc1..a3690b0e8ca 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -2157,6 +2157,8 @@ struct TABLE_LIST
/* I_S: Flags to open_table (e.g. OPEN_TABLE_ONLY or OPEN_VIEW_ONLY) */
uint i_s_requested_object;
+ bool prohibit_cond_pushdown;
+
/*
I_S: how to read the tables (SKIP_OPEN_TABLE/OPEN_FRM_ONLY/OPEN_FULL_TABLE)
*/
diff --git a/sql/wsrep_hton.cc b/sql/wsrep_hton.cc
index 0ccd533eac1..1121bb65fe3 100644
--- a/sql/wsrep_hton.cc
+++ b/sql/wsrep_hton.cc
@@ -323,7 +323,7 @@ wsrep_run_wsrep_commit(THD *thd, bool all)
DBUG_ENTER("wsrep_run_wsrep_commit");
if (thd->get_stmt_da()->is_error()) {
- WSREP_ERROR("commit issue, error: %d %s",
+ WSREP_DEBUG("commit issue, error: %d %s",
thd->get_stmt_da()->sql_errno(), thd->get_stmt_da()->message());
}
diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h
index c553b4ba27e..7eae366df7a 100644
--- a/sql/wsrep_mysqld.h
+++ b/sql/wsrep_mysqld.h
@@ -51,6 +51,7 @@ struct wsrep_thd_shadow {
char *db;
size_t db_length;
my_hrtime_t user_time;
+ longlong row_count_func;
};
// Global wsrep parameters
diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc
index a2d3b4923ab..4acf8a3bf1e 100644
--- a/sql/wsrep_thd.cc
+++ b/sql/wsrep_thd.cc
@@ -167,6 +167,7 @@ static void wsrep_prepare_bf_thd(THD *thd, struct wsrep_thd_shadow* shadow)
shadow->db = thd->db;
shadow->db_length = thd->db_length;
shadow->user_time = thd->user_time;
+ shadow->row_count_func= thd->get_row_count_func();
thd->reset_db(NULL, 0);
}
@@ -187,6 +188,7 @@ static void wsrep_return_from_bf_mode(THD *thd, struct wsrep_thd_shadow* shadow)
thd->wsrep_rgi->cleanup_after_session();
delete thd->wsrep_rgi;
thd->wsrep_rgi = NULL;
+ thd->set_row_count_func(shadow->row_count_func);
}
void wsrep_replay_transaction(THD *thd)
@@ -201,12 +203,31 @@ void wsrep_replay_transaction(THD *thd)
WSREP_ERROR("replay issue, thd has reported status already");
}
+
/*
PS reprepare observer should have been removed already.
open_table() will fail if we have dangling observer here.
*/
DBUG_ASSERT(thd->m_reprepare_observer == NULL);
+ struct da_shadow
+ {
+ enum Diagnostics_area::enum_diagnostics_status status;
+ ulonglong affected_rows;
+ ulonglong last_insert_id;
+ char message[MYSQL_ERRMSG_SIZE];
+ };
+ struct da_shadow da_status;
+ da_status.status= thd->get_stmt_da()->status();
+ if (da_status.status == Diagnostics_area::DA_OK)
+ {
+ da_status.affected_rows= thd->get_stmt_da()->affected_rows();
+ da_status.last_insert_id= thd->get_stmt_da()->last_insert_id();
+ strmake(da_status.message,
+ thd->get_stmt_da()->message(),
+ sizeof(da_status.message)-1);
+ }
+
thd->get_stmt_da()->reset_diagnostics_area();
thd->wsrep_conflict_state= REPLAYING;
@@ -274,7 +295,17 @@ void wsrep_replay_transaction(THD *thd)
}
else
{
- my_ok(thd);
+ if (da_status.status == Diagnostics_area::DA_OK)
+ {
+ my_ok(thd,
+ da_status.affected_rows,
+ da_status.last_insert_id,
+ da_status.message);
+ }
+ else
+ {
+ my_ok(thd);
+ }
}
break;
case WSREP_TRX_FAIL: