summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2017-03-08 19:44:22 +0200
committerMarko Mäkelä <marko.makela@mariadb.com>2017-03-09 08:53:08 +0200
commitad0c218a440575fa6fb6634aca7a08448a4360e0 (patch)
treeb52811847ce51c92eabdeed3104df8b0168943df /sql
parentbb4ef470c24cdbcedba3dd3dcda3b3d88b6fb491 (diff)
parent9fe92a9770a801c4cd36390620486be4cb06752b (diff)
downloadmariadb-git-ad0c218a440575fa6fb6634aca7a08448a4360e0.tar.gz
Merge 10.0 into 10.1
Also, implement MDEV-11027 a little differently from 5.5 and 10.0: recv_apply_hashed_log_recs(): Change the return type back to void (DB_SUCCESS was always returned). Report progress also via systemd using sd_notifyf().
Diffstat (limited to 'sql')
-rw-r--r--sql/ha_partition.cc1
-rw-r--r--sql/handler.cc5
-rw-r--r--sql/item_cmpfunc.cc12
-rw-r--r--sql/item_cmpfunc.h7
-rw-r--r--sql/item_subselect.cc9
-rw-r--r--sql/item_subselect.h9
-rw-r--r--sql/log_slow.h33
-rw-r--r--sql/mysqld.cc4
-rw-r--r--sql/opt_range.cc14
-rw-r--r--sql/partition_info.cc2
-rw-r--r--sql/sql_acl.cc6
-rw-r--r--sql/sql_db.cc9
-rw-r--r--sql/sql_derived.cc3
-rw-r--r--sql/sql_join_cache.cc5
-rw-r--r--sql/sql_parse.cc66
-rw-r--r--sql/sql_parse.h3
-rw-r--r--sql/sql_select.cc79
-rw-r--r--sql/table.cc2
18 files changed, 149 insertions, 120 deletions
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index 90efd730875..29054c76cbe 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -7271,6 +7271,7 @@ int ha_partition::reset(void)
result= tmp;
}
bitmap_clear_all(&m_partitions_to_reset);
+ m_extra_prepare_for_update= FALSE;
DBUG_RETURN(result);
}
diff --git a/sql/handler.cc b/sql/handler.cc
index 7ac8dd63e9e..751b6d3ca3c 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -3355,6 +3355,7 @@ void handler::print_error(int error, myf errflag)
textno=ER_FILE_USED;
break;
case ENOENT:
+ case ENOTDIR:
textno=ER_FILE_NOT_FOUND;
break;
case ENOSPC:
@@ -3831,7 +3832,6 @@ int handler::delete_table(const char *name)
int saved_error= 0;
int error= 0;
int enoent_or_zero;
- char buff[FN_REFLEN];
if (ht->discover_table)
enoent_or_zero= 0; // the table may not exist in the engine, it's ok
@@ -3840,8 +3840,7 @@ int handler::delete_table(const char *name)
for (const char **ext=bas_ext(); *ext ; ext++)
{
- fn_format(buff, name, "", *ext, MY_UNPACK_FILENAME|MY_APPEND_EXT);
- if (mysql_file_delete_with_symlink(key_file_misc, buff, MYF(0)))
+ if (my_handler_delete_with_symlink(key_file_misc, name, *ext, 0))
{
if (my_errno != ENOENT)
{
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index e78f73ee03c..d2ffa0e64f9 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -5151,6 +5151,18 @@ bool Item_func_like::with_sargable_pattern() const
}
+SEL_TREE *Item_func_like::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
+{
+ MEM_ROOT *tmp_root= param->mem_root;
+ param->thd->mem_root= param->old_root;
+ bool sargable_pattern= with_sargable_pattern();
+ param->thd->mem_root= tmp_root;
+ return sargable_pattern ?
+ Item_bool_func2::get_mm_tree(param, cond_ptr) :
+ Item_func::get_mm_tree(param, cond_ptr);
+}
+
+
bool Item_func_like::fix_fields(THD *thd, Item **ref)
{
DBUG_ASSERT(fixed == 0);
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 697420df0e8..4015255e7ad 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -1842,12 +1842,7 @@ public:
}
void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
table_map usable_tables, SARGABLE_PARAM **sargables);
- SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
- {
- return with_sargable_pattern() ?
- Item_bool_func2::get_mm_tree(param, cond_ptr) :
- Item_func::get_mm_tree(param, cond_ptr);
- }
+ SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr);
Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond)
{
/*
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 3157d666e9b..6330165702e 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -928,7 +928,7 @@ void Item_subselect::update_used_tables()
if (!forced_const)
{
recalc_used_tables(parent_select, FALSE);
- if (!engine->uncacheable())
+ if (!(engine->uncacheable() & ~UNCACHEABLE_EXPLAIN))
{
// did all used tables become static?
if (!(used_tables_cache & ~engine->upper_select_const_tables()))
@@ -2104,6 +2104,7 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join,
We can encounter "NULL IN (SELECT ...)". Wrap the added condition
within a trig_cond.
*/
+ disable_cond_guard_for_const_null_left_expr(0);
item= new (thd->mem_root) Item_func_trig_cond(thd, item, get_cond_guard(0));
}
@@ -2128,6 +2129,7 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join,
having= new (thd->mem_root) Item_is_not_null_test(thd, this, having);
if (left_expr->maybe_null)
{
+ disable_cond_guard_for_const_null_left_expr(0);
if (!(having= new (thd->mem_root) Item_func_trig_cond(thd, having,
get_cond_guard(0))))
DBUG_RETURN(true);
@@ -2146,6 +2148,7 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join,
*/
if (!abort_on_null && left_expr->maybe_null)
{
+ disable_cond_guard_for_const_null_left_expr(0);
if (!(item= new (thd->mem_root) Item_func_trig_cond(thd, item,
get_cond_guard(0))))
DBUG_RETURN(true);
@@ -2175,6 +2178,7 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join,
(char *)"<result>"));
if (!abort_on_null && left_expr->maybe_null)
{
+ disable_cond_guard_for_const_null_left_expr(0);
if (!(new_having= new (thd->mem_root) Item_func_trig_cond(thd, new_having,
get_cond_guard(0))))
DBUG_RETURN(true);
@@ -2374,6 +2378,7 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
Item_cond_or(thd, item_eq, item_isnull);
if (!abort_on_null && left_expr->element_index(i)->maybe_null)
{
+ disable_cond_guard_for_const_null_left_expr(i);
if (!(col_item= new (thd->mem_root)
Item_func_trig_cond(thd, col_item, get_cond_guard(i))))
DBUG_RETURN(true);
@@ -2391,6 +2396,7 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
(char *)"<list ref>"));
if (!abort_on_null && left_expr->element_index(i)->maybe_null)
{
+ disable_cond_guard_for_const_null_left_expr(i);
if (!(item_nnull_test=
new (thd->mem_root)
Item_func_trig_cond(thd, item_nnull_test, get_cond_guard(i))))
@@ -2451,6 +2457,7 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
item= new (thd->mem_root) Item_cond_or(thd, item, item_isnull);
if (left_expr->element_index(i)->maybe_null)
{
+ disable_cond_guard_for_const_null_left_expr(i);
if (!(item= new (thd->mem_root)
Item_func_trig_cond(thd, item, get_cond_guard(i))))
DBUG_RETURN(true);
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index d18db4aab86..6669027338e 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -618,6 +618,15 @@ public:
bool expr_cache_is_needed(THD *thd);
inline bool left_expr_has_null();
+ void disable_cond_guard_for_const_null_left_expr(int i)
+ {
+ if (left_expr->const_item() && !left_expr->is_expensive())
+ {
+ if (left_expr->element_index(i)->is_null())
+ set_cond_guard_var(i,FALSE);
+ }
+ }
+
int optimize(double *out_rows, double *cost);
/*
Return the identifier that we could use to identify the subquery for the
diff --git a/sql/log_slow.h b/sql/log_slow.h
index 3ae2060cc27..aea5b149263 100644
--- a/sql/log_slow.h
+++ b/sql/log_slow.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2009 Monty Program Ab
+/* Copyright (C) 2009, 2017, MariaDB Corporation.
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
@@ -16,23 +16,22 @@
/* Defining what to log to slow log */
#define LOG_SLOW_VERBOSITY_INIT 0
-#define LOG_SLOW_VERBOSITY_INNODB (1 << 0)
-#define LOG_SLOW_VERBOSITY_QUERY_PLAN (1 << 1)
-#define LOG_SLOW_VERBOSITY_EXPLAIN (1 << 2)
+#define LOG_SLOW_VERBOSITY_INNODB (1U << 0)
+#define LOG_SLOW_VERBOSITY_QUERY_PLAN (1U << 1)
+#define LOG_SLOW_VERBOSITY_EXPLAIN (1U << 2)
#define QPLAN_INIT QPLAN_QC_NO
-#define QPLAN_ADMIN (1 << 0)
-#define QPLAN_FILESORT (1 << 1)
-#define QPLAN_FILESORT_DISK (1 << 2)
-#define QPLAN_FULL_JOIN (1 << 3)
-#define QPLAN_FULL_SCAN (1 << 4)
-#define QPLAN_QC (1 << 5)
-#define QPLAN_QC_NO (1 << 6)
-#define QPLAN_TMP_DISK (1 << 7)
-#define QPLAN_TMP_TABLE (1 << 8)
-#define QPLAN_FILESORT_PRIORITY_QUEUE (1 << 9)
-
+#define QPLAN_ADMIN (1U << 0)
+#define QPLAN_FILESORT (1U << 1)
+#define QPLAN_FILESORT_DISK (1U << 2)
+#define QPLAN_FULL_JOIN (1U << 3)
+#define QPLAN_FULL_SCAN (1U << 4)
+#define QPLAN_QC (1U << 5)
+#define QPLAN_QC_NO (1U << 6)
+#define QPLAN_TMP_DISK (1U << 7)
+#define QPLAN_TMP_TABLE (1U << 8)
+#define QPLAN_FILESORT_PRIORITY_QUEUE (1U << 9)
+
/* ... */
-#define QPLAN_MAX (((ulong) 1) << 31) /* reserved as placeholder */
-
+#define QPLAN_MAX (1U << 31) /* reserved as placeholder */
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 2607307ceee..4f83e19f905 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -21,7 +21,7 @@
#ifndef __WIN__
#include <netdb.h> // getservbyname, servent
#endif
-#include "sql_parse.h" // test_if_data_home_dir
+#include "sql_parse.h" // path_starts_from_data_home_dir
#include "sql_cache.h" // query_cache, query_cache_*
#include "sql_locale.h" // MY_LOCALES, my_locales, my_locale_by_name
#include "sql_show.h" // free_status_vars, add_status_vars,
@@ -8612,7 +8612,7 @@ static int mysql_init_variables(void)
mysql_home[0]= pidfile_name[0]= log_error_file[0]= 0;
#if defined(HAVE_REALPATH) && !defined(HAVE_valgrind) && !defined(HAVE_BROKEN_REALPATH)
/* We can only test for sub paths if my_symlink.c is using realpath */
- myisam_test_invalid_symlink= test_if_data_home_dir;
+ mysys_test_invalid_symlink= path_starts_from_data_home_dir;
#endif
opt_log= 0;
opt_bin_log= opt_bin_log_used= 0;
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 0577ef01bb2..bb4f7370ac9 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -9300,6 +9300,13 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2)
if (!tmp->next_key_part)
{
+ if (key2->use_count)
+ {
+ SEL_ARG *key2_cpy= new SEL_ARG(*key2);
+ if (key2_cpy)
+ return 0;
+ key2= key2_cpy;
+ }
/*
tmp->next_key_part is empty: cut the range that is covered
by tmp from key2.
@@ -9331,13 +9338,6 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2)
key2: [---]
tmp: [---------]
*/
- if (key2->use_count)
- {
- SEL_ARG *key2_cpy= new SEL_ARG(*key2);
- if (key2_cpy)
- return 0;
- key2= key2_cpy;
- }
key2->copy_max_to_min(tmp);
continue;
}
diff --git a/sql/partition_info.cc b/sql/partition_info.cc
index a92c7686eaf..bc0db9e0174 100644
--- a/sql/partition_info.cc
+++ b/sql/partition_info.cc
@@ -27,7 +27,7 @@
#include "sql_partition.h" // partition_info.h: LIST_PART_ENTRY
// NOT_A_PARTITION_ID
#include "partition_info.h"
-#include "sql_parse.h" // test_if_data_home_dir
+#include "sql_parse.h"
#include "sql_acl.h" // *_ACL
#include "sql_base.h" // fill_record
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 912930d60f3..cb4c3cb1049 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -9096,13 +9096,13 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop,
case USER_ACL:
acl_user->user.str= strdup_root(&acl_memroot, user_to->user.str);
acl_user->user.length= user_to->user.length;
- acl_user->host.hostname= strdup_root(&acl_memroot, user_to->host.str);
- acl_user->hostname_length= user_to->host.length;
+ update_hostname(&acl_user->host, strdup_root(&acl_memroot, user_to->host.str));
+ acl_user->hostname_length= strlen(acl_user->host.hostname);
break;
case DB_ACL:
acl_db->user= strdup_root(&acl_memroot, user_to->user.str);
- acl_db->host.hostname= strdup_root(&acl_memroot, user_to->host.str);
+ update_hostname(&acl_db->host, strdup_root(&acl_memroot, user_to->host.str));
break;
case COLUMN_PRIVILEGES_HASH:
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index cb50301d79d..701f4e6aa4e 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -846,7 +846,8 @@ mysql_rm_db_internal(THD *thd,char *db, bool if_exists, bool silent)
if there exists a table with the name 'db', so let's just do it
separately. We know this file exists and needs to be deleted anyway.
*/
- if (my_delete_with_symlink(path, MYF(0)) && my_errno != ENOENT)
+ if (my_handler_delete_with_symlink(key_file_misc, path, "", MYF(0)) &&
+ my_errno != ENOENT)
{
my_error(EE_DELETE, MYF(0), path, my_errno);
DBUG_RETURN(true);
@@ -1149,9 +1150,9 @@ static bool find_db_tables_and_rm_known_files(THD *thd, MY_DIR *dirp,
strxmov(filePath, path, "/", file->name, NullS);
/*
We ignore ENOENT error in order to skip files that was deleted
- by concurrently running statement like REAPIR TABLE ...
+ by concurrently running statement like REPAIR TABLE ...
*/
- if (my_delete_with_symlink(filePath, MYF(0)) &&
+ if (my_handler_delete_with_symlink(key_file_misc, filePath, "", MYF(0)) &&
my_errno != ENOENT)
{
my_error(EE_DELETE, MYF(0), filePath, my_errno);
@@ -1267,7 +1268,7 @@ long mysql_rm_arc_files(THD *thd, MY_DIR *dirp, const char *org_path)
continue;
}
strxmov(filePath, org_path, "/", file->name, NullS);
- if (mysql_file_delete_with_symlink(key_file_misc, filePath, MYF(MY_WME)))
+ if (my_handler_delete_with_symlink(key_file_misc, filePath, "", MYF(MY_WME)))
{
goto err;
}
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 493f231bb39..d9457ba6624 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -447,6 +447,9 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived)
{
Item *expr= derived->on_expr;
expr= and_conds(thd, expr, dt_select->join ? dt_select->join->conds : 0);
+ if (expr)
+ expr->top_level_item();
+
if (expr && (derived->prep_on_expr || expr != derived->on_expr))
{
derived->on_expr= expr;
diff --git a/sql/sql_join_cache.cc b/sql/sql_join_cache.cc
index 818598110ca..9df993cf035 100644
--- a/sql/sql_join_cache.cc
+++ b/sql/sql_join_cache.cc
@@ -589,6 +589,11 @@ void JOIN_CACHE::create_remaining_fields()
{
MY_BITMAP *rem_field_set;
TABLE *table= tab->table;
+#if MYSQL_VERSION_ID < 100204
+ empty_record(table);
+#else
+#error remove
+#endif
if (all_read_fields)
rem_field_set= table->read_set;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 45815fe7a02..7af299f3f06 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2123,12 +2123,12 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
#endif
case SCH_COLUMNS:
case SCH_STATISTICS:
- {
#ifdef DONT_ALLOW_SHOW_COMMANDS
my_message(ER_NOT_ALLOWED_COMMAND,
ER_THD(thd, ER_NOT_ALLOWED_COMMAND), MYF(0));
DBUG_RETURN(1);
#else
+ {
DBUG_ASSERT(table_ident);
TABLE_LIST **query_tables_last= lex->query_tables_last;
schema_select_lex= new SELECT_LEX();
@@ -7248,7 +7248,7 @@ static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length,
}
/*
- When you modify mysql_parse(), you may need to mofify
+ When you modify mysql_parse(), you may need to modify
mysql_test_parse_for_slave() in this same file.
*/
@@ -9134,48 +9134,24 @@ bool check_ident_length(LEX_STRING *ident)
}
-C_MODE_START
-
/*
Check if path does not contain mysql data home directory
SYNOPSIS
- test_if_data_home_dir()
- dir directory
+ path_starts_from_data_home_dir()
+ dir directory, with all symlinks resolved
RETURN VALUES
0 ok
1 error ; Given path contains data directory
*/
+extern "C" {
-int test_if_data_home_dir(const char *dir)
+int path_starts_from_data_home_dir(const char *path)
{
- char path[FN_REFLEN];
- int dir_len;
- DBUG_ENTER("test_if_data_home_dir");
+ int dir_len= strlen(path);
+ DBUG_ENTER("path_starts_from_data_home_dir");
- if (!dir)
- DBUG_RETURN(0);
-
- /*
- data_file_name and index_file_name include the table name without
- extension. Mostly this does not refer to an existing file. When
- comparing data_file_name or index_file_name against the data
- directory, we try to resolve all symbolic links. On some systems,
- we use realpath(3) for the resolution. This returns ENOENT if the
- resolved path does not refer to an existing file. my_realpath()
- does then copy the requested path verbatim, without symlink
- resolution. Thereafter the comparison can fail even if the
- requested path is within the data directory. E.g. if symlinks to
- another file system are used. To make realpath(3) return the
- resolved path, we strip the table name and compare the directory
- path only. If the directory doesn't exist either, table creation
- will fail anyway.
- */
-
- (void) fn_format(path, dir, "", "",
- (MY_RETURN_REAL_PATH|MY_RESOLVE_SYMLINKS));
- dir_len= strlen(path);
if (mysql_unpacked_real_data_home_len<= dir_len)
{
if (dir_len > mysql_unpacked_real_data_home_len &&
@@ -9203,7 +9179,31 @@ int test_if_data_home_dir(const char *dir)
DBUG_RETURN(0);
}
-C_MODE_END
+}
+
+/*
+ Check if path does not contain mysql data home directory
+
+ SYNOPSIS
+ test_if_data_home_dir()
+ dir directory
+
+ RETURN VALUES
+ 0 ok
+ 1 error ; Given path contains data directory
+*/
+
+int test_if_data_home_dir(const char *dir)
+{
+ char path[FN_REFLEN];
+ DBUG_ENTER("test_if_data_home_dir");
+
+ if (!dir)
+ DBUG_RETURN(0);
+
+ (void) fn_format(path, dir, "", "", MY_RETURN_REAL_PATH);
+ DBUG_RETURN(path_starts_from_data_home_dir(path));
+}
int error_if_data_home_dir(const char *path, const char *what)
diff --git a/sql/sql_parse.h b/sql/sql_parse.h
index c50090a95cc..da9721df0b7 100644
--- a/sql/sql_parse.h
+++ b/sql/sql_parse.h
@@ -33,7 +33,8 @@ enum enum_mysql_completiontype {
COMMIT_RELEASE=-1, COMMIT=0, COMMIT_AND_CHAIN=6
};
-extern "C" int test_if_data_home_dir(const char *dir);
+extern "C" int path_starts_from_data_home_dir(const char *dir);
+int test_if_data_home_dir(const char *dir);
int error_if_data_home_dir(const char *path, const char *what);
bool multi_update_precheck(THD *thd, TABLE_LIST *tables);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index cc07067bc8d..cb39cb3a8b8 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -8679,8 +8679,6 @@ get_best_combination(JOIN *join)
form=join->table[tablenr]=j->table;
used_tables|= form->map;
form->reginfo.join_tab=j;
- if (!*j->on_expr_ref)
- form->reginfo.not_exists_optimize=0; // Only with LEFT JOIN
DBUG_PRINT("info",("type: %d", j->type));
if (j->type == JT_CONST)
goto loop_end; // Handled in make_join_stat..
@@ -9542,7 +9540,10 @@ make_outerjoin_info(JOIN *join)
tab->cond_equal= tbl->cond_equal;
if (embedding && !embedding->is_active_sjm())
tab->first_upper= embedding->nested_join->first_nested;
- }
+ }
+ else if (!embedding)
+ tab->table->reginfo.not_exists_optimize= 0;
+
for ( ; embedding ; embedding= embedding->embedding)
{
if (embedding->is_active_sjm())
@@ -9552,7 +9553,10 @@ make_outerjoin_info(JOIN *join)
}
/* Ignore sj-nests: */
if (!(embedding->on_expr && embedding->outer_join))
+ {
+ tab->table->reginfo.not_exists_optimize= 0;
continue;
+ }
NESTED_JOIN *nested_join= embedding->nested_join;
if (!nested_join->counter)
{
@@ -9568,17 +9572,10 @@ make_outerjoin_info(JOIN *join)
}
if (!tab->first_inner)
tab->first_inner= nested_join->first_nested;
- if (tab->table->reginfo.not_exists_optimize)
- tab->first_inner->table->reginfo.not_exists_optimize= 1;
if (++nested_join->counter < nested_join->n_tables)
break;
/* Table tab is the last inner table for nested join. */
nested_join->first_nested->last_inner= tab;
- if (tab->first_inner->table->reginfo.not_exists_optimize)
- {
- for (JOIN_TAB *join_tab= tab->first_inner; join_tab <= tab; join_tab++)
- join_tab->table->reginfo.not_exists_optimize= 1;
- }
}
}
DBUG_RETURN(FALSE);
@@ -10352,7 +10349,7 @@ void JOIN::drop_unused_derived_keys()
continue;
if (!tmp_tbl->pos_in_table_list->is_materialized_derived())
continue;
- if (tmp_tbl->max_keys > 1)
+ if (tmp_tbl->max_keys > 1 && !tab->is_ref_for_hash_join())
tmp_tbl->use_index(tab->ref.key);
if (tmp_tbl->s->keys)
{
@@ -15924,7 +15921,9 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
DBUG_ASSERT(thd == table->in_use);
new_field= item->Item::create_tmp_field(false, table);
- if (copy_func && item->real_item()->is_result_field())
+ if (copy_func &&
+ (item->is_result_field() ||
+ (item->real_item()->is_result_field())))
*((*copy_func)++) = item; // Save for copy_funcs
if (modify_item)
item->set_result_field(new_field);
@@ -18440,32 +18439,41 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
first_unmatched->found= 1;
for (JOIN_TAB *tab= first_unmatched; tab <= join_tab; tab++)
{
+ /*
+ Check whether 'not exists' optimization can be used here.
+ If tab->table->reginfo.not_exists_optimize is set to true
+ then WHERE contains a conjunctive predicate IS NULL over
+ a non-nullable field of tab. When activated this predicate
+ will filter out all records with matches for the left part
+ of the outer join whose inner tables start from the
+ first_unmatched table and include table tab. To safely use
+ 'not exists' optimization we have to check that the
+ IS NULL predicate is really activated, i.e. all guards
+ that wrap it are in the 'open' state.
+ */
+ bool not_exists_opt_is_applicable=
+ tab->table->reginfo.not_exists_optimize;
+ for (JOIN_TAB *first_upper= first_unmatched->first_upper;
+ not_exists_opt_is_applicable && first_upper;
+ first_upper= first_upper->first_upper)
+ {
+ if (!first_upper->found)
+ not_exists_opt_is_applicable= false;
+ }
/* Check all predicates that has just been activated. */
/*
Actually all predicates non-guarded by first_unmatched->found
will be re-evaluated again. It could be fixed, but, probably,
it's not worth doing now.
*/
- /*
- not_exists_optimize has been created from a
- select_cond containing 'is_null'. This 'is_null'
- predicate is still present on any 'tab' with
- 'not_exists_optimize'. Furthermore, the usual rules
- for condition guards also applies for
- 'not_exists_optimize' -> When 'is_null==false' we
- know all cond. guards are open and we can apply
- the 'not_exists_optimize'.
- */
- DBUG_ASSERT(!(tab->table->reginfo.not_exists_optimize &&
- !tab->select_cond));
-
if (tab->select_cond && !tab->select_cond->val_int())
{
/* The condition attached to table tab is false */
-
if (tab == join_tab)
{
found= 0;
+ if (not_exists_opt_is_applicable)
+ DBUG_RETURN(NESTED_LOOP_NO_MORE_ROWS);
}
else
{
@@ -18474,21 +18482,10 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
not to the last table of the current nest level.
*/
join->return_tab= tab;
- }
-
- if (tab->table->reginfo.not_exists_optimize)
- {
- /*
- When not_exists_optimize is set: No need to further
- explore more rows of 'tab' for this partial result.
- Any found 'tab' matches are known to evaluate to 'false'.
- Returning .._NO_MORE_ROWS will skip rem. 'tab' rows.
- */
- DBUG_RETURN(NESTED_LOOP_NO_MORE_ROWS);
- }
- else if (tab != join_tab)
- {
- DBUG_RETURN(NESTED_LOOP_OK);
+ if (not_exists_opt_is_applicable)
+ DBUG_RETURN(NESTED_LOOP_NO_MORE_ROWS);
+ else
+ DBUG_RETURN(NESTED_LOOP_OK);
}
}
}
diff --git a/sql/table.cc b/sql/table.cc
index 759a2d05de7..fe09ec8948d 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -571,7 +571,7 @@ enum open_frm_error open_table_def(THD *thd, TABLE_SHARE *share, uint flags)
{
DBUG_ASSERT(flags & GTS_TABLE);
DBUG_ASSERT(flags & GTS_USE_DISCOVERY);
- mysql_file_delete_with_symlink(key_file_frm, path, MYF(0));
+ my_handler_delete_with_symlink(key_file_frm, path, "", MYF(0));
file= -1;
}
else