summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/CMakeLists.txt2
-rw-r--r--sql/db.opt2
-rw-r--r--sql/events.cc2
-rw-r--r--sql/filesort.cc4
-rw-r--r--sql/ha_partition.cc178
-rw-r--r--sql/ha_partition.h3
-rw-r--r--sql/handler.cc47
-rw-r--r--sql/handler.h69
-rw-r--r--sql/hostname.cc6
-rw-r--r--sql/item.cc28
-rw-r--r--sql/item_cmpfunc.cc7
-rw-r--r--sql/item_cmpfunc.h3
-rw-r--r--sql/item_func.cc31
-rw-r--r--sql/item_strfunc.cc8
-rw-r--r--sql/item_subselect.cc14
-rw-r--r--sql/item_timefunc.cc10
-rw-r--r--sql/item_timefunc.h2
-rw-r--r--sql/lock.cc3
-rw-r--r--sql/log.cc76
-rw-r--r--sql/log_event.cc116
-rw-r--r--sql/log_event.h27
-rw-r--r--sql/mdl.cc37
-rw-r--r--sql/mdl.h2
-rw-r--r--sql/mysqld.cc57
-rw-r--r--sql/mysqld.h11
-rw-r--r--sql/opt_range.cc186
-rw-r--r--sql/protocol.cc11
-rw-r--r--sql/protocol.h8
-rw-r--r--sql/rpl_mi.h10
-rw-r--r--sql/rpl_parallel.cc14
-rw-r--r--sql/rpl_rli.cc53
-rw-r--r--sql/rpl_rli.h35
-rw-r--r--sql/set_var.h1
-rw-r--r--sql/share/charsets/Index.xml1
-rw-r--r--sql/share/charsets/ascii.xml1
-rw-r--r--sql/share/charsets/cp1250.xml1
-rw-r--r--sql/share/charsets/cp1256.xml1
-rw-r--r--sql/share/charsets/cp1257.xml1
-rw-r--r--sql/share/charsets/cp850.xml1
-rw-r--r--sql/share/charsets/cp866.xml1
-rw-r--r--sql/share/charsets/dec8.xml1
-rw-r--r--sql/share/charsets/geostd8.xml1
-rw-r--r--sql/share/charsets/greek.xml1
-rw-r--r--sql/share/charsets/hebrew.xml1
-rw-r--r--sql/share/charsets/hp8.xml1
-rw-r--r--sql/share/charsets/keybcs2.xml1
-rw-r--r--sql/share/charsets/koi8r.xml1
-rw-r--r--sql/share/charsets/koi8u.xml1
-rw-r--r--sql/share/charsets/languages.html1
-rw-r--r--sql/share/charsets/latin1.xml1
-rw-r--r--sql/share/charsets/latin2.xml1
-rw-r--r--sql/share/charsets/latin5.xml1
-rw-r--r--sql/share/charsets/latin7.xml1
-rw-r--r--sql/share/charsets/macce.xml1
-rw-r--r--sql/share/charsets/macroman.xml1
-rw-r--r--sql/share/charsets/swe7.xml1
-rw-r--r--sql/share/errmsg-utf8.txt43
-rw-r--r--sql/slave.cc19
-rw-r--r--sql/slave.h3
-rw-r--r--sql/sp.cc2
-rw-r--r--sql/sp_head.cc4
-rw-r--r--sql/sql_acl.cc36
-rw-r--r--sql/sql_acl.h2
-rw-r--r--sql/sql_admin.cc14
-rw-r--r--sql/sql_alter.h4
-rw-r--r--sql/sql_base.cc123
-rw-r--r--sql/sql_cache.cc2
-rw-r--r--sql/sql_class.cc4
-rw-r--r--sql/sql_class.h16
-rw-r--r--sql/sql_connect.cc2
-rw-r--r--sql/sql_lex.h2
-rw-r--r--sql/sql_locale.cc70
-rw-r--r--sql/sql_parse.cc119
-rw-r--r--sql/sql_plugin.cc14
-rw-r--r--sql/sql_select.cc199
-rw-r--r--sql/sql_show.cc204
-rw-r--r--sql/sql_state.c1
-rw-r--r--sql/sql_table.cc54
-rw-r--r--sql/sql_table.h6
-rw-r--r--sql/sql_time.cc51
-rw-r--r--sql/sql_time.h3
-rw-r--r--sql/sql_trigger.cc7
-rw-r--r--sql/sql_update.cc15
-rw-r--r--sql/sql_yacc.yy18
-rw-r--r--sql/sys_vars.cc45
-rw-r--r--sql/table.cc43
-rw-r--r--sql/table.h9
-rw-r--r--sql/transaction.cc35
-rw-r--r--sql/unireg.cc7
89 files changed, 1507 insertions, 755 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index 75652c06649..598462d1bba 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -300,7 +300,7 @@ ADD_CUSTOM_TARGET(distclean
IF(INSTALL_LAYOUT STREQUAL "STANDALONE")
# Copy db.opt into data/test/
-SET(DBOPT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/db.opt )
+SET(DBOPT_FILE ${CMAKE_SOURCE_DIR}/support-files/db.opt )
INSTALL(FILES ${DBOPT_FILE} DESTINATION data/test COMPONENT DataFiles)
# Install initial database on windows
diff --git a/sql/db.opt b/sql/db.opt
deleted file mode 100644
index d8429c4e0de..00000000000
--- a/sql/db.opt
+++ /dev/null
@@ -1,2 +0,0 @@
-default-character-set=latin1
-default-collation=latin1_swedish_ci
diff --git a/sql/events.cc b/sql/events.cc
index 944e91a4d21..e7631e33bf9 100644
--- a/sql/events.cc
+++ b/sql/events.cc
@@ -596,6 +596,8 @@ Events::drop_schema_events(THD *thd, char *db)
DBUG_ENTER("Events::drop_schema_events");
DBUG_PRINT("enter", ("dropping events from %s", db));
+ DBUG_ASSERT(ok_for_lower_case_names(db));
+
/*
Sic: no check if the scheduler is disabled or system tables
are damaged, as intended.
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 776ec064365..0d554df6e18 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
- Copyright (c) 2009, 2012, Monty Program Ab.
+/* Copyright (c) 2000, 2014, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2014, Monty Program 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
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index fd6ac3b180a..788254bcc3f 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -8151,7 +8151,6 @@ class ha_partition_inplace_ctx : public inplace_alter_handler_ctx
{
public:
inplace_alter_handler_ctx **handler_ctx_array;
- bool rollback_done;
private:
uint m_tot_parts;
@@ -8159,7 +8158,6 @@ public:
ha_partition_inplace_ctx(THD *thd, uint tot_parts)
: inplace_alter_handler_ctx(),
handler_ctx_array(NULL),
- rollback_done(false),
m_tot_parts(tot_parts)
{}
@@ -8178,14 +8176,11 @@ enum_alter_inplace_result
ha_partition::check_if_supported_inplace_alter(TABLE *altered_table,
Alter_inplace_info *ha_alter_info)
{
-#ifdef PARTITION_SUPPORTS_INPLACE_ALTER
uint index= 0;
enum_alter_inplace_result result= HA_ALTER_INPLACE_NO_LOCK;
ha_partition_inplace_ctx *part_inplace_ctx;
+ bool first_is_set= false;
THD *thd= ha_thd();
-#else
- enum_alter_inplace_result result= HA_ALTER_INPLACE_NOT_SUPPORTED;
-#endif
DBUG_ENTER("ha_partition::check_if_supported_inplace_alter");
/*
@@ -8196,34 +8191,21 @@ ha_partition::check_if_supported_inplace_alter(TABLE *altered_table,
if (ha_alter_info->alter_info->flags == Alter_info::ALTER_PARTITION)
DBUG_RETURN(HA_ALTER_INPLACE_NO_LOCK);
-#ifndef PARTITION_SUPPORTS_INPLACE_ALTER
- /*
- Due to bug#14760210 partitions can be out-of-sync in case
- commit_inplace_alter_table fails after the first partition.
-
- Until we can either commit all partitions at the same time or
- have an atomic recover on failure/crash we don't support any
- inplace alter.
-
- TODO: investigate what happens when indexes are out-of-sync
- between partitions. If safe and possible to recover from,
- then we could allow ADD/DROP INDEX.
- */
- DBUG_RETURN(result);
-#else
part_inplace_ctx=
new (thd->mem_root) ha_partition_inplace_ctx(thd, m_tot_parts);
if (!part_inplace_ctx)
DBUG_RETURN(HA_ALTER_ERROR);
part_inplace_ctx->handler_ctx_array= (inplace_alter_handler_ctx **)
- thd->alloc(sizeof(inplace_alter_handler_ctx *) * m_tot_parts);
+ thd->alloc(sizeof(inplace_alter_handler_ctx *) * (m_tot_parts + 1));
if (!part_inplace_ctx->handler_ctx_array)
DBUG_RETURN(HA_ALTER_ERROR);
- for (index= 0; index < m_tot_parts; index++)
+ /* Set all to NULL, including the terminating one. */
+ for (index= 0; index <= m_tot_parts; index++)
part_inplace_ctx->handler_ctx_array[index]= NULL;
+ ha_alter_info->handler_flags |= Alter_inplace_info::ALTER_PARTITIONED;
for (index= 0; index < m_tot_parts; index++)
{
enum_alter_inplace_result p_result=
@@ -8231,15 +8213,32 @@ ha_partition::check_if_supported_inplace_alter(TABLE *altered_table,
ha_alter_info);
part_inplace_ctx->handler_ctx_array[index]= ha_alter_info->handler_ctx;
+ if (index == 0)
+ {
+ first_is_set= (ha_alter_info->handler_ctx != NULL);
+ }
+ else if (first_is_set != (ha_alter_info->handler_ctx != NULL))
+ {
+ /* Either none or all partitions must set handler_ctx! */
+ DBUG_ASSERT(0);
+ DBUG_RETURN(HA_ALTER_ERROR);
+ }
if (p_result < result)
result= p_result;
if (result == HA_ALTER_ERROR)
break;
}
+
ha_alter_info->handler_ctx= part_inplace_ctx;
+ /*
+ To indicate for future inplace calls that there are several
+ partitions/handlers that need to be committed together,
+ we set group_commit_ctx to the NULL terminated array of
+ the partitions handlers.
+ */
+ ha_alter_info->group_commit_ctx= part_inplace_ctx->handler_ctx_array;
DBUG_RETURN(result);
-#endif
}
@@ -8320,8 +8319,8 @@ bool ha_partition::commit_inplace_alter_table(TABLE *altered_table,
Alter_inplace_info *ha_alter_info,
bool commit)
{
- uint index= 0;
ha_partition_inplace_ctx *part_inplace_ctx;
+ bool error= false;
DBUG_ENTER("ha_partition::commit_inplace_alter_table");
@@ -8335,117 +8334,52 @@ bool ha_partition::commit_inplace_alter_table(TABLE *altered_table,
part_inplace_ctx=
static_cast<class ha_partition_inplace_ctx*>(ha_alter_info->handler_ctx);
- if (!commit && part_inplace_ctx->rollback_done)
- DBUG_RETURN(false); // We have already rolled back changes.
-
- for (index= 0; index < m_tot_parts; index++)
+ if (commit)
{
- ha_alter_info->handler_ctx= part_inplace_ctx->handler_ctx_array[index];
- if (m_file[index]->ha_commit_inplace_alter_table(altered_table,
- ha_alter_info, commit))
+ DBUG_ASSERT(ha_alter_info->group_commit_ctx ==
+ part_inplace_ctx->handler_ctx_array);
+ ha_alter_info->handler_ctx= part_inplace_ctx->handler_ctx_array[0];
+ error= m_file[0]->ha_commit_inplace_alter_table(altered_table,
+ ha_alter_info, commit);
+ if (error)
+ goto end;
+ if (ha_alter_info->group_commit_ctx)
{
- part_inplace_ctx->handler_ctx_array[index]= ha_alter_info->handler_ctx;
- goto err;
- }
- part_inplace_ctx->handler_ctx_array[index]= ha_alter_info->handler_ctx;
- DBUG_EXECUTE_IF("ha_partition_fail_final_add_index", {
- /* Simulate failure by rollback of the second partition */
- if (m_tot_parts > 1)
+ /*
+ If ha_alter_info->group_commit_ctx is not set to NULL,
+ then the engine did only commit the first partition!
+ The engine is probably new, since both innodb and the default
+ implementation of handler::commit_inplace_alter_table sets it to NULL
+ and simply return false, since it allows metadata changes only.
+ Loop over all other partitions as to follow the protocol!
+ */
+ uint i;
+ DBUG_ASSERT(0);
+ for (i= 1; i < m_tot_parts; i++)
{
- index++;
- ha_alter_info->handler_ctx= part_inplace_ctx->handler_ctx_array[index];
- m_file[index]->ha_commit_inplace_alter_table(altered_table,
- ha_alter_info, false);
- part_inplace_ctx->handler_ctx_array[index]= ha_alter_info->handler_ctx;
- goto err;
+ ha_alter_info->handler_ctx= part_inplace_ctx->handler_ctx_array[i];
+ error|= m_file[i]->ha_commit_inplace_alter_table(altered_table,
+ ha_alter_info,
+ true);
}
- });
}
- ha_alter_info->handler_ctx= part_inplace_ctx;
-
- DBUG_RETURN(false);
-
-err:
- ha_alter_info->handler_ctx= part_inplace_ctx;
- /*
- Reverting committed changes is (for now) only possible for ADD INDEX
- For other changes we will just try to rollback changes.
- */
- if (index > 0 &&
- ha_alter_info->handler_flags & (Alter_inplace_info::ADD_INDEX |
- Alter_inplace_info::ADD_UNIQUE_INDEX |
- Alter_inplace_info::ADD_PK_INDEX))
- {
- Alter_inplace_info drop_info(ha_alter_info->create_info,
- ha_alter_info->alter_info,
- NULL, 0,
- ha_alter_info->modified_part_info,
- ha_alter_info->ignore);
-
- if (ha_alter_info->handler_flags & Alter_inplace_info::ADD_INDEX)
- drop_info.handler_flags|= Alter_inplace_info::DROP_INDEX;
- if (ha_alter_info->handler_flags & Alter_inplace_info::ADD_UNIQUE_INDEX)
- drop_info.handler_flags|= Alter_inplace_info::DROP_UNIQUE_INDEX;
- if (ha_alter_info->handler_flags & Alter_inplace_info::ADD_PK_INDEX)
- drop_info.handler_flags|= Alter_inplace_info::DROP_PK_INDEX;
- drop_info.index_drop_count= ha_alter_info->index_add_count;
- drop_info.index_drop_buffer=
- (KEY**) ha_thd()->alloc(sizeof(KEY*) * drop_info.index_drop_count);
- if (!drop_info.index_drop_buffer)
- {
- sql_print_error("Failed with error handling of adding index:\n"
- "committing index failed, and when trying to revert "
- "already committed partitions we failed allocating\n"
- "memory for the index for table '%s'",
- table_share->table_name.str);
- DBUG_RETURN(true);
- }
- for (uint i= 0; i < drop_info.index_drop_count; i++)
- drop_info.index_drop_buffer[i]=
- &ha_alter_info->key_info_buffer[ha_alter_info->index_add_buffer[i]];
-
- // Drop index for each partition where we already committed new index.
- for (uint i= 0; i < index; i++)
- {
- bool error= m_file[i]->ha_prepare_inplace_alter_table(altered_table,
- &drop_info);
- error|= m_file[i]->ha_inplace_alter_table(altered_table, &drop_info);
- error|= m_file[i]->ha_commit_inplace_alter_table(altered_table,
- &drop_info, true);
- if (error)
- sql_print_error("Failed with error handling of adding index:\n"
- "committing index failed, and when trying to revert "
- "already committed partitions we failed removing\n"
- "the index for table '%s' partition nr %d",
- table_share->table_name.str, i);
}
-
- // Rollback uncommitted changes.
- for (uint i= index+1; i < m_tot_parts; i++)
+ else
+ {
+ uint i;
+ for (i= 0; i < m_tot_parts; i++)
{
+ /* Rollback, commit == false, is done for each partition! */
ha_alter_info->handler_ctx= part_inplace_ctx->handler_ctx_array[i];
if (m_file[i]->ha_commit_inplace_alter_table(altered_table,
ha_alter_info, false))
- {
- /* How could this happen? */
- sql_print_error("Failed with error handling of adding index:\n"
- "Rollback of add_index failed for table\n"
- "'%s' partition nr %d",
- table_share->table_name.str, i);
+ error= true;
}
- part_inplace_ctx->handler_ctx_array[i]= ha_alter_info->handler_ctx;
}
-
- // We have now reverted/rolled back changes. Set flag to prevent
- // it from being done again.
- part_inplace_ctx->rollback_done= true;
-
- print_error(HA_ERR_NO_PARTITION_FOUND, MYF(0));
- }
-
+end:
ha_alter_info->handler_ctx= part_inplace_ctx;
- DBUG_RETURN(true);
+ DBUG_RETURN(error);
}
diff --git a/sql/ha_partition.h b/sql/ha_partition.h
index 1f55301d14e..eb265363ee5 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -1284,11 +1284,14 @@ public:
}
#ifdef WITH_WSREP
virtual int wsrep_db_type() const;
+#if 0
+ // TODO: Verify : https://mariadb.atlassian.net/browse/MDEV-4953
void wsrep_reset_files()
{
for (uint i=0; i < m_tot_parts; i++)
m_file[i]->ha_start_of_new_statement();
}
+#endif
#endif /* WITH_WSREP */
diff --git a/sql/handler.cc b/sql/handler.cc
index af0e1c74b15..b3d4bdf757c 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -362,6 +362,7 @@ int ha_init_errors(void)
SETMSG(HA_FTS_INVALID_DOCID, "Invalid InnoDB FTS Doc ID");
SETMSG(HA_ERR_TABLE_IN_FK_CHECK, ER_DEFAULT(ER_TABLE_IN_FK_CHECK));
SETMSG(HA_ERR_DISK_FULL, ER_DEFAULT(ER_DISK_FULL));
+ SETMSG(HA_ERR_FTS_TOO_MANY_WORDS_IN_PHRASE, "Too many words in a FTS phrase or proximity search");
/* Register the error messages for use with my_error(). */
return my_error_register(get_handler_errmsgs, HA_ERR_FIRST, HA_ERR_LAST);
@@ -2042,6 +2043,41 @@ int ha_release_temporary_latches(THD *thd)
return 0;
}
+/**
+ Check if all storage engines used in transaction agree that after
+ rollback to savepoint it is safe to release MDL locks acquired after
+ savepoint creation.
+
+ @param thd The client thread that executes the transaction.
+
+ @return true - It is safe to release MDL locks.
+ false - If it is not.
+*/
+bool ha_rollback_to_savepoint_can_release_mdl(THD *thd)
+{
+ Ha_trx_info *ha_info;
+ THD_TRANS *trans= (thd->in_sub_stmt ? &thd->transaction.stmt :
+ &thd->transaction.all);
+
+ DBUG_ENTER("ha_rollback_to_savepoint_can_release_mdl");
+
+ /**
+ Checking whether it is safe to release metadata locks after rollback to
+ savepoint in all the storage engines that are part of the transaction.
+ */
+ for (ha_info= trans->ha_list; ha_info; ha_info= ha_info->next())
+ {
+ handlerton *ht= ha_info->ht();
+ DBUG_ASSERT(ht);
+
+ if (ht->savepoint_rollback_can_release_mdl == 0 ||
+ ht->savepoint_rollback_can_release_mdl(ht, thd) == false)
+ DBUG_RETURN(false);
+ }
+
+ DBUG_RETURN(true);
+}
+
int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv)
{
int error=0;
@@ -3922,14 +3958,11 @@ int handler::ha_check(THD *thd, HA_CHECK_OPT *check_opt)
if it is started.
*/
+inline
void
-handler::mark_trx_read_write_part2()
+handler::mark_trx_read_write()
{
Ha_trx_info *ha_info= &ha_thd()->ha_data[ht->slot].ha_info[0];
-
- /* Don't call this function again for this statement */
- mark_trx_done= TRUE;
-
/*
When a storage engine method is called, the transaction must
have been started, unless it's a DDL call, for which the
@@ -6165,6 +6198,10 @@ void signal_log_not_needed(struct handlerton, char *log_file)
DBUG_VOID_RETURN;
}
+void handler::set_lock_type(enum thr_lock_type lock)
+{
+ table->reginfo.lock_type= lock;
+}
#ifdef WITH_WSREP
/**
diff --git a/sql/handler.h b/sql/handler.h
index 7b49ff1ffd4..53e8997acbe 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -1,8 +1,8 @@
#ifndef HANDLER_INCLUDED
#define HANDLER_INCLUDED
/*
- Copyright (c) 2000, 2011, Oracle and/or its affiliates.
- Copyright (c) 2009, 2013, Monty Program Ab.
+ Copyright (c) 2000, 2014, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2014, Monty Program Ab.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@@ -1026,6 +1026,13 @@ struct handlerton
to the savepoint_set call
*/
int (*savepoint_rollback)(handlerton *hton, THD *thd, void *sv);
+ /**
+ Check if storage engine allows to release metadata locks which were
+ acquired after the savepoint if rollback to savepoint is done.
+ @return true - If it is safe to release MDL locks.
+ false - If it is not.
+ */
+ bool (*savepoint_rollback_can_release_mdl)(handlerton *hton, THD *thd);
int (*savepoint_release)(handlerton *hton, THD *thd, void *sv);
/*
'all' is true if it's a real commit, that makes persistent changes
@@ -1678,8 +1685,7 @@ public:
All these operations are supported as in-place operations by the
SQL layer. This means that operations that by their nature must
be performed by copying the table to a temporary table, will not
- have their own flags here (e.g. ALTER TABLE FORCE, ALTER TABLE
- ENGINE).
+ have their own flags here.
We generally try to specify handler flags only if there are real
changes. But in cases when it is cumbersome to determine if some
@@ -1783,8 +1789,17 @@ public:
// Partition operation with ALL keyword
static const HA_ALTER_FLAGS ALTER_ALL_PARTITION = 1L << 28;
+ /**
+ Recreate the table for ALTER TABLE FORCE, ALTER TABLE ENGINE
+ and OPTIMIZE TABLE operations.
+ */
+ static const HA_ALTER_FLAGS RECREATE_TABLE = 1L << 29;
+
// Virtual columns changed
- static const HA_ALTER_FLAGS ALTER_COLUMN_VCOL = 1L << 29;
+ static const HA_ALTER_FLAGS ALTER_COLUMN_VCOL = 1L << 30;
+
+ // ALTER TABLE for a partitioned table
+ static const HA_ALTER_FLAGS ALTER_PARTITIONED = 1L << 31;
/**
Create options (like MAX_ROWS) for the new version of table.
@@ -1857,6 +1872,18 @@ public:
inplace_alter_handler_ctx *handler_ctx;
/**
+ If the table uses several handlers, like ha_partition uses one handler
+ per partition, this contains a Null terminated array of ctx pointers
+ that should all be committed together.
+ Or NULL if only handler_ctx should be committed.
+ Set to NULL if the low level handler::commit_inplace_alter_table uses it,
+ to signal to the main handler that everything was committed as atomically.
+
+ @see inplace_alter_handler_ctx for information about object lifecycle.
+ */
+ inplace_alter_handler_ctx **group_commit_ctx;
+
+ /**
Flags describing in detail which operations the storage engine is to execute.
*/
HA_ALTER_FLAGS handler_flags;
@@ -1904,6 +1931,7 @@ public:
index_add_count(0),
index_add_buffer(NULL),
handler_ctx(NULL),
+ group_commit_ctx(NULL),
handler_flags(0),
modified_part_info(modified_part_info_arg),
ignore(ignore_arg),
@@ -2451,7 +2479,6 @@ public:
FT_INFO *ft_handler;
enum {NONE=0, INDEX, RND} inited;
bool implicit_emptied; /* Can be !=0 only if HEAP */
- bool mark_trx_done;
const COND *pushed_cond;
/**
next_insert_id is the next value which should be inserted into the
@@ -2532,7 +2559,7 @@ public:
in_range_check_pushed_down(FALSE),
ref_length(sizeof(my_off_t)),
ft_handler(0), inited(NONE),
- implicit_emptied(0), mark_trx_done(FALSE),
+ implicit_emptied(0),
pushed_cond(0), next_insert_id(0), insert_id_for_cur_row(0),
pushed_idx_cond(NULL),
pushed_idx_cond_keyno(MAX_KEY),
@@ -2613,13 +2640,6 @@ public:
}
int ha_rnd_init_with_error(bool scan) __attribute__ ((warn_unused_result));
int ha_reset();
- /* Tell handler (not storage engine) this is start of a new statement */
- void ha_start_of_new_statement()
- {
- ft_handler= 0;
- mark_trx_done= FALSE;
- }
-
/* this is necessary in many places, e.g. in HANDLER command */
int ha_index_or_rnd_end()
{
@@ -3623,6 +3643,10 @@ protected:
@note In case of partitioning, this function might be called for rollback
without prepare_inplace_alter_table() having been called first.
+ Also partitioned tables sets ha_alter_info->group_commit_ctx to a NULL
+ terminated array of the partitions handlers and if all of them are
+ committed as one, then group_commit_ctx should be set to NULL to indicate
+ to the partitioning handler that all partitions handlers are committed.
@see prepare_inplace_alter_table().
@param altered_table TABLE object for new version of table.
@@ -3637,7 +3661,11 @@ protected:
virtual bool commit_inplace_alter_table(TABLE *altered_table,
Alter_inplace_info *ha_alter_info,
bool commit)
- { return false; }
+{
+ /* Nothing to commit/rollback, mark all handlers committed! */
+ ha_alter_info->group_commit_ctx= NULL;
+ return false;
+}
/**
@@ -3710,12 +3738,8 @@ protected:
private:
/* Private helpers */
- void mark_trx_read_write_part2();
- inline void mark_trx_read_write()
- {
- if (!mark_trx_done)
- mark_trx_read_write_part2();
- }
+ inline void mark_trx_read_write();
+private:
inline void increment_statistics(ulong SSV::*offset) const;
inline void decrement_statistics(ulong SSV::*offset) const;
@@ -3921,6 +3945,8 @@ public:
inline int ha_write_tmp_row(uchar *buf);
inline int ha_update_tmp_row(const uchar * old_data, uchar * new_data);
+ virtual void set_lock_type(enum thr_lock_type lock);
+
friend enum icp_result handler_index_cond_check(void* h_arg);
protected:
Handler_share *get_ha_share_ptr();
@@ -4057,6 +4083,7 @@ int ha_enable_transaction(THD *thd, bool on);
/* savepoints */
int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv);
+bool ha_rollback_to_savepoint_can_release_mdl(THD *thd);
int ha_savepoint(THD *thd, SAVEPOINT *sv);
int ha_release_savepoint(THD *thd, SAVEPOINT *sv);
#ifdef WITH_WSREP
diff --git a/sql/hostname.cc b/sql/hostname.cc
index 11cd16ac857..c6c58a0db92 100644
--- a/sql/hostname.cc
+++ b/sql/hostname.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
+/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
Copyright (c) 2011, 2014, SkySQL Ab.
This program is free software; you can redistribute it and/or modify
@@ -457,12 +457,12 @@ int ip_to_hostname(struct sockaddr_storage *ip_storage,
if (entry)
{
entry->m_last_seen= now;
+ *connect_errors= entry->m_errors.m_connect;
- if (entry->m_errors.m_connect > max_connect_errors)
+ if (entry->m_errors.m_connect >= max_connect_errors)
{
entry->m_errors.m_host_blocked++;
entry->set_error_timestamps(now);
- *connect_errors= entry->m_errors.m_connect;
mysql_mutex_unlock(&hostname_cache->lock);
DBUG_RETURN(RC_BLOCKED_HOST);
}
diff --git a/sql/item.cc b/sql/item.cc
index 9b27f730e80..2c963322eb6 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -4742,6 +4742,10 @@ bool is_outer_table(TABLE_LIST *table, SELECT_LEX *select)
DBUG_ASSERT(table->select_lex != select);
TABLE_LIST *tl;
+ if (table->belong_to_view &&
+ table->belong_to_view->select_lex == select)
+ return FALSE;
+
for (tl= select->master_unit()->derived;
tl && tl->is_merged_derived();
select= tl->select_lex, tl= select->master_unit()->derived)
@@ -5318,15 +5322,23 @@ mark_non_agg_field:
/*
Mark selects according to presence of non aggregated fields.
Fields from outer selects added to the aggregate function
- outer_fields list as its unknown at the moment whether it's
+ outer_fields list as it's unknown at the moment whether it's
aggregated or not.
- We're using either the select lex of the cached table (if present)
- or the field's resolution context. context->select_lex is
- safe for use because it's either the SELECT we want to use
- (the current level) or a stub added by non-SELECT queries.
+ We're using the select lex of the cached table (if present).
*/
- SELECT_LEX *select_lex= cached_table ?
- cached_table->select_lex : field->table->pos_in_table_list->select_lex;
+ SELECT_LEX *select_lex;
+ if (cached_table)
+ select_lex= cached_table->select_lex;
+ else if (!(select_lex= field->table->pos_in_table_list->select_lex))
+ {
+ /*
+ This can only happen when there is no real table in the query.
+ We are using the field's resolution context. context->select_lex is eee
+ safe for use because it's either the SELECT we want to use
+ (the current level) or a stub added by non-SELECT queries.
+ */
+ select_lex= context->select_lex;
+ }
if (!thd->lex->in_sum_func)
select_lex->set_non_agg_field_used(true);
else
@@ -6509,6 +6521,7 @@ void Item_date_literal::print(String *str, enum_query_type query_type)
bool Item_date_literal::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
{
DBUG_ASSERT(fixed);
+ fuzzy_date |= sql_mode_for_dates(current_thd);
*ltime= cached_time;
return (null_value= check_date_with_warn(ltime, fuzzy_date,
MYSQL_TIMESTAMP_ERROR));
@@ -6528,6 +6541,7 @@ void Item_datetime_literal::print(String *str, enum_query_type query_type)
bool Item_datetime_literal::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
{
DBUG_ASSERT(fixed);
+ fuzzy_date |= sql_mode_for_dates(current_thd);
*ltime= cached_time;
return (null_value= check_date_with_warn(ltime, fuzzy_date,
MYSQL_TIMESTAMP_ERROR));
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 4b9eb37488e..f142c51db4d 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -2763,13 +2763,13 @@ Item_func_nullif::fix_length_and_dec()
maybe_null=1;
if (args[0]) // Only false if EOM
{
- max_length=args[0]->max_length;
decimals=args[0]->decimals;
unsigned_flag= args[0]->unsigned_flag;
cached_result_type= args[0]->result_type();
if (cached_result_type == STRING_RESULT &&
agg_arg_charsets_for_comparison(collation, args, arg_count))
return;
+ fix_char_length(args[0]->max_char_length());
}
}
@@ -5055,6 +5055,11 @@ bool Item_func_like::find_selective_predicates_list_processor(uchar *arg)
}
+int Regexp_processor_pcre::default_regex_flags()
+{
+ return default_regex_flags_pcre(current_thd);
+}
+
/**
Convert string to lib_charset, if needed.
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 4b3acf83f85..bf28b00c908 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -1513,9 +1513,10 @@ public:
m_library_charset(&my_charset_utf8_general_ci),
m_subpatterns_needed(0)
{}
+ int default_regex_flags();
void init(CHARSET_INFO *data_charset, int extra_flags, uint nsubpatterns)
{
- m_library_flags= extra_flags |
+ m_library_flags= default_regex_flags() | extra_flags |
(data_charset != &my_charset_bin ?
(PCRE_UTF8 | PCRE_UCP) : 0) |
((data_charset->state &
diff --git a/sql/item_func.cc b/sql/item_func.cc
index c3fd95c2b2d..572c9fdde60 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -6262,18 +6262,39 @@ bool Item_func_match::fix_fields(THD *thd, Item **ref)
bool allows_multi_table_search= true;
const_item_cache=0;
+ table= 0;
for (uint i=1 ; i < arg_count ; i++)
{
item=args[i];
if (item->type() == Item::REF_ITEM)
args[i]= item= *((Item_ref *)item)->ref;
- if (item->type() != Item::FIELD_ITEM)
+ /*
+ When running in PS mode, some Item_field's can already be replaced
+ to Item_func_conv_charset during PREPARE time. This is possible
+ in case of "MATCH (f1,..,fN) AGAINST (... IN BOOLEAN MODE)"
+ when running without any fulltext indexes and when fields f1..fN
+ have different character sets.
+ So we check for FIELD_ITEM only during prepare time and in non-PS mode,
+ and do not check in PS execute time.
+ */
+ if (!thd->stmt_arena->is_stmt_execute() &&
+ item->type() != Item::FIELD_ITEM)
{
my_error(ER_WRONG_ARGUMENTS, MYF(0), "AGAINST");
return TRUE;
}
- allows_multi_table_search &=
- allows_search_on_non_indexed_columns(((Item_field *)item)->field->table);
+ /*
+ During the prepare-time execution of fix_fields() of a PS query some
+ Item_fields's could have been already replaced to Item_func_conv_charset
+ (by the call for agg_arg_charsets_for_comparison below()).
+ But agg_arg_charsets_for_comparison() is written in a way that
+ at least *one* of the Item_field's is not replaced.
+ This makes sure that "table" gets initialized during PS execution time.
+ */
+ if (item->type() == Item::FIELD_ITEM)
+ table= ((Item_field *)item)->field->table;
+
+ allows_multi_table_search &= allows_search_on_non_indexed_columns(table);
}
/*
@@ -6289,15 +6310,13 @@ bool Item_func_match::fix_fields(THD *thd, Item **ref)
my_error(ER_WRONG_ARGUMENTS,MYF(0),"MATCH");
return TRUE;
}
- table=((Item_field *)item)->field->table;
if (!(table->file->ha_table_flags() & HA_CAN_FULLTEXT))
{
my_error(ER_TABLE_CANT_HANDLE_FT, MYF(0), table->file->table_type());
return 1;
}
table->fulltext_searched=1;
- return agg_item_collations_for_comparison(cmp_collation, func_name(),
- args+1, arg_count-1, 0);
+ return agg_arg_charsets_for_comparison(cmp_collation, args+1, arg_count-1);
}
bool Item_func_match::fix_index()
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 1ae080ba22d..100d54133dd 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1604,7 +1604,7 @@ String *Item_str_conv::val_str(String *str)
if (multiply == 1)
{
uint len;
- res= copy_if_not_alloced(str,res,res->length());
+ res= copy_if_not_alloced(&tmp_value, res, res->length());
len= converter(collation.collation, (char*) res->ptr(), res->length(),
(char*) res->ptr(), res->length());
DBUG_ASSERT(len <= res->length());
@@ -1810,8 +1810,10 @@ void Item_func_substr_index::fix_length_and_dec()
String *Item_func_substr_index::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
+ char buff[MAX_FIELD_WIDTH];
+ String tmp(buff,sizeof(buff),system_charset_info);
String *res= args[0]->val_str(str);
- String *delimiter= args[1]->val_str(&tmp_value);
+ String *delimiter= args[1]->val_str(&tmp);
int32 count= (int32) args[2]->val_int();
uint offset;
@@ -1918,6 +1920,8 @@ String *Item_func_substr_index::val_str(String *str)
break;
}
}
+ if (count)
+ return res; // Didn't find, return org string
}
}
/*
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 67af49c4f9f..38bb3121ed8 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -2626,7 +2626,7 @@ static bool check_equality_for_exist2in(Item_func *func,
typedef struct st_eq_field_outer
{
- Item_func **eq_ref;
+ Item **eq_ref;
Item_ident *local_field;
Item *outer_exp;
} EQ_FIELD_OUTER;
@@ -2665,7 +2665,7 @@ static bool find_inner_outer_equalities(Item **conds,
&element.outer_exp))
{
found= TRUE;
- element.eq_ref= (Item_func **)li.ref();
+ element.eq_ref= li.ref();
if (result.append(element))
goto alloc_err;
}
@@ -2677,7 +2677,7 @@ static bool find_inner_outer_equalities(Item **conds,
&element.outer_exp))
{
found= TRUE;
- element.eq_ref= (Item_func **)conds;
+ element.eq_ref= conds;
if (result.append(element))
goto alloc_err;
}
@@ -2700,7 +2700,7 @@ bool Item_exists_subselect::exists2in_processor(uchar *opt_arg)
THD *thd= (THD *)opt_arg;
SELECT_LEX *first_select=unit->first_select(), *save_select;
JOIN *join= first_select->join;
- Item_func *eq= NULL, **eq_ref= NULL;
+ Item **eq_ref= NULL;
Item_ident *local_field= NULL;
Item *outer_exp= NULL;
Item *left_exp= NULL; Item_in_subselect *in_subs;
@@ -2774,7 +2774,6 @@ bool Item_exists_subselect::exists2in_processor(uchar *opt_arg)
{
Item *item= it++;
eq_ref= eqs.at(i).eq_ref;
- eq= *eq_ref;
local_field= eqs.at(i).local_field;
outer_exp= eqs.at(i).outer_exp;
/* Add the field to the SELECT_LIST */
@@ -2789,10 +2788,7 @@ bool Item_exists_subselect::exists2in_processor(uchar *opt_arg)
/* remove the parts from condition */
if (!upper_not || !local_field->maybe_null)
- {
- eq->arguments()[0]= new Item_int(1);
- eq->arguments()[1]= new Item_int(1);
- }
+ *eq_ref= new Item_int(1);
else
{
*eq_ref= new Item_func_isnotnull(
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 4d261e7a7d9..0aaeb3d55db 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -2523,10 +2523,10 @@ bool Item_date_typecast::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
if (get_arg0_date(ltime, fuzzy_date & ~TIME_TIME_ONLY))
return 1;
- ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0;
- ltime->time_type= MYSQL_TIMESTAMP_DATE;
- return (null_value= check_date_with_warn(ltime, fuzzy_date,
- MYSQL_TIMESTAMP_DATE));
+ if (make_date_with_warn(ltime, fuzzy_date, MYSQL_TIMESTAMP_DATE))
+ return (null_value= 1);
+
+ return 0;
}
@@ -3144,7 +3144,7 @@ void Item_func_str_to_date::fix_length_and_dec()
}
cached_field_type= MYSQL_TYPE_DATETIME;
- decimals= NOT_FIXED_DEC;
+ decimals= TIME_SECOND_PART_DIGITS;
if ((const_item= args[1]->const_item()))
{
char format_buff[64];
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 8f881487e21..29badddad8e 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -809,7 +809,7 @@ public:
bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
void fix_length_and_dec()
{
- decimals= args[0]->decimals;
+ decimals= MY_MIN(args[0]->decimals, TIME_SECOND_PART_DIGITS);
Item_timefunc::fix_length_and_dec();
}
const char *func_name() const { return "sec_to_time"; }
diff --git a/sql/lock.cc b/sql/lock.cc
index 793b56f965d..082a5827908 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -331,6 +331,7 @@ bool mysql_lock_tables(THD *thd, MYSQL_LOCK *sql_lock, uint flags)
(void) unlock_external(thd, sql_lock->table, sql_lock->table_count);
end:
+ THD_STAGE_INFO(thd, stage_after_table_lock);
#ifdef WITH_WSREP
thd_proc_info(thd, "mysql_lock_tables(): unlocking tables II");
#else /* WITH_WSREP */
@@ -877,6 +878,8 @@ bool lock_object_name(THD *thd, MDL_key::enum_mdl_namespace mdl_type,
MDL_request schema_request;
MDL_request mdl_request;
+ DBUG_ASSERT(ok_for_lower_case_names(db));
+
if (thd->locked_tables_mode)
{
my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
diff --git a/sql/log.cc b/sql/log.cc
index 0ac5a4818aa..0da411d42e2 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -76,6 +76,8 @@ static int binlog_init(void *p);
static int binlog_close_connection(handlerton *hton, THD *thd);
static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv);
static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv);
+static bool binlog_savepoint_rollback_can_release_mdl(handlerton *hton,
+ THD *thd);
static int binlog_commit(handlerton *hton, THD *thd, bool all);
static int binlog_rollback(handlerton *hton, THD *thd, bool all);
static int binlog_prepare(handlerton *hton, THD *thd, bool all);
@@ -1770,6 +1772,8 @@ int binlog_init(void *p)
binlog_hton->close_connection= binlog_close_connection;
binlog_hton->savepoint_set= binlog_savepoint_set;
binlog_hton->savepoint_rollback= binlog_savepoint_rollback;
+ binlog_hton->savepoint_rollback_can_release_mdl=
+ binlog_savepoint_rollback_can_release_mdl;
binlog_hton->commit= binlog_commit;
binlog_hton->rollback= binlog_rollback;
binlog_hton->prepare= binlog_prepare;
@@ -2028,6 +2032,32 @@ static int binlog_prepare(handlerton *hton, THD *thd, bool all)
return 0;
}
+/*
+ We flush the cache wrapped in a beging/rollback if:
+ . aborting a single or multi-statement transaction and;
+ . the OPTION_KEEP_LOG is active or;
+ . the format is STMT and a non-trans table was updated or;
+ . the format is MIXED and a temporary non-trans table was
+ updated or;
+ . the format is MIXED, non-trans table was updated and
+ aborting a single statement transaction;
+*/
+static bool trans_cannot_safely_rollback(THD *thd, bool all)
+{
+ binlog_cache_mngr *const cache_mngr=
+ (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
+
+ return ((thd->variables.option_bits & OPTION_KEEP_LOG) ||
+ (trans_has_updated_non_trans_table(thd) &&
+ WSREP_FORMAT(thd->variables.binlog_format) == BINLOG_FORMAT_STMT) ||
+ (cache_mngr->trx_cache.changes_to_non_trans_temp_table() &&
+ WSREP_FORMAT(thd->variables.binlog_format) == BINLOG_FORMAT_MIXED) ||
+ (trans_has_updated_non_trans_table(thd) &&
+ ending_single_stmt_trans(thd,all) &&
+ WSREP_FORMAT(thd->variables.binlog_format) == BINLOG_FORMAT_MIXED));
+}
+
+
/**
This function is called once after each statement.
@@ -2157,26 +2187,8 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
error |= binlog_truncate_trx_cache(thd, cache_mngr, all);
}
else if (!error)
- {
- /*
- We flush the cache wrapped in a beging/rollback if:
- . aborting a single or multi-statement transaction and;
- . the OPTION_KEEP_LOG is active or;
- . the format is STMT and a non-trans table was updated or;
- . the format is MIXED and a temporary non-trans table was
- updated or;
- . the format is MIXED, non-trans table was updated and
- aborting a single statement transaction;
- */
- if (ending_trans(thd, all) &&
- ((thd->variables.option_bits & OPTION_KEEP_LOG) ||
- (trans_has_updated_non_trans_table(thd) &&
- WSREP_FORMAT(thd->variables.binlog_format) == BINLOG_FORMAT_STMT) ||
- (cache_mngr->trx_cache.changes_to_non_trans_temp_table() &&
- WSREP_FORMAT(thd->variables.binlog_format) == BINLOG_FORMAT_MIXED) ||
- (trans_has_updated_non_trans_table(thd) &&
- ending_single_stmt_trans(thd,all) &&
- WSREP_FORMAT(thd->variables.binlog_format) == BINLOG_FORMAT_MIXED)))
+ {
+ if (ending_trans(thd, all) && trans_cannot_safely_rollback(thd, all))
error= binlog_rollback_flush_trx_cache(thd, all, cache_mngr);
/*
Truncate the cache if:
@@ -2366,6 +2378,30 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv)
}
+/**
+ Check whether binlog state allows to safely release MDL locks after
+ rollback to savepoint.
+
+ @param hton The binlog handlerton.
+ @param thd The client thread that executes the transaction.
+
+ @return true - It is safe to release MDL locks.
+ false - If it is not.
+*/
+static bool binlog_savepoint_rollback_can_release_mdl(handlerton *hton,
+ THD *thd)
+{
+ DBUG_ENTER("binlog_savepoint_rollback_can_release_mdl");
+ /*
+ If we have not updated any non-transactional tables rollback
+ to savepoint will simply truncate binlog cache starting from
+ SAVEPOINT command. So it should be safe to release MDL acquired
+ after SAVEPOINT command in this case.
+ */
+ DBUG_RETURN(!trans_cannot_safely_rollback(thd, true));
+}
+
+
int check_binlog_magic(IO_CACHE* log, const char** errmsg)
{
uchar magic[4];
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 9886e90bb41..c8b394e8290 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1,6 +1,6 @@
/*
- Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2009, 2013, Monty Program Ab.
+ Copyright (c) 2000, 2014, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2014, Monty Program 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
@@ -41,6 +41,7 @@
#include "transaction.h"
#include <my_dir.h>
#include "sql_show.h" // append_identifier
+#include <mysql/psi/mysql_statement.h>
#include <strfunc.h>
#include "compat56.h"
@@ -4167,7 +4168,8 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi,
(sql_mode & ~(ulong) MODE_NO_DIR_IN_CREATE));
if (charset_inited)
{
- if (rli->cached_charset_compare(charset))
+ rpl_sql_thread_info *sql_info= thd->system_thread_info.rpl_sql_info;
+ if (sql_info->cached_charset_compare(charset))
{
/* Verify that we support the charsets found in the event. */
if (!(thd->variables.character_set_client=
@@ -4183,7 +4185,7 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi,
stop with EE_UNKNOWN_CHARSET in compare_errors (unless set to
ignore this error).
*/
- set_slave_thread_default_charset(thd, rli);
+ set_slave_thread_default_charset(thd, rgi);
goto compare_errors;
}
thd->update_charset(); // for the charset change to take effect
@@ -4285,6 +4287,13 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi,
Parser_state parser_state;
if (!parser_state.init(thd, thd->query(), thd->query_length()))
{
+ thd->m_statement_psi= MYSQL_START_STATEMENT(&thd->m_statement_state,
+ stmt_info_rpl.m_key,
+ thd->db, thd->db_length,
+ thd->charset());
+ THD_STAGE_INFO(thd, stage_init);
+ MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, thd->query(), thd->query_length());
+
mysql_parse(thd, thd->query(), thd->query_length(), &parser_state);
/* Finalize server status flags after executing a statement. */
thd->update_server_status();
@@ -4468,6 +4477,11 @@ end:
thd->set_db(NULL, 0); /* will free the current database */
thd->reset_query();
DBUG_PRINT("info", ("end: query= 0"));
+
+ /* Mark the statement completed. */
+ MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
+ thd->m_statement_psi= NULL;
+
/*
As a disk space optimization, future masters will not log an event for
LAST_INSERT_ID() if that function returned 0 (and thus they will be able
@@ -4484,18 +4498,7 @@ end:
int Query_log_event::do_update_pos(rpl_group_info *rgi)
{
- /*
- Note that we will not increment group* positions if we are just
- after a SET ONE_SHOT, because SET ONE_SHOT should not be separated
- from its following updating query.
- */
- if (thd->one_shot_set)
- {
- rgi->inc_event_relay_log_pos();
- return 0;
- }
- else
- return Log_event::do_update_pos(rgi);
+ return Log_event::do_update_pos(rgi);
}
@@ -6240,7 +6243,7 @@ int Rotate_log_event::do_update_pos(rpl_group_info *rgi)
master is 4.0 then the events are in the slave's format (conversion).
*/
set_slave_thread_options(thd);
- set_slave_thread_default_charset(thd, rli);
+ set_slave_thread_default_charset(thd, rgi);
thd->variables.sql_mode= global_system_variables.sql_mode;
thd->variables.auto_increment_increment=
thd->variables.auto_increment_offset= 1;
@@ -9501,8 +9504,31 @@ int Rows_log_event::do_add_row_data(uchar *row_data, size_t length)
if (static_cast<size_t>(m_rows_end - m_rows_cur) <= length)
{
size_t const block_size= 1024;
- my_ptrdiff_t const cur_size= m_rows_cur - m_rows_buf;
- my_ptrdiff_t const new_alloc=
+ ulong cur_size= m_rows_cur - m_rows_buf;
+ DBUG_EXECUTE_IF("simulate_too_big_row_case1",
+ cur_size= UINT_MAX32 - (block_size * 10);
+ length= UINT_MAX32 - (block_size * 10););
+ DBUG_EXECUTE_IF("simulate_too_big_row_case2",
+ cur_size= UINT_MAX32 - (block_size * 10);
+ length= block_size * 10;);
+ DBUG_EXECUTE_IF("simulate_too_big_row_case3",
+ cur_size= block_size * 10;
+ length= UINT_MAX32 - (block_size * 10););
+ DBUG_EXECUTE_IF("simulate_too_big_row_case4",
+ cur_size= UINT_MAX32 - (block_size * 10);
+ length= (block_size * 10) - block_size + 1;);
+ ulong remaining_space= UINT_MAX32 - cur_size;
+ /* Check that the new data fits within remaining space and we can add
+ block_size without wrapping.
+ */
+ if (length > remaining_space ||
+ ((length + block_size) > remaining_space))
+ {
+ sql_print_error("The row data is greater than 4GB, which is too big to "
+ "write to the binary log.");
+ DBUG_RETURN(ER_BINLOG_ROW_LOGGING_FAILED);
+ }
+ ulong const new_alloc=
block_size * ((cur_size + length + block_size - 1) / block_size);
uchar* const new_buf= (uchar*)my_realloc((uchar*)m_rows_buf, (uint) new_alloc,
@@ -9834,10 +9860,14 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
/*
Bug#56662 Assertion failed: next_insert_id == 0, file handler.cc
Don't allow generation of auto_increment value when processing
- rows event by setting 'MODE_NO_AUTO_VALUE_ON_ZERO'.
+ rows event by setting 'MODE_NO_AUTO_VALUE_ON_ZERO'. The exception
+ to this rule happens when the auto_inc column exists on some
+ extra columns on the slave. In that case, do not force
+ MODE_NO_AUTO_VALUE_ON_ZERO.
*/
ulonglong saved_sql_mode= thd->variables.sql_mode;
- thd->variables.sql_mode= MODE_NO_AUTO_VALUE_ON_ZERO;
+ if (!is_auto_inc_in_extra_columns())
+ thd->variables.sql_mode= MODE_NO_AUTO_VALUE_ON_ZERO;
// row processing loop
@@ -11171,9 +11201,28 @@ Write_rows_log_event::do_before_row_operations(const Slave_reporting_capability
* table->auto_increment_field_not_null and SQL_MODE(if includes
* MODE_NO_AUTO_VALUE_ON_ZERO) in update_auto_increment function.
* SQL_MODE of slave sql thread is always consistency with master's.
- * In RBR, auto_increment fields never are NULL.
+ * In RBR, auto_increment fields never are NULL, except if the auto_inc
+ * column exists only on the slave side (i.e., in an extra column
+ * on the slave's table).
*/
- m_table->auto_increment_field_not_null= TRUE;
+ if (!is_auto_inc_in_extra_columns())
+ m_table->auto_increment_field_not_null= TRUE;
+ else
+ {
+ /*
+ Here we have checked that there is an extra field
+ on this server's table that has an auto_inc column.
+
+ Mark that the auto_increment field is null and mark
+ the read and write set bits.
+
+ (There can only be one AUTO_INC column, it is always
+ indexed and it cannot have a DEFAULT value).
+ */
+ m_table->auto_increment_field_not_null= FALSE;
+ m_table->mark_auto_increment_column();
+ }
+
return error;
}
@@ -11182,6 +11231,19 @@ Write_rows_log_event::do_after_row_operations(const Slave_reporting_capability *
int error)
{
int local_error= 0;
+
+ /**
+ Clear the write_set bit for auto_inc field that only
+ existed on the destination table as an extra column.
+ */
+ if (is_auto_inc_in_extra_columns())
+ {
+ bitmap_clear_bit(m_table->write_set, m_table->next_number_field->field_index);
+ bitmap_clear_bit( m_table->read_set, m_table->next_number_field->field_index);
+
+ if (get_flags(STMT_END_F))
+ m_table->file->ha_release_auto_increment();
+ }
m_table->next_number_field=0;
m_table->auto_increment_field_not_null= FALSE;
if ((slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT) ||
@@ -11334,7 +11396,13 @@ Rows_log_event::write_row(rpl_group_info *rgi,
ulong estimated_rows= (m_rows_end - m_curr_row) / (m_curr_row_end - m_curr_row);
table->file->ha_start_bulk_insert(estimated_rows);
}
-
+
+ /*
+ Explicitly set the auto_inc to null to make sure that
+ it gets an auto_generated value.
+ */
+ if (is_auto_inc_in_extra_columns())
+ m_table->next_number_field->set_null();
#ifndef DBUG_OFF
DBUG_DUMP("record[0]", table->record[0], table->s->reclength);
diff --git a/sql/log_event.h b/sql/log_event.h
index bba1b907a57..020af59ae81 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -1,5 +1,5 @@
-/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2009, 2013, Monty Program Ab.
+/* Copyright (c) 2000, 2014, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2014, Monty Program 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
@@ -663,7 +663,8 @@ enum Log_event_type
PRE_GA_DELETE_ROWS_EVENT = 22,
/*
- These event numbers are used from 5.1.16 until mysql-trunk-xx
+ These event numbers are used from 5.1.16 until mysql-5.6.6,
+ and in MariaDB
*/
WRITE_ROWS_EVENT_V1 = 23,
UPDATE_ROWS_EVENT_V1 = 24,
@@ -685,11 +686,13 @@ enum Log_event_type
data to the slave: data that a slave can handle in case there
is code for handling it, but which can be ignored if it is not
recognized.
+
+ These mysql-5.6 events are not recognized (and ignored) by MariaDB
*/
IGNORABLE_LOG_EVENT= 28,
ROWS_QUERY_LOG_EVENT= 29,
- /* Version 2 of the Row events */
+ /* Version 2 of the Row events, generated only by mysql-5.6.6+ */
WRITE_ROWS_EVENT = 30,
UPDATE_ROWS_EVENT = 31,
DELETE_ROWS_EVENT = 32,
@@ -4340,7 +4343,21 @@ protected:
bool process_triggers(trg_event_type event,
trg_action_time_type time_type,
bool old_row_is_record1);
-#endif //defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
+
+ /**
+ Helper function to check whether there is an auto increment
+ column on the table where the event is to be applied.
+
+ @return true if there is an autoincrement field on the extra
+ columns, false otherwise.
+ */
+ inline bool is_auto_inc_in_extra_columns()
+ {
+ DBUG_ASSERT(m_table);
+ return (m_table->next_number_field &&
+ m_table->next_number_field->field_index >= m_width);
+ }
+#endif
private:
diff --git a/sql/mdl.cc b/sql/mdl.cc
index 8360243b4da..5755b2bbfd5 100644
--- a/sql/mdl.cc
+++ b/sql/mdl.cc
@@ -730,6 +730,7 @@ static inline int mdl_iterate_lock(MDL_lock *lock,
int mdl_iterate(int (*callback)(MDL_ticket *ticket, void *arg), void *arg)
{
+ DYNAMIC_ARRAY locks;
uint i, j;
int res;
DBUG_ENTER("mdl_iterate");
@@ -738,18 +739,48 @@ int mdl_iterate(int (*callback)(MDL_ticket *ticket, void *arg), void *arg)
(res= mdl_iterate_lock(mdl_locks.m_commit_lock, callback, arg)))
DBUG_RETURN(res);
+ my_init_dynamic_array(&locks, sizeof(MDL_lock*), 512, 1, MYF(0));
+
for (i= 0; i < mdl_locks.m_partitions.elements(); i++)
{
MDL_map_partition *part= mdl_locks.m_partitions.at(i);
+ /* Collect all locks first */
mysql_mutex_lock(&part->m_mutex);
+ if (allocate_dynamic(&locks, part->m_locks.records))
+ {
+ res= 1;
+ mysql_mutex_unlock(&part->m_mutex);
+ break;
+ }
+ reset_dynamic(&locks);
for (j= 0; j < part->m_locks.records; j++)
{
- if ((res= mdl_iterate_lock((MDL_lock*) my_hash_element(&part->m_locks, j),
- callback, arg)))
- break;
+ MDL_lock *lock= (MDL_lock*) my_hash_element(&part->m_locks, j);
+ lock->m_ref_usage++;
+ insert_dynamic(&locks, &lock);
}
mysql_mutex_unlock(&part->m_mutex);
+
+ /* Now show them */
+ for (j= 0; j < locks.elements; j++)
+ {
+ MDL_lock *lock= (MDL_lock*) *dynamic_element(&locks, j, MDL_lock**);
+ res= mdl_iterate_lock(lock, callback, arg);
+
+ mysql_prlock_wrlock(&lock->m_rwlock);
+ uint ref_usage= lock->m_ref_usage;
+ uint ref_release= ++lock->m_ref_release;
+ bool is_destroyed= lock->m_is_destroyed;
+ mysql_prlock_unlock(&lock->m_rwlock);
+
+ if (unlikely(is_destroyed && ref_usage == ref_release))
+ MDL_lock::destroy(lock);
+
+ if (res)
+ break;
+ }
}
+ delete_dynamic(&locks);
DBUG_RETURN(res);
}
diff --git a/sql/mdl.h b/sql/mdl.h
index 1601d5a2634..639a8966b33 100644
--- a/sql/mdl.h
+++ b/sql/mdl.h
@@ -37,6 +37,7 @@ class THD;
class MDL_context;
class MDL_lock;
class MDL_ticket;
+bool ok_for_lower_case_names(const char *name);
/**
@def ENTER_COND(C, M, S, O)
@@ -350,6 +351,7 @@ public:
NAME_LEN) - m_ptr + 1);
m_hash_value= my_hash_sort(&my_charset_bin, (uchar*) m_ptr + 1,
m_length - 1);
+ DBUG_ASSERT(ok_for_lower_case_names(db));
}
void mdl_key_init(const MDL_key *rhs)
{
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index bdd5b59206e..89d0b0281b2 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
+/* Copyright (c) 2000, 2014, Oracle and/or its affiliates.
Copyright (c) 2008, 2014, SkySQL Ab.
This program is free software; you can redistribute it and/or modify
@@ -344,6 +344,13 @@ static PSI_rwlock_key key_rwlock_openssl;
volatile sig_atomic_t ld_assume_kernel_is_set= 0;
#endif
+/**
+ Statement instrumentation key for replication.
+*/
+#ifdef HAVE_PSI_STATEMENT_INTERFACE
+PSI_statement_info stmt_info_rpl;
+#endif
+
/* the default log output is log tables */
static bool lower_case_table_names_used= 0;
static bool max_long_data_size_used= false;
@@ -2368,7 +2375,7 @@ static struct passwd *check_user(const char *user)
}
if (!user)
{
- if (!opt_bootstrap)
+ if (!opt_bootstrap && !opt_help)
{
sql_print_error("Fatal error: Please read \"Security\" section of the manual to find out how to run mysqld as root!\n");
unireg_abort(1);
@@ -3940,7 +3947,7 @@ void init_com_statement_info()
com_statement_info[index].m_flags= 0;
}
- /* "statement/com/query" can mutate into "statement/sql/..." */
+ /* "statement/abstract/query" can mutate into "statement/sql/..." */
com_statement_info[(uint) COM_QUERY].m_flags= PSI_FLAG_MUTABLE;
}
#endif
@@ -10129,6 +10136,8 @@ static PSI_file_info all_server_files[]=
#endif /* HAVE_PSI_INTERFACE */
PSI_stage_info stage_after_create= { 0, "After create", 0};
+PSI_stage_info stage_after_opening_tables= { 0, "After opening tables", 0};
+PSI_stage_info stage_after_table_lock= { 0, "After table lock", 0};
PSI_stage_info stage_allocating_local_table= { 0, "allocating local table", 0};
PSI_stage_info stage_alter_inplace_prepare= { 0, "preparing for alter table", 0};
PSI_stage_info stage_alter_inplace= { 0, "altering table", 0};
@@ -10157,6 +10166,7 @@ PSI_stage_info stage_end= { 0, "end", 0};
PSI_stage_info stage_executing= { 0, "executing", 0};
PSI_stage_info stage_execution_of_init_command= { 0, "Execution of init_command", 0};
PSI_stage_info stage_explaining= { 0, "explaining", 0};
+PSI_stage_info stage_finding_key_cache= { 0, "Finding key cache", 0};
PSI_stage_info stage_finished_reading_one_binlog_switching_to_next_binlog= { 0, "Finished reading one binlog; switching to next binlog", 0};
PSI_stage_info stage_flushing_relay_log_and_master_info_repository= { 0, "Flushing relay log and master info repository.", 0};
PSI_stage_info stage_flushing_relay_log_info_file= { 0, "Flushing relay-log info file.", 0};
@@ -10181,6 +10191,7 @@ PSI_stage_info stage_purging_old_relay_logs= { 0, "Purging old relay logs", 0};
PSI_stage_info stage_query_end= { 0, "query end", 0};
PSI_stage_info stage_queueing_master_event_to_the_relay_log= { 0, "Queueing master event to the relay log", 0};
PSI_stage_info stage_reading_event_from_the_relay_log= { 0, "Reading event from the relay log", 0};
+PSI_stage_info stage_recreating_table= { 0, "recreating table", 0};
PSI_stage_info stage_registering_slave_on_master= { 0, "Registering slave on master", 0};
PSI_stage_info stage_removing_duplicates= { 0, "Removing duplicates", 0};
PSI_stage_info stage_removing_tmp_table= { 0, "removing tmp table", 0};
@@ -10249,6 +10260,8 @@ PSI_stage_info stage_gtid_wait_other_connection= { 0, "Waiting for other master
PSI_stage_info *all_server_stages[]=
{
& stage_after_create,
+ & stage_after_opening_tables,
+ & stage_after_table_lock,
& stage_allocating_local_table,
& stage_alter_inplace,
& stage_alter_inplace_commit,
@@ -10280,6 +10293,7 @@ PSI_stage_info *all_server_stages[]=
& stage_executing,
& stage_execution_of_init_command,
& stage_explaining,
+ & stage_finding_key_cache,
& stage_finished_reading_one_binlog_switching_to_next_binlog,
& stage_flushing_relay_log_and_master_info_repository,
& stage_flushing_relay_log_info_file,
@@ -10304,6 +10318,7 @@ PSI_stage_info *all_server_stages[]=
& stage_query_end,
& stage_queueing_master_event_to_the_relay_log,
& stage_reading_event_from_the_relay_log,
+ & stage_recreating_table,
& stage_registering_slave_on_master,
& stage_removing_duplicates,
& stage_removing_tmp_table,
@@ -10411,23 +10426,49 @@ void init_server_psi_keys(void)
category= "com";
init_com_statement_info();
- count= array_elements(com_statement_info);
+
+ /*
+ Register [0 .. COM_QUERY - 1] as "statement/com/..."
+ */
+ count= (int) COM_QUERY;
mysql_statement_register(category, com_statement_info, count);
/*
+ Register [COM_QUERY + 1 .. COM_END] as "statement/com/..."
+ */
+ count= (int) COM_END - (int) COM_QUERY;
+ mysql_statement_register(category, & com_statement_info[(int) COM_QUERY + 1], count);
+
+ category= "abstract";
+ /*
+ Register [COM_QUERY] as "statement/abstract/com_query"
+ */
+ mysql_statement_register(category, & com_statement_info[(int) COM_QUERY], 1);
+
+ /*
When a new packet is received,
- it is instrumented as "statement/com/".
+ it is instrumented as "statement/abstract/new_packet".
Based on the packet type found, it later mutates to the
proper narrow type, for example
- "statement/com/query" or "statement/com/ping".
- In cases of "statement/com/query", SQL queries are given to
+ "statement/abstract/query" or "statement/com/ping".
+ In cases of "statement/abstract/query", SQL queries are given to
the parser, which mutates the statement type to an even more
narrow classification, for example "statement/sql/select".
*/
stmt_info_new_packet.m_key= 0;
- stmt_info_new_packet.m_name= "";
+ stmt_info_new_packet.m_name= "new_packet";
stmt_info_new_packet.m_flags= PSI_FLAG_MUTABLE;
mysql_statement_register(category, &stmt_info_new_packet, 1);
+
+ /*
+ Statements processed from the relay log are initially instrumented as
+ "statement/abstract/relay_log". The parser will mutate the statement type to
+ a more specific classification, for example "statement/sql/insert".
+ */
+ stmt_info_rpl.m_key= 0;
+ stmt_info_rpl.m_name= "relay_log";
+ stmt_info_rpl.m_flags= PSI_FLAG_MUTABLE;
+ mysql_statement_register(category, &stmt_info_rpl, 1);
#endif
}
diff --git a/sql/mysqld.h b/sql/mysqld.h
index f1dde5cc03e..dd774e0d565 100644
--- a/sql/mysqld.h
+++ b/sql/mysqld.h
@@ -338,6 +338,8 @@ void init_server_psi_keys();
Hint: grep PSI_stage_info | sort -u
*/
extern PSI_stage_info stage_after_create;
+extern PSI_stage_info stage_after_opening_tables;
+extern PSI_stage_info stage_after_table_lock;
extern PSI_stage_info stage_allocating_local_table;
extern PSI_stage_info stage_alter_inplace_prepare;
extern PSI_stage_info stage_alter_inplace;
@@ -366,6 +368,7 @@ extern PSI_stage_info stage_enabling_keys;
extern PSI_stage_info stage_executing;
extern PSI_stage_info stage_execution_of_init_command;
extern PSI_stage_info stage_explaining;
+extern PSI_stage_info stage_finding_key_cache;
extern PSI_stage_info stage_finished_reading_one_binlog_switching_to_next_binlog;
extern PSI_stage_info stage_flushing_relay_log_and_master_info_repository;
extern PSI_stage_info stage_flushing_relay_log_info_file;
@@ -390,6 +393,7 @@ extern PSI_stage_info stage_purging_old_relay_logs;
extern PSI_stage_info stage_query_end;
extern PSI_stage_info stage_queueing_master_event_to_the_relay_log;
extern PSI_stage_info stage_reading_event_from_the_relay_log;
+extern PSI_stage_info stage_recreating_table;
extern PSI_stage_info stage_registering_slave_on_master;
extern PSI_stage_info stage_removing_duplicates;
extern PSI_stage_info stage_removing_tmp_table;
@@ -466,6 +470,11 @@ extern PSI_statement_info sql_statement_info[(uint) SQLCOM_END + 1];
*/
extern PSI_statement_info com_statement_info[(uint) COM_END + 1];
+/**
+ Statement instrumentation key for replication.
+*/
+extern PSI_statement_info stmt_info_rpl;
+
void init_sql_statement_info();
void init_com_statement_info();
#endif /* HAVE_PSI_STATEMENT_INTERFACE */
@@ -632,7 +641,7 @@ extern my_atomic_rwlock_t statistics_lock;
void unireg_end(void) __attribute__((noreturn));
/* increment query_id and return it. */
-inline query_id_t next_query_id()
+inline __attribute__((warn_unused_result)) query_id_t next_query_id()
{
query_id_t id;
my_atomic_rwlock_wrlock(&global_query_id_lock);
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index cbc3d285d0a..bfba74cf587 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -2181,7 +2181,7 @@ int QUICK_ROR_INTERSECT_SELECT::init_ror_merged_scan(bool reuse_handler,
quick->record= head->record[0];
}
- if (need_to_fetch_row && head->file->ha_rnd_init_with_error(1))
+ if (need_to_fetch_row && head->file->ha_rnd_init_with_error(false))
{
DBUG_PRINT("error", ("ROR index_merge rnd_init call failed"));
DBUG_RETURN(1);
@@ -2363,8 +2363,13 @@ int QUICK_ROR_UNION_SELECT::reset()
quick->save_last_pos();
queue_insert(&queue, (uchar*)quick);
}
-
- if ((error= head->file->ha_rnd_init(1)))
+ /* Prepare for ha_rnd_pos calls. */
+ if (head->file->inited && (error= head->file->ha_rnd_end()))
+ {
+ DBUG_PRINT("error", ("ROR index_merge rnd_end call failed"));
+ DBUG_RETURN(error);
+ }
+ if ((error= head->file->ha_rnd_init(false)))
{
DBUG_PRINT("error", ("ROR index_merge rnd_init call failed"));
DBUG_RETURN(error);
@@ -3390,6 +3395,17 @@ double records_in_column_ranges(PARAM *param, uint idx,
on the rows of 'table' in the processed query.
The calculated selectivity is assigned to the field table->cond_selectivity.
+ Selectivity is calculated as a product of selectivities imposed by:
+
+ 1. possible range accesses. (if multiple range accesses use the same
+ restrictions on the same field, we make adjustments for that)
+ 2. Sargable conditions on fields for which we have column statistics (if
+ a field is used in a possible range access, we assume that selectivity
+ is already provided by the range access' estimates)
+ 3. Reading a few records from the table pages and checking the condition
+ selectivity (this is used for conditions like "column LIKE '%val%'"
+ where approaches #1 and #2 do not provide selectivity data).
+
NOTE
Currently the selectivities of range conditions over different columns are
considered independent.
@@ -3415,14 +3431,90 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item *cond)
if (table->pos_in_table_list->schema_table)
DBUG_RETURN(FALSE);
+ MY_BITMAP handled_columns;
+ my_bitmap_map* buf;
+ if (!(buf= (my_bitmap_map*)thd->alloc(table->s->column_bitmap_size)))
+ DBUG_RETURN(TRUE);
+ my_bitmap_init(&handled_columns, buf, table->s->fields, FALSE);
+
+ /*
+ First, take into account possible range accesses.
+ range access estimates are the most precise, we prefer them to any other
+ estimate sources.
+ */
+
+ for (keynr= 0; keynr < table->s->keys; keynr++)
+ {
+ if (table->quick_keys.is_set(keynr))
+ set_if_bigger(max_quick_key_parts, table->quick_key_parts[keynr]);
+ }
+
+ /*
+ Walk through all indexes, indexes where range access uses more keyparts
+ go first.
+ */
+ for (uint quick_key_parts= max_quick_key_parts;
+ quick_key_parts; quick_key_parts--)
+ {
+ for (keynr= 0; keynr < table->s->keys; keynr++)
+ {
+ if (table->quick_keys.is_set(keynr) &&
+ table->quick_key_parts[keynr] == quick_key_parts)
+ {
+ uint i;
+ uint used_key_parts= table->quick_key_parts[keynr];
+ double quick_cond_selectivity= table->quick_rows[keynr] /
+ table_records;
+ KEY *key_info= table->key_info + keynr;
+ KEY_PART_INFO* key_part= key_info->key_part;
+ /*
+ Suppose, there are range conditions on two keys
+ KEY1 (col1, col2)
+ KEY2 (col3, col2)
+
+ we don't want to count selectivity of condition on col2 twice.
+
+ First, find the longest key prefix that's made of columns whose
+ selectivity wasn't already accounted for.
+ */
+ for (i= 0; i < used_key_parts; i++, key_part++)
+ {
+ if (bitmap_is_set(&handled_columns, key_part->fieldnr-1))
+ break;
+ bitmap_set_bit(&handled_columns, key_part->fieldnr-1);
+ }
+ if (i)
+ {
+ /*
+ There is at least 1-column prefix of columns whose selectivity has
+ not yet been accounted for.
+ */
+ table->cond_selectivity*= quick_cond_selectivity;
+ if (i != used_key_parts)
+ {
+ /*
+ Range access got us estimate for #used_key_parts.
+ We need estimate for #(i-1) key parts.
+ */
+ double f1= key_info->actual_rec_per_key(i-1);
+ double f2= key_info->actual_rec_per_key(i);
+ table->cond_selectivity*= f1 / f2;
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ Second step: calculate the selectivity of the range conditions not
+ supported by any index
+ */
+ bitmap_subtract(used_fields, &handled_columns);
+ /* no need to do: my_bitmap_free(&handled_columns); */
+
if (thd->variables.optimizer_use_condition_selectivity > 2 &&
!bitmap_is_clear_all(used_fields))
{
- /*
- Calculate the selectivity of the range conditions not supported
- by any index
- */
-
PARAM param;
MEM_ROOT alloc;
SEL_TREE *tree;
@@ -3509,47 +3601,8 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item *cond)
bitmap_clear_all(used_fields);
- for (keynr= 0; keynr < table->s->keys; keynr++)
- {
- if (table->quick_keys.is_set(keynr))
- set_if_bigger(max_quick_key_parts, table->quick_key_parts[keynr]);
- }
-
- for (uint quick_key_parts= max_quick_key_parts;
- quick_key_parts; quick_key_parts--)
- {
- for (keynr= 0; keynr < table->s->keys; keynr++)
- {
- if (table->quick_keys.is_set(keynr) &&
- table->quick_key_parts[keynr] == quick_key_parts)
- {
- uint i;
- uint used_key_parts= table->quick_key_parts[keynr];
- double quick_cond_selectivity= table->quick_rows[keynr] /
- table_records;
- KEY *key_info= table->key_info + keynr;
- KEY_PART_INFO* key_part= key_info->key_part;
- for (i= 0; i < used_key_parts; i++, key_part++)
- {
- if (bitmap_is_set(used_fields, key_part->fieldnr-1))
- break;
- bitmap_set_bit(used_fields, key_part->fieldnr-1);
- }
- if (i)
- {
- table->cond_selectivity*= quick_cond_selectivity;
- if (i != used_key_parts)
- {
- double f1= key_info->actual_rec_per_key(i-1);
- double f2= key_info->actual_rec_per_key(i);
- table->cond_selectivity*= f1 / f2;
- }
- }
- }
- }
- }
- /* Calculate selectivity of probably highly selective predicates */
+ /* Check if we can improve selectivity estimates by using sampling */
ulong check_rows=
MY_MIN(thd->variables.optimizer_selectivity_sampling_limit,
(ulong) (table_records * SELECTIVITY_SAMPLING_SHARE));
@@ -13376,7 +13429,7 @@ SEL_ARG * get_index_range_tree(uint index, SEL_TREE* range_tree, PARAM *param,
DESCRIPTION
This method computes the access cost of a TRP_GROUP_MIN_MAX instance and
- the number of rows returned. It updates this->read_cost and this->records.
+ the number of rows returned.
NOTES
The cost computation distinguishes several cases:
@@ -13432,7 +13485,6 @@ void cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts,
double p_overlap; /* Probability that a sub-group overlaps two blocks. */
double quick_prefix_selectivity;
double io_cost;
- double cpu_cost= 0; /* TODO: CPU cost of index_read calls? */
DBUG_ENTER("cost_group_min_max");
table_records= table->stat_records();
@@ -13480,11 +13532,25 @@ void cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts,
(double) num_blocks;
/*
- TODO: If there is no WHERE clause and no other expressions, there should be
- no CPU cost. We leave it here to make this cost comparable to that of index
- scan as computed in SQL_SELECT::test_quick_select().
+ CPU cost must be comparable to that of an index scan as computed
+ in SQL_SELECT::test_quick_select(). When the groups are small,
+ e.g. for a unique index, using index scan will be cheaper since it
+ reads the next record without having to re-position to it on every
+ group. To make the CPU cost reflect this, we estimate the CPU cost
+ as the sum of:
+ 1. Cost for evaluating the condition (similarly as for index scan).
+ 2. Cost for navigating the index structure (assuming a b-tree).
+ Note: We only add the cost for one comparision per block. For a
+ b-tree the number of comparisons will be larger.
+ TODO: This cost should be provided by the storage engine.
*/
- cpu_cost= (double) num_groups / TIME_FOR_COMPARE;
+ const double tree_traversal_cost=
+ ceil(log(static_cast<double>(table_records))/
+ log(static_cast<double>(keys_per_block))) *
+ 1/double(2*TIME_FOR_COMPARE);
+
+ const double cpu_cost= num_groups *
+ (tree_traversal_cost + 1/double(TIME_FOR_COMPARE));
*read_cost= io_cost + cpu_cost;
*records= num_groups;
@@ -13689,15 +13755,21 @@ int QUICK_GROUP_MIN_MAX_SELECT::init()
{
if (group_prefix) /* Already initialized. */
return 0;
-
- if (!(last_prefix= (uchar*) alloc_root(&alloc, group_prefix_len)))
+
+ /*
+ We allocate one byte more to serve the case when the last field in
+ the buffer is compared using uint3korr (e.g. a Field_newdate field)
+ */
+ if (!(last_prefix= (uchar*) alloc_root(&alloc, group_prefix_len+1)))
return 1;
/*
We may use group_prefix to store keys with all select fields, so allocate
enough space for it.
+ We allocate one byte more to serve the case when the last field in
+ the buffer is compared using uint3korr (e.g. a Field_newdate field)
*/
if (!(group_prefix= (uchar*) alloc_root(&alloc,
- real_prefix_len + min_max_arg_len)))
+ real_prefix_len+min_max_arg_len+1)))
return 1;
if (key_infix_len > 0)
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 33c753b8321..af2accfd146 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -64,7 +64,7 @@ bool Protocol_binary::net_store_data(const uchar *from, size_t length)
/*
- net_store_data() - extended version with character set conversion.
+ net_store_data_cs() - extended version with character set conversion.
It is optimized for short strings whose length after
conversion is garanteed to be less than 251, which accupies
@@ -76,8 +76,12 @@ bool Protocol_binary::net_store_data(const uchar *from, size_t length)
*/
#ifndef EMBEDDED_LIBRARY
-bool Protocol::net_store_data(const uchar *from, size_t length,
+bool Protocol::net_store_data_cs(const uchar *from, size_t length,
CHARSET_INFO *from_cs, CHARSET_INFO *to_cs)
+#else
+bool Protocol_binary::net_store_data_cs(const uchar *from, size_t length,
+ CHARSET_INFO *from_cs, CHARSET_INFO *to_cs)
+#endif
{
uint dummy_errors;
/* Calculate maxumum possible result length */
@@ -117,7 +121,6 @@ bool Protocol::net_store_data(const uchar *from, size_t length,
packet->length((uint) (to - packet->ptr()));
return 0;
}
-#endif
/**
@@ -1015,7 +1018,7 @@ bool Protocol::store_string_aux(const char *from, size_t length,
tocs != &my_charset_bin)
{
/* Store with conversion */
- return net_store_data((uchar*) from, length, fromcs, tocs);
+ return net_store_data_cs((uchar*) from, length, fromcs, tocs);
}
/* Store without conversion */
return net_store_data((uchar*) from, length);
diff --git a/sql/protocol.h b/sql/protocol.h
index 1c0a28560bd..c58de68289f 100644
--- a/sql/protocol.h
+++ b/sql/protocol.h
@@ -44,8 +44,12 @@ protected:
uint field_count;
#ifndef EMBEDDED_LIBRARY
bool net_store_data(const uchar *from, size_t length);
+ bool net_store_data_cs(const uchar *from, size_t length,
+ CHARSET_INFO *fromcs, CHARSET_INFO *tocs);
#else
virtual bool net_store_data(const uchar *from, size_t length);
+ virtual bool net_store_data_cs(const uchar *from, size_t length,
+ CHARSET_INFO *fromcs, CHARSET_INFO *tocs);
char **next_field;
MYSQL_FIELD *next_mysql_field;
MEM_ROOT *alloc;
@@ -54,8 +58,6 @@ protected:
The following two are low-level functions that are invoked from
higher-level store_xxx() funcs. The data is stored into this->packet.
*/
- bool net_store_data(const uchar *from, size_t length,
- CHARSET_INFO *fromcs, CHARSET_INFO *tocs);
bool store_string_aux(const char *from, size_t length,
CHARSET_INFO *fromcs, CHARSET_INFO *tocs);
@@ -184,6 +186,8 @@ public:
#ifdef EMBEDDED_LIBRARY
virtual bool write();
bool net_store_data(const uchar *from, size_t length);
+ bool net_store_data_cs(const uchar *from, size_t length,
+ CHARSET_INFO *fromcs, CHARSET_INFO *tocs);
#endif
virtual bool store_null();
virtual bool store_tiny(longlong from);
diff --git a/sql/rpl_mi.h b/sql/rpl_mi.h
index a136af38356..af739b1dad4 100644
--- a/sql/rpl_mi.h
+++ b/sql/rpl_mi.h
@@ -216,6 +216,16 @@ public:
bool stop_all_slaves(THD *thd);
};
+
+/*
+ The class rpl_io_thread_info is the THD::system_thread_info for the IO thread.
+*/
+class rpl_io_thread_info
+{
+public:
+};
+
+
bool check_master_connection_name(LEX_STRING *name);
void create_logfile_name_with_suffix(char *res_file_name, size_t length,
const char *info_file,
diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc
index 9c4c819c022..e72d3470a7f 100644
--- a/sql/rpl_parallel.cc
+++ b/sql/rpl_parallel.cc
@@ -33,7 +33,7 @@ rpt_handle_event(rpl_parallel_thread::queued_event *qev,
THD *thd= rgi->thd;
thd->rgi_slave= rgi;
- thd->rpl_filter = rli->mi->rpl_filter;
+ thd->system_thread_info.rpl_sql_info->rpl_filter = rli->mi->rpl_filter;
/* ToDo: Access to thd, and what about rli, split out a parallel part? */
mysql_mutex_lock(&rli->data_lock);
@@ -212,6 +212,7 @@ handle_rpl_parallel_thread(void *arg)
rpl_parallel_thread::queued_event *qevs_to_free;
rpl_group_info *rgis_to_free;
group_commit_orderer *gcos_to_free;
+ rpl_sql_thread_info sql_info(NULL);
size_t total_event_size;
int err;
@@ -242,6 +243,7 @@ handle_rpl_parallel_thread(void *arg)
thd_proc_info(thd, "Waiting for work from main SQL threads");
thd->set_time();
thd->variables.lock_wait_timeout= LONG_TIMEOUT;
+ thd->system_thread_info.rpl_sql_info= &sql_info;
/*
For now, we need to run the replication parallel worker threads in
READ COMMITTED. This is needed because gap locks are not symmetric.
@@ -1495,7 +1497,6 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev,
}
else if (!is_group_event)
{
- my_off_t log_pos;
int err;
bool tmp;
/*
@@ -1509,7 +1510,13 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev,
serial_rgi->is_parallel_exec= true;
err= rpt_handle_event(qev, NULL);
serial_rgi->is_parallel_exec= tmp;
- log_pos= ev->log_pos;
+ if (ev->is_relay_log_event())
+ qev->future_event_master_log_pos= 0;
+ else if (typ == ROTATE_EVENT)
+ qev->future_event_master_log_pos=
+ (static_cast<Rotate_log_event *>(ev))->pos;
+ else
+ qev->future_event_master_log_pos= ev->log_pos;
delete_or_keep_event_post_apply(serial_rgi, typ, ev);
if (err)
@@ -1532,7 +1539,6 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev,
the current point.
*/
qev->ev= NULL;
- qev->future_event_master_log_pos= log_pos;
}
else
{
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index 0d0c8c9df70..a162d1d79f8 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -82,7 +82,6 @@ Relay_log_info::Relay_log_info(bool is_slave_recovery)
max_relay_log_size= global_system_variables.max_relay_log_size;
bzero((char*) &info_file, sizeof(info_file));
bzero((char*) &cache_buf, sizeof(cache_buf));
- cached_charset_invalidate();
mysql_mutex_init(key_relay_log_info_run_lock, &run_lock, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_relay_log_info_data_lock,
&data_lock, MY_MUTEX_INIT_FAST);
@@ -1200,29 +1199,6 @@ bool Relay_log_info::is_until_satisfied(THD *thd, Log_event *ev)
}
-void Relay_log_info::cached_charset_invalidate()
-{
- DBUG_ENTER("Relay_log_info::cached_charset_invalidate");
-
- /* Full of zeroes means uninitialized. */
- bzero(cached_charset, sizeof(cached_charset));
- DBUG_VOID_RETURN;
-}
-
-
-bool Relay_log_info::cached_charset_compare(char *charset) const
-{
- DBUG_ENTER("Relay_log_info::cached_charset_compare");
-
- if (memcmp(cached_charset, charset, sizeof(cached_charset)))
- {
- memcpy(const_cast<char*>(cached_charset), charset, sizeof(cached_charset));
- DBUG_RETURN(1);
- }
- DBUG_RETURN(0);
-}
-
-
void Relay_log_info::stmt_done(my_off_t event_master_log_pos,
time_t event_creation_time, THD *thd,
rpl_group_info *rgi)
@@ -1769,4 +1745,33 @@ rpl_group_info::mark_start_commit()
}
+rpl_sql_thread_info::rpl_sql_thread_info(Rpl_filter *filter)
+ : rpl_filter(filter)
+{
+ cached_charset_invalidate();
+}
+
+
+void rpl_sql_thread_info::cached_charset_invalidate()
+{
+ DBUG_ENTER("rpl_group_info::cached_charset_invalidate");
+
+ /* Full of zeroes means uninitialized. */
+ bzero(cached_charset, sizeof(cached_charset));
+ DBUG_VOID_RETURN;
+}
+
+
+bool rpl_sql_thread_info::cached_charset_compare(char *charset) const
+{
+ DBUG_ENTER("rpl_group_info::cached_charset_compare");
+
+ if (memcmp(cached_charset, charset, sizeof(cached_charset)))
+ {
+ memcpy(const_cast<char*>(cached_charset), charset, sizeof(cached_charset));
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
+
#endif
diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h
index 48193afce4d..137571ab820 100644
--- a/sql/rpl_rli.h
+++ b/sql/rpl_rli.h
@@ -26,6 +26,7 @@
struct RPL_TABLE_LIST;
class Master_info;
+class Rpl_filter;
/****************************************************************************
@@ -295,7 +296,6 @@ public:
/* Condition for UNTIL master_gtid_pos. */
slave_connection_state until_gtid_pos;
- char cached_charset[6];
/*
retried_trans is a cumulative counter: how many times the slave
has retried a transaction (any) since slave started.
@@ -371,15 +371,6 @@ public:
group_relay_log_pos);
}
- /*
- Last charset (6 bytes) seen by slave SQL thread is cached here; it helps
- the thread save 3 get_charset() per Query_log_event if the charset is not
- changing from event to event (common situation).
- When the 6 bytes are equal to 0 is used to mean "cache is invalidated".
- */
- void cached_charset_invalidate();
- bool cached_charset_compare(char *charset) const;
-
/**
Helper function to do after statement completion.
@@ -726,6 +717,30 @@ struct rpl_group_info
};
+/*
+ The class rpl_sql_thread_info is the THD::system_thread_info for an SQL
+ thread; this is either the driver SQL thread or a worker thread for parallel
+ replication.
+*/
+class rpl_sql_thread_info
+{
+public:
+ char cached_charset[6];
+ Rpl_filter* rpl_filter;
+
+ rpl_sql_thread_info(Rpl_filter *filter);
+
+ /*
+ Last charset (6 bytes) seen by slave SQL thread is cached here; it helps
+ the thread save 3 get_charset() per Query_log_event if the charset is not
+ changing from event to event (common situation).
+ When the 6 bytes are equal to 0 is used to mean "cache is invalidated".
+ */
+ void cached_charset_invalidate();
+ bool cached_charset_compare(char *charset) const;
+};
+
+
// Defined in rpl_rli.cc
int init_relay_log_info(Relay_log_info* rli, const char* info_fname);
diff --git a/sql/set_var.h b/sql/set_var.h
index de47c4646e7..19d2b4fd14c 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -340,6 +340,7 @@ bool fix_delay_key_write(sys_var *self, THD *thd, enum_var_type type);
ulonglong expand_sql_mode(ulonglong sql_mode);
bool sql_mode_string_representation(THD *thd, ulonglong sql_mode, LEX_STRING *ls);
+int default_regex_flags_pcre(const THD *thd);
extern sys_var *Sys_autocommit_ptr;
diff --git a/sql/share/charsets/Index.xml b/sql/share/charsets/Index.xml
index 3e402226a34..9764d629625 100644
--- a/sql/share/charsets/Index.xml
+++ b/sql/share/charsets/Index.xml
@@ -4,6 +4,7 @@
<copyright>
Copyright (c) 2003-2005 MySQL AB
+ Use is subject to license terms
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/share/charsets/ascii.xml b/sql/share/charsets/ascii.xml
index 29336b3a665..c516a68516c 100644
--- a/sql/share/charsets/ascii.xml
+++ b/sql/share/charsets/ascii.xml
@@ -4,6 +4,7 @@
<copyright>
Copyright (c) 2003, 2007 MySQL AB
+ Use is subject to license terms
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/share/charsets/cp1250.xml b/sql/share/charsets/cp1250.xml
index 1b4a71ef6d5..e6681a625a2 100644
--- a/sql/share/charsets/cp1250.xml
+++ b/sql/share/charsets/cp1250.xml
@@ -4,6 +4,7 @@
<copyright>
Copyright (c) 2003, 2005 MySQL AB
+ Use is subject to license terms
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/share/charsets/cp1256.xml b/sql/share/charsets/cp1256.xml
index 806fef961f7..ab0ba855f3b 100644
--- a/sql/share/charsets/cp1256.xml
+++ b/sql/share/charsets/cp1256.xml
@@ -6,6 +6,7 @@
<copyright>
Copyright (C) 2003 MySQL AB
+ Use is subject to license terms
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/share/charsets/cp1257.xml b/sql/share/charsets/cp1257.xml
index 8ae73fdf25a..61d1d276b0a 100644
--- a/sql/share/charsets/cp1257.xml
+++ b/sql/share/charsets/cp1257.xml
@@ -4,6 +4,7 @@
<copyright>
Copyright (C) 2003 MySQL AB
+ Use is subject to license terms
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/share/charsets/cp850.xml b/sql/share/charsets/cp850.xml
index 198b336daef..06465540a75 100644
--- a/sql/share/charsets/cp850.xml
+++ b/sql/share/charsets/cp850.xml
@@ -4,6 +4,7 @@
<copyright>
Copyright (C) 2003 MySQL AB
+ Use is subject to license terms
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/share/charsets/cp866.xml b/sql/share/charsets/cp866.xml
index d35f3d68b05..9cd8c8c504b 100644
--- a/sql/share/charsets/cp866.xml
+++ b/sql/share/charsets/cp866.xml
@@ -4,6 +4,7 @@
<copyright>
Copyright (C) 2003 MySQL AB
+ Use is subject to license terms
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/share/charsets/dec8.xml b/sql/share/charsets/dec8.xml
index 66bb421b674..68949309ced 100644
--- a/sql/share/charsets/dec8.xml
+++ b/sql/share/charsets/dec8.xml
@@ -4,6 +4,7 @@
<copyright>
Copyright (C) 2003 MySQL AB
+ Use is subject to license terms
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/share/charsets/geostd8.xml b/sql/share/charsets/geostd8.xml
index a789d07e6d8..822cc083724 100644
--- a/sql/share/charsets/geostd8.xml
+++ b/sql/share/charsets/geostd8.xml
@@ -4,6 +4,7 @@
<copyright>
Copyright (C) 2003 MySQL AB
+ Use is subject to license terms
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/share/charsets/greek.xml b/sql/share/charsets/greek.xml
index 5b66a7ab442..cbbe22e675a 100644
--- a/sql/share/charsets/greek.xml
+++ b/sql/share/charsets/greek.xml
@@ -4,6 +4,7 @@
<copyright>
Copyright (C) 2003 MySQL AB
+ Use is subject to license terms
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/share/charsets/hebrew.xml b/sql/share/charsets/hebrew.xml
index 0544b27ef4f..562fa4f4748 100644
--- a/sql/share/charsets/hebrew.xml
+++ b/sql/share/charsets/hebrew.xml
@@ -4,6 +4,7 @@
<copyright>
Copyright (c) 2003, 2006 MySQL AB
+ Use is subject to license terms
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/share/charsets/hp8.xml b/sql/share/charsets/hp8.xml
index 83a076237f7..b17f75ed73e 100644
--- a/sql/share/charsets/hp8.xml
+++ b/sql/share/charsets/hp8.xml
@@ -4,6 +4,7 @@
<copyright>
Copyright (C) 2003 MySQL AB
+ Use is subject to license terms
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/share/charsets/keybcs2.xml b/sql/share/charsets/keybcs2.xml
index a9f305deab8..7c2775ba5c3 100644
--- a/sql/share/charsets/keybcs2.xml
+++ b/sql/share/charsets/keybcs2.xml
@@ -4,6 +4,7 @@
<copyright>
Copyright (C) 2003 MySQL AB
+ Use is subject to license terms
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/share/charsets/koi8r.xml b/sql/share/charsets/koi8r.xml
index 21ebf78b79e..25264d4f9ce 100644
--- a/sql/share/charsets/koi8r.xml
+++ b/sql/share/charsets/koi8r.xml
@@ -4,6 +4,7 @@
<copyright>
Copyright (C) 2003 MySQL AB
+ Use is subject to license terms
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/share/charsets/koi8u.xml b/sql/share/charsets/koi8u.xml
index 65145c97593..a2f5de9feb2 100644
--- a/sql/share/charsets/koi8u.xml
+++ b/sql/share/charsets/koi8u.xml
@@ -4,6 +4,7 @@
<copyright>
Copyright (C) 2003 MySQL AB
+ Use is subject to license terms
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/share/charsets/languages.html b/sql/share/charsets/languages.html
index 2b1c44421bf..3263d6a2ae2 100644
--- a/sql/share/charsets/languages.html
+++ b/sql/share/charsets/languages.html
@@ -1,6 +1,7 @@
#!/bin/sh
# Copyright (C) 2003 MySQL AB
+# Use is subject to license terms
#
# 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/share/charsets/latin1.xml b/sql/share/charsets/latin1.xml
index 4054eea8d33..68307847d91 100644
--- a/sql/share/charsets/latin1.xml
+++ b/sql/share/charsets/latin1.xml
@@ -4,6 +4,7 @@
<copyright>
Copyright (c) 2003, 2005 MySQL AB
+ Use is subject to license terms
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/share/charsets/latin2.xml b/sql/share/charsets/latin2.xml
index a44ec7e0ec6..29ff4cb974b 100644
--- a/sql/share/charsets/latin2.xml
+++ b/sql/share/charsets/latin2.xml
@@ -4,6 +4,7 @@
<copyright>
Copyright (c) 2003, 2005 MySQL AB
+ Use is subject to license terms
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/share/charsets/latin5.xml b/sql/share/charsets/latin5.xml
index 6b60e58cdda..ca7dd106de5 100644
--- a/sql/share/charsets/latin5.xml
+++ b/sql/share/charsets/latin5.xml
@@ -4,6 +4,7 @@
<copyright>
Copyright (c) 2003, 2005 MySQL AB
+ Use is subject to license terms
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/share/charsets/latin7.xml b/sql/share/charsets/latin7.xml
index fb384b3a5ff..81866c23bbd 100644
--- a/sql/share/charsets/latin7.xml
+++ b/sql/share/charsets/latin7.xml
@@ -4,6 +4,7 @@
<copyright>
Copyright (C) 2003 MySQL AB
+ Use is subject to license terms
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/share/charsets/macce.xml b/sql/share/charsets/macce.xml
index d7242f26297..4fa46301d2e 100644
--- a/sql/share/charsets/macce.xml
+++ b/sql/share/charsets/macce.xml
@@ -4,6 +4,7 @@
<copyright>
Copyright (C) 2003 MySQL AB
+ Use is subject to license terms
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/share/charsets/macroman.xml b/sql/share/charsets/macroman.xml
index a2485cf9379..4ee8dc1f952 100644
--- a/sql/share/charsets/macroman.xml
+++ b/sql/share/charsets/macroman.xml
@@ -4,6 +4,7 @@
<copyright>
Copyright (C) 2003 MySQL AB
+ Use is subject to license terms
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/share/charsets/swe7.xml b/sql/share/charsets/swe7.xml
index f12a2238718..d881f1e7d62 100644
--- a/sql/share/charsets/swe7.xml
+++ b/sql/share/charsets/swe7.xml
@@ -4,6 +4,7 @@
<copyright>
Copyright (C) 2003 MySQL AB
+ Use is subject to license terms
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/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index dc50c68bcdd..ed7976e2abd 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -6911,6 +6911,49 @@ ER_MTS_EVENT_BIGGER_PENDING_JOBS_SIZE_MAX
ER_INNODB_NO_FT_USES_PARSER
eng "Cannot CREATE FULLTEXT INDEX WITH PARSER on InnoDB table"
+ER_BINLOG_LOGICAL_CORRUPTION
+ eng "The binary log file '%s' is logically corrupted: %s"
+
+ER_WARN_PURGE_LOG_IN_USE
+ eng "file %s was not purged because it was being read by %d thread(s), purged only %d out of %d files."
+
+ER_WARN_PURGE_LOG_IS_ACTIVE
+ eng "file %s was not purged because it is the active log file."
+
+ER_AUTO_INCREMENT_CONFLICT
+ eng "Auto-increment value in UPDATE conflicts with internally generated values"
+
+WARN_ON_BLOCKHOLE_IN_RBR
+ eng "Row events are not logged for %s statements that modify BLACKHOLE tables in row format. Table(s): '%-.192s'"
+
+ER_SLAVE_MI_INIT_REPOSITORY
+ eng "Slave failed to initialize master info structure from the repository"
+
+ER_SLAVE_RLI_INIT_REPOSITORY
+ eng "Slave failed to initialize relay log info structure from the repository"
+
+ER_ACCESS_DENIED_CHANGE_USER_ERROR 28000
+ eng "Access denied trying to change to user '%-.48s'@'%-.64s' (using password: %s). Disconnecting."
+ bgn "Отказан достъп при опит за смяна към потребител %-.48s'@'%-.64s' (използвана парола: %s). Затваряне на връзката."
+
+ER_INNODB_READ_ONLY
+ eng "InnoDB is in read only mode."
+
+ER_STOP_SLAVE_SQL_THREAD_TIMEOUT
+ eng "STOP SLAVE command execution is incomplete: Slave SQL thread got the stop signal, thread is busy, SQL thread will stop once the current task is complete."
+
+ER_STOP_SLAVE_IO_THREAD_TIMEOUT
+ eng "STOP SLAVE command execution is incomplete: Slave IO thread got the stop signal, thread is busy, IO thread will stop once the current task is complete."
+
+ER_TABLE_CORRUPT
+ eng "Operation cannot be performed. The table '%-.64s.%-.64s' is missing, corrupt or contains bad data."
+
+ER_TEMP_FILE_WRITE_FAILURE
+ eng "Temporary file write failure."
+
+ER_INNODB_FT_AUX_NOT_HEX_ID
+ eng "Upgrade index name failed, please use create index(alter table) algorithm copy to rebuild index."
+
#
# MariaDB error messages section starts here
diff --git a/sql/slave.cc b/sql/slave.cc
index 7d24093f27b..a43347743eb 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -321,7 +321,7 @@ handle_slave_init(void *arg __attribute__((unused)))
mysql_mutex_lock(&LOCK_thread_count);
slave_init_thread_running= false;
- mysql_cond_signal(&COND_thread_count);
+ mysql_cond_broadcast(&COND_thread_count);
mysql_mutex_unlock(&LOCK_thread_count);
return 0;
@@ -2882,7 +2882,7 @@ void set_slave_thread_options(THD* thd)
DBUG_VOID_RETURN;
}
-void set_slave_thread_default_charset(THD* thd, Relay_log_info const *rli)
+void set_slave_thread_default_charset(THD* thd, rpl_group_info *rgi)
{
DBUG_ENTER("set_slave_thread_default_charset");
@@ -2894,13 +2894,7 @@ void set_slave_thread_default_charset(THD* thd, Relay_log_info const *rli)
global_system_variables.collation_server;
thd->update_charset();
- /*
- We use a const cast here since the conceptual (and externally
- visible) behavior of the function is to set the default charset of
- the thread. That the cache has to be invalidated is a secondary
- effect.
- */
- const_cast<Relay_log_info*>(rli)->cached_charset_invalidate();
+ thd->system_thread_info.rpl_sql_info->cached_charset_invalidate();
DBUG_VOID_RETURN;
}
@@ -3777,6 +3771,7 @@ pthread_handler_t handle_slave_io(void *arg)
uint retry_count;
bool suppress_warnings;
int ret;
+ rpl_io_thread_info io_info;
#ifndef DBUG_OFF
uint retry_count_reg= 0, retry_count_dump= 0, retry_count_event= 0;
#endif
@@ -3810,6 +3805,7 @@ pthread_handler_t handle_slave_io(void *arg)
sql_print_error("Failed during slave I/O thread initialization");
goto err_during_init;
}
+ thd->system_thread_info.rpl_io_info= &io_info;
mysql_mutex_lock(&LOCK_thread_count);
threads.append(thd);
mysql_mutex_unlock(&LOCK_thread_count);
@@ -4376,6 +4372,7 @@ pthread_handler_t handle_slave_sql(void *arg)
Relay_log_info* rli = &mi->rli;
const char *errmsg;
rpl_group_info *serial_rgi;
+ rpl_sql_thread_info sql_info(mi->rpl_filter);
// needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff
my_thread_init();
@@ -4387,7 +4384,7 @@ pthread_handler_t handle_slave_sql(void *arg)
serial_rgi= new rpl_group_info(rli);
thd = new THD; // note that contructor of THD uses DBUG_ !
thd->thread_stack = (char*)&thd; // remember where our stack is
- thd->rpl_filter = mi->rpl_filter;
+ thd->system_thread_info.rpl_sql_info= &sql_info;
DBUG_ASSERT(rli->inited);
DBUG_ASSERT(rli->mi == mi);
@@ -4690,7 +4687,7 @@ err_during_init:
mysql_cond_broadcast(&rli->data_cond);
rli->ignore_log_space_limit= 0; /* don't need any lock */
/* we die so won't remember charset - re-update them on next thread start */
- rli->cached_charset_invalidate();
+ thd->system_thread_info.rpl_sql_info->cached_charset_invalidate();
/*
TODO: see if we can do this conditionally in next_event() instead
diff --git a/sql/slave.h b/sql/slave.h
index 3981a9d4f2c..aa3976f6e6c 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -51,6 +51,7 @@
class Relay_log_info;
class Master_info;
class Master_info_index;
+struct rpl_group_info;
struct rpl_parallel_thread;
int init_intvar_from_file(int* var, IO_CACHE* f, int default_val);
@@ -226,7 +227,7 @@ int init_relay_log_pos(Relay_log_info* rli,const char* log,ulonglong pos,
int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset,
const char** errmsg);
void set_slave_thread_options(THD* thd);
-void set_slave_thread_default_charset(THD *thd, Relay_log_info const *rli);
+void set_slave_thread_default_charset(THD *thd, rpl_group_info *rgi);
int rotate_relay_log(Master_info* mi);
int apply_event_and_update_pos(Log_event* ev, THD* thd,
struct rpl_group_info *rgi,
diff --git a/sql/sp.cc b/sql/sp.cc
index d3d692b8251..b5b543ead0e 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -1437,6 +1437,8 @@ bool lock_db_routines(THD *thd, char *db)
uchar keybuf[MAX_KEY_LENGTH];
DBUG_ENTER("lock_db_routines");
+ DBUG_ASSERT(ok_for_lower_case_names(db));
+
/*
mysql.proc will be re-opened during deletion, so we can ignore
errors when opening the table here. The error handler is
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 92f7ac020f5..8a9e8ddc816 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -493,6 +493,7 @@ sp_name::init_qname(THD *thd)
(int) m_db.length, (m_db.length ? m_db.str : ""),
dot, ".",
(int) m_name.length, m_name.str);
+ DBUG_ASSERT(ok_for_lower_case_names(m_db.str));
}
@@ -1156,6 +1157,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
LEX *old_lex;
Item_change_list old_change_list;
String old_packet;
+ uint old_server_status;
Reprepare_observer *save_reprepare_observer= thd->m_reprepare_observer;
Object_creation_ctx *saved_creation_ctx;
Diagnostics_area *da= thd->get_stmt_da();
@@ -1289,6 +1291,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
It is probably safe to use same thd->convert_buff everywhere.
*/
old_packet.swap(thd->packet);
+ old_server_status= thd->server_status;
/*
Switch to per-instruction arena here. We can do it since we cleanup
@@ -1409,6 +1412,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
thd->spcont->pop_all_cursors(); // To avoid memory leaks after an error
/* Restore all saved */
+ thd->server_status= old_server_status;
old_packet.swap(thd->packet);
DBUG_ASSERT(thd->change_list.is_empty());
old_change_list.move_elements_to(&thd->change_list);
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index cd7ad3f8665..a0917c18aa3 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -38,6 +38,7 @@
#include "records.h" // READ_RECORD, read_record_info,
// init_read_record, end_read_record
#include "rpl_filter.h" // rpl_filter
+#include "rpl_rli.h"
#include <m_ctype.h>
#include <stdarg.h>
#include "sp_head.h"
@@ -2561,7 +2562,7 @@ bool change_password(THD *thd, const char *host, const char *user,
{
TABLE_LIST tables;
TABLE *table;
- Rpl_filter *rpl_filter= thd->rpl_filter;
+ Rpl_filter *rpl_filter;
/* Buffer should be extended when password length is extended. */
char buff[512];
ulong query_length=0;
@@ -2598,7 +2599,8 @@ bool change_password(THD *thd, const char *host, const char *user,
GRANT and REVOKE are applied the slave in/exclusion rules as they are
some kind of updates to the mysql.% tables.
*/
- if (thd->slave_thread && rpl_filter->is_on())
+ if (thd->slave_thread &&
+ (rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter)->is_on())
{
/*
The tables must be marked "updating" so that tables_ok() takes them into
@@ -5425,7 +5427,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
TABLE_LIST tables[3];
bool create_new_users=0;
char *db_name, *table_name;
- Rpl_filter *rpl_filter= thd->rpl_filter;
+ Rpl_filter *rpl_filter;
DBUG_ENTER("mysql_table_grant");
if (!initialized)
@@ -5515,7 +5517,8 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
GRANT and REVOKE are applied the slave in/exclusion rules as they are
some kind of updates to the mysql.% tables.
*/
- if (thd->slave_thread && rpl_filter->is_on())
+ if (thd->slave_thread &&
+ (rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter)->is_on())
{
/*
The tables must be marked "updating" so that tables_ok() takes them into
@@ -5702,7 +5705,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
TABLE_LIST tables[2];
bool create_new_users=0, result=0;
char *db_name, *table_name;
- Rpl_filter *rpl_filter= thd->rpl_filter;
+ Rpl_filter *rpl_filter;
DBUG_ENTER("mysql_routine_grant");
if (!initialized)
@@ -5737,7 +5740,8 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
GRANT and REVOKE are applied the slave in/exclusion rules as they are
some kind of updates to the mysql.% tables.
*/
- if (thd->slave_thread && rpl_filter->is_on())
+ if (thd->slave_thread &&
+ (rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter)->is_on())
{
/*
The tables must be marked "updating" so that tables_ok() takes them into
@@ -6173,7 +6177,7 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
char tmp_db[SAFE_NAME_LEN+1];
bool create_new_users=0;
TABLE_LIST tables[2];
- Rpl_filter *rpl_filter= thd->rpl_filter;
+ Rpl_filter *rpl_filter;
DBUG_ENTER("mysql_grant");
if (!initialized)
@@ -6222,7 +6226,8 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
GRANT and REVOKE are applied the slave in/exclusion rules as they are
some kind of updates to the mysql.% tables.
*/
- if (thd->slave_thread && rpl_filter->is_on())
+ if (thd->slave_thread &&
+ (rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter)->is_on())
{
/*
The tables must be marked "updating" so that tables_ok() takes them into
@@ -8255,7 +8260,7 @@ void get_mqh(const char *user, const char *host, USER_CONN *uc)
#define GRANT_TABLES 7
static int open_grant_tables(THD *thd, TABLE_LIST *tables)
{
- Rpl_filter *rpl_filter= thd->rpl_filter;
+ Rpl_filter *rpl_filter;
DBUG_ENTER("open_grant_tables");
if (!initialized)
@@ -8299,7 +8304,8 @@ static int open_grant_tables(THD *thd, TABLE_LIST *tables)
GRANT and REVOKE are applied the slave in/exclusion rules as they are
some kind of updates to the mysql.% tables.
*/
- if (thd->slave_thread && rpl_filter->is_on())
+ if (thd->slave_thread &&
+ (rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter)->is_on())
{
/*
The tables must be marked "updating" so that tables_ok() takes them into
@@ -10867,7 +10873,6 @@ struct MPVIO_EXT :public MYSQL_PLUGIN_VIO
uint pkt_len;
} cached_server_packet;
int packets_read, packets_written; ///< counters for send/received packets
- uint connect_errors; ///< if there were connect errors for this host
bool make_it_fail;
/** when plugin returns a failure this tells us what really happened */
enum { SUCCESS, FAILURE, RESTART } status;
@@ -11418,9 +11423,6 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
*/
DBUG_ASSERT(net->read_pos[pkt_len] == 0);
- if (mpvio->connect_errors)
- reset_host_connect_errors(thd->main_security_ctx.ip);
-
ulong client_capabilities= uint2korr(net->read_pos);
if (client_capabilities & CLIENT_PROTOCOL_41)
{
@@ -11998,8 +12000,6 @@ static int do_auth_once(THD *thd, const LEX_STRING *auth_plugin_name,
Perform the handshake, authorize the client and update thd sctx variables.
@param thd thread handle
- @param connect_errors number of previous failed connect attemps
- from this host
@param com_change_user_pkt_len size of the COM_CHANGE_USER packet
(without the first, command, byte) or 0
if it's not a COM_CHANGE_USER (that is, if
@@ -12008,8 +12008,7 @@ static int do_auth_once(THD *thd, const LEX_STRING *auth_plugin_name,
@retval 0 success, thd is updated.
@retval 1 error
*/
-bool acl_authenticate(THD *thd, uint connect_errors,
- uint com_change_user_pkt_len)
+bool acl_authenticate(THD *thd, uint com_change_user_pkt_len)
{
int res= CR_OK;
MPVIO_EXT mpvio;
@@ -12023,7 +12022,6 @@ bool acl_authenticate(THD *thd, uint connect_errors,
mpvio.write_packet= server_mpvio_write_packet;
mpvio.info= server_mpvio_info;
mpvio.thd= thd;
- mpvio.connect_errors= connect_errors;
mpvio.status= MPVIO_EXT::FAILURE;
mpvio.make_it_fail= false;
mpvio.auth_info.host_or_ip= thd->security_ctx->host_or_ip;
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index df523fae1ca..1aeb123153e 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -202,7 +202,7 @@ my_bool acl_reload(THD *thd);
void acl_free(bool end=0);
ulong acl_get(const char *host, const char *ip,
const char *user, const char *db, my_bool db_is_pattern);
-bool acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len);
+bool acl_authenticate(THD *thd, uint com_change_user_pkt_len);
bool acl_getroot(Security_context *sctx, char *user, char *host,
char *ip, char *db);
bool acl_check_host(const char *host, const char *ip);
diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc
index 518ebdc511d..ee70914d331 100644
--- a/sql/sql_admin.cc
+++ b/sql/sql_admin.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2010, 2013, Oracle and/or its affiliates.
- Copyright (c) 2012, 2013, Monty Program Ab.
+/* Copyright (c) 2010, 2014, Oracle and/or its affiliates.
+ Copyright (c) 2012, 2014, Monty Program 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
@@ -55,7 +55,7 @@ static bool admin_recreate_table(THD *thd, TABLE_LIST *table_list)
DEBUG_SYNC(thd, "ha_admin_try_alter");
tmp_disable_binlog(thd); // binlogging is done by caller if wanted
result_code= (open_temporary_tables(thd, table_list) ||
- mysql_recreate_table(thd, table_list));
+ mysql_recreate_table(thd, table_list, false));
reenable_binlog(thd);
/*
mysql_recreate_table() can push OK or ERROR.
@@ -719,7 +719,9 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
if (result_code == HA_ADMIN_OK)
{
DBUG_PRINT("admin", ("calling operator_func '%s'", operator_name));
+ THD_STAGE_INFO(thd, stage_executing);
result_code = (table->table->file->*operator_func)(thd, check_opt);
+ THD_STAGE_INFO(thd, stage_sending_data);
DBUG_PRINT("admin", ("operator_func returned: %d", result_code));
}
@@ -862,7 +864,7 @@ send_result_message:
}
if (protocol->write())
goto err;
-
+ THD_STAGE_INFO(thd, stage_recreating_table);
DBUG_PRINT("info", ("HA_ADMIN_TRY_ALTER, trying analyze..."));
TABLE_LIST *save_next_local= table->next_local,
*save_next_global= table->next_global;
@@ -1080,6 +1082,7 @@ bool mysql_assign_to_keycache(THD* thd, TABLE_LIST* tables,
KEY_CACHE *key_cache;
DBUG_ENTER("mysql_assign_to_keycache");
+ THD_STAGE_INFO(thd, stage_finding_key_cache);
check_opt.init();
mysql_mutex_lock(&LOCK_global_system_variables);
if (!(key_cache= get_key_cache(key_cache_name)))
@@ -1199,8 +1202,7 @@ bool Sql_cmd_optimize_table::execute(THD *thd)
goto error; /* purecov: inspected */
thd->enable_slow_log= opt_log_slow_admin_statements;
res= (specialflag & SPECIAL_NO_NEW_FUNC) ?
-
- mysql_recreate_table(thd, first_table) :
+ mysql_recreate_table(thd, first_table, true) :
mysql_admin_table(thd, first_table, &m_lex->check_opt,
"optimize", TL_WRITE, 1, 0, 0, 0,
&handler::ha_optimize, 0);
diff --git a/sql/sql_alter.h b/sql/sql_alter.h
index f0c0a873a5c..526442e83e2 100644
--- a/sql/sql_alter.h
+++ b/sql/sql_alter.h
@@ -1,4 +1,5 @@
-/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2010, 2014, Oracle and/or its affiliates.
+ Copyright (c) 2013, 2014, Monty Program 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
@@ -73,6 +74,7 @@ public:
static const uint ALTER_CONVERT = 1L << 10;
// Set for FORCE
+ // Set for ENGINE(same engine)
// Set by mysql_recreate_table()
static const uint ALTER_RECREATE = 1L << 11;
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 2f304b21706..7304dd7c128 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -887,6 +887,8 @@ void close_thread_tables(THD *thd)
TABLE *table;
DBUG_ENTER("close_thread_tables");
+ THD_STAGE_INFO(thd, stage_closing_tables);
+
#ifdef EXTRA_DEBUG
DBUG_PRINT("tcache", ("open tables:"));
for (table= thd->open_tables; table; table= table->next)
@@ -4604,6 +4606,8 @@ restart:
#endif
err:
+ THD_STAGE_INFO(thd, stage_after_opening_tables);
+
#ifdef WITH_WSREP
if (WSREP(thd))
thd_proc_info(thd, "exit open_tables()");
@@ -5066,6 +5070,8 @@ end:
close_thread_tables(thd);
}
+ THD_STAGE_INFO(thd, stage_after_opening_tables);
+
#ifdef WITH_WSREP
if (WSREP(thd))
thd_proc_info(thd, "End opening table");
@@ -8401,6 +8407,75 @@ void wrap_ident(THD *thd, Item **conds)
thd->restore_active_arena(arena, &backup);
}
+/**
+ Prepare ON expression
+
+ @param thd Thread handle
+ @param table Pointer to table list
+ @param is_update Update flag
+
+ @retval TRUE error.
+ @retval FALSE OK.
+*/
+
+bool setup_on_expr(THD *thd, TABLE_LIST *table, bool is_update)
+{
+ uchar buff[STACK_BUFF_ALLOC]; // Max argument in function
+ if (check_stack_overrun(thd, STACK_MIN_SIZE, buff))
+ return TRUE; // Fatal error flag is set!
+ for(; table; table= table->next_local)
+ {
+ TABLE_LIST *embedded; /* The table at the current level of nesting. */
+ TABLE_LIST *embedding= table; /* The parent nested table reference. */
+ do
+ {
+ embedded= embedding;
+ DBUG_PRINT("XXX", ("check: %s", table->alias));
+ if (embedded->on_expr)
+ {
+ thd->where="on clause";
+ embedded->on_expr->mark_as_condition_AND_part(embedded);
+ if ((!embedded->on_expr->fixed &&
+ embedded->on_expr->fix_fields(thd, &embedded->on_expr)) ||
+ embedded->on_expr->check_cols(1))
+ return TRUE;
+ }
+ /*
+ If it's a semi-join nest, fix its "left expression", as it is used by
+ the SJ-Materialization
+ */
+ if (embedded->sj_subq_pred)
+ {
+ Item **left_expr= &embedded->sj_subq_pred->left_expr;
+ if (!(*left_expr)->fixed && (*left_expr)->fix_fields(thd, left_expr))
+ return TRUE;
+ }
+
+ embedding= embedded->embedding;
+ }
+ while (embedding &&
+ embedding->nested_join->join_list.head() == embedded);
+
+ if (table->is_merged_derived())
+ {
+ SELECT_LEX *select_lex= table->get_single_select();
+ setup_on_expr(thd, select_lex->get_table_list(), is_update);
+ }
+
+ /* process CHECK OPTION */
+ if (is_update)
+ {
+ TABLE_LIST *view= table->top_table();
+ if (view->effective_with_check)
+ {
+ if (view->prepare_check_option(thd))
+ return TRUE;
+ thd->change_item_tree(&table->check_option, view->check_option);
+ }
+ }
+ }
+ return FALSE;
+}
/*
Fix all conditions and outer join expressions.
@@ -8425,7 +8500,6 @@ int setup_conds(THD *thd, TABLE_LIST *tables, List<TABLE_LIST> &leaves,
{
SELECT_LEX *select_lex= thd->lex->current_select;
TABLE_LIST *table= NULL; // For HP compilers
- List_iterator<TABLE_LIST> ti(leaves);
/*
it_is_update set to TRUE when tables of primary SELECT_LEX (SELECT_LEX
which belong to LEX, i.e. most up SELECT) will be updated by
@@ -8484,51 +8558,8 @@ int setup_conds(THD *thd, TABLE_LIST *tables, List<TABLE_LIST> &leaves,
Apply fix_fields() to all ON clauses at all levels of nesting,
including the ones inside view definitions.
*/
- while ((table= ti++))
- {
- TABLE_LIST *embedded; /* The table at the current level of nesting. */
- TABLE_LIST *embedding= table; /* The parent nested table reference. */
- do
- {
- embedded= embedding;
- if (embedded->on_expr)
- {
- /* Make a join an a expression */
- thd->where="on clause";
- embedded->on_expr->mark_as_condition_AND_part(embedded);
- if ((!embedded->on_expr->fixed &&
- embedded->on_expr->fix_fields(thd, &embedded->on_expr)) ||
- embedded->on_expr->check_cols(1))
- goto err_no_arena;
- }
- /*
- If it's a semi-join nest, fix its "left expression", as it is used by
- the SJ-Materialization
- */
- if (embedded->sj_subq_pred)
- {
- Item **left_expr= &embedded->sj_subq_pred->left_expr;
- if (!(*left_expr)->fixed && (*left_expr)->fix_fields(thd, left_expr))
- goto err_no_arena;
- }
-
- embedding= embedded->embedding;
- }
- while (embedding &&
- embedding->nested_join->join_list.head() == embedded);
-
- /* process CHECK OPTION */
- if (it_is_update)
- {
- TABLE_LIST *view= table->top_table();
- if (view->effective_with_check)
- {
- if (view->prepare_check_option(thd))
- goto err_no_arena;
- thd->change_item_tree(&table->check_option, view->check_option);
- }
- }
- }
+ if (setup_on_expr(thd, tables, it_is_update))
+ goto err_no_arena;
if (!thd->stmt_arena->is_conventional())
{
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index c6c5418e0cf..cf68ba36997 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -2306,6 +2306,8 @@ void Query_cache::invalidate(THD *thd, char *db)
if (is_disabled())
DBUG_VOID_RETURN;
+ DBUG_ASSERT(ok_for_lower_case_names(db));
+
bool restart= FALSE;
/*
Lock the query cache and queue all invalidation attempts to avoid
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 6a9c5dacf5a..198a67ac712 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1144,7 +1144,6 @@ THD::THD()
connection_name.length= 0;
bzero(&variables, sizeof(variables));
- one_shot_set= 0;
file_id = 0;
query_id= 0;
query_name_consts= 0;
@@ -1450,7 +1449,6 @@ Sql_condition* THD::raise_condition(uint sql_errno,
got_warning= 1;
break;
case Sql_condition::WARN_LEVEL_ERROR:
- mysql_audit_general(this, MYSQL_AUDIT_GENERAL_ERROR, sql_errno, msg);
break;
default:
DBUG_ASSERT(FALSE);
@@ -1461,6 +1459,8 @@ Sql_condition* THD::raise_condition(uint sql_errno,
if (level == Sql_condition::WARN_LEVEL_ERROR)
{
+ mysql_audit_general(this, MYSQL_AUDIT_GENERAL_ERROR, sql_errno, msg);
+
is_slave_error= 1; // needed to catch query errors during replication
if (!da->is_error())
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 4e1caca581a..b64006d7b71 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -84,6 +84,8 @@ class Parser_state;
class Rows_log_event;
class Sroutine_hash_entry;
class user_var_entry;
+class rpl_io_thread_info;
+class rpl_sql_thread_info;
enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY, RNEXT_SAME };
enum enum_duplicates { DUP_ERROR, DUP_REPLACE, DUP_UPDATE };
@@ -528,6 +530,7 @@ typedef struct system_variables
ulonglong join_buff_size;
ulonglong sortbuff_size;
ulonglong group_concat_max_len;
+ ulonglong default_regex_flags;
ha_rows select_limit;
ha_rows max_join_size;
ha_rows expensive_subquery_limit;
@@ -1826,8 +1829,10 @@ public:
/* Slave applier execution context */
rpl_group_info* rgi_slave;
- /* Used to SLAVE SQL thread */
- Rpl_filter* rpl_filter;
+ union {
+ rpl_io_thread_info *rpl_io_info;
+ rpl_sql_thread_info *rpl_sql_info;
+ } system_thread_info;
void reset_for_next_command();
/*
@@ -2604,7 +2609,7 @@ public:
char default_master_connection_buff[MAX_CONNECTION_NAME+1];
uint8 password; /* 0, 1 or 2 */
uint8 failed_com_change_user;
- bool slave_thread, one_shot_set;
+ bool slave_thread;
bool extra_port; /* If extra connection */
bool no_errors;
@@ -3121,8 +3126,11 @@ public:
Clear the current error, if any.
We do not clear is_fatal_error or is_fatal_sub_stmt_error since we
assume this is never called if the fatal error is set.
+
@todo: To silence an error, one should use Internal_error_handler
- mechanism. In future this function will be removed.
+ mechanism. Issuing an error that can be possibly later "cleared" is not
+ compatible with other installed error handlers and audit plugins.
+ In future this function will be removed.
*/
inline void clear_error()
{
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
index 49d9ae5a76f..bea331fe8ee 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -1070,7 +1070,7 @@ static int check_connection(THD *thd)
return 1; /* The error is set by alloc(). */
}
- auth_rc= acl_authenticate(thd, connect_errors, 0);
+ auth_rc= acl_authenticate(thd, 0);
if (auth_rc == 0 && connect_errors != 0)
{
/*
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 13cbcdd9f08..76288e94c75 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -2468,7 +2468,7 @@ struct LEX: public Query_tables_list
uint16 create_view_algorithm;
uint8 create_view_check;
uint8 context_analysis_only;
- bool drop_temporary, local_file, one_shot_set;
+ bool drop_temporary, local_file;
bool check_exists;
bool autocommit;
bool verbose, no_write_to_binlog;
diff --git a/sql/sql_locale.cc b/sql/sql_locale.cc
index b2b112ed4ba..c7d21ffd424 100644
--- a/sql/sql_locale.cc
+++ b/sql/sql_locale.cc
@@ -3247,6 +3247,75 @@ MY_LOCALE my_locale_el_GR
);
/***** LOCALE END el_GR *****/
+
+/***** LOCALE BEGIN rm_CH: Romansh - Switzerland *****/
+static const char *my_locale_month_names_rm_CH[13]=
+{
+ "schaner", "favrer", "mars", "avrigl", "matg", "zercladur",
+ "fanadur", "avust", "settember", "october", "november", "december", NullS
+};
+
+static const char *my_locale_ab_month_names_rm_CH[13]=
+{
+ "schan", "favr", "mars", "avr", "matg", "zercl",
+ "fan", "avust", "sett", "oct", "nov", "dec", NullS
+};
+
+static const char *my_locale_day_names_rm_CH[8]=
+{
+ "glindesdi", "mardi", "mesemna", "gievgia",
+ "venderdi", "sonda", "dumengia", NullS
+};
+
+static const char *my_locale_ab_day_names_rm_CH[8]=
+{
+ "gli", "ma", "me", "gie", "ve", "so", "du", NullS
+};
+
+static TYPELIB my_locale_typelib_month_names_rm_CH=
+{
+ array_elements(my_locale_month_names_rm_CH) - 1,
+ "", my_locale_month_names_rm_CH, NULL
+};
+
+static TYPELIB my_locale_typelib_ab_month_names_rm_CH=
+{
+ array_elements(my_locale_ab_month_names_rm_CH) - 1,
+ "", my_locale_ab_month_names_rm_CH, NULL
+};
+
+static TYPELIB my_locale_typelib_day_names_rm_CH=
+{
+ array_elements(my_locale_day_names_rm_CH) - 1,
+ "", my_locale_day_names_rm_CH, NULL
+};
+
+static TYPELIB my_locale_typelib_ab_day_names_rm_CH=
+{
+ array_elements(my_locale_ab_day_names_rm_CH) - 1,
+ "", my_locale_ab_day_names_rm_CH, NULL
+};
+
+MY_LOCALE my_locale_rm_CH
+(
+ 110,
+ "rm_CH",
+ "Romansh - Switzerland",
+ FALSE,
+ &my_locale_typelib_month_names_rm_CH,
+ &my_locale_typelib_ab_month_names_rm_CH,
+ &my_locale_typelib_day_names_rm_CH,
+ &my_locale_typelib_ab_day_names_rm_CH,
+ 9, /* max mon name length */
+ 9, /* max day name length */
+ ',', /* decimal point rm_CH */
+ '\'', /* thousands_sep rm_CH */
+ "\x03\x03", /* grouping rm_CH */
+ &global_errmsgs[en_US]
+);
+/***** LOCALE END rm_CH *****/
+
+
/*
The list of all locales.
Note, locales must be ordered according to their
@@ -3365,6 +3434,7 @@ MY_LOCALE *my_locales[]=
&my_locale_sv_FI,
&my_locale_zh_HK,
&my_locale_el_GR,
+ &my_locale_rm_CH,
NULL
};
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 08e8b535f76..039e79c2acf 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -177,8 +177,9 @@ const char *xa_state_names[]={
*/
inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables)
{
- return thd->rpl_filter->is_on() && tables && !thd->spcont &&
- !thd->rpl_filter->tables_ok(thd->db, tables);
+ Rpl_filter *rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter;
+ return rpl_filter->is_on() && tables && !thd->spcont &&
+ !rpl_filter->tables_ok(thd->db, tables);
}
#endif
@@ -1395,7 +1396,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
auth_rc= 1;
}
else
- auth_rc= acl_authenticate(thd, 0, packet_length);
+ auth_rc= acl_authenticate(thd, packet_length);
mysql_audit_notify_connection_change_user(thd);
if (auth_rc)
@@ -2238,23 +2239,6 @@ bool alloc_query(THD *thd, const char *packet, uint packet_length)
return FALSE;
}
-static void reset_one_shot_variables(THD *thd)
-{
- thd->variables.character_set_client=
- global_system_variables.character_set_client;
- thd->variables.collation_connection=
- global_system_variables.collation_connection;
- thd->variables.collation_database=
- global_system_variables.collation_database;
- thd->variables.collation_server=
- global_system_variables.collation_server;
- thd->update_charset();
- thd->variables.time_zone=
- global_system_variables.time_zone;
- thd->variables.lc_time_names= &my_locale_en_US;
- thd->one_shot_set= 0;
-}
-
bool sp_process_definer(THD *thd)
{
@@ -2448,7 +2432,7 @@ mysql_execute_command(THD *thd)
/* have table map for update for multi-update statement (BUG#37051) */
bool have_table_map_for_update= FALSE;
/* */
- Rpl_filter *rpl_filter= thd->rpl_filter;
+ Rpl_filter *rpl_filter;
#endif
DBUG_ENTER("mysql_execute_command");
@@ -2562,9 +2546,6 @@ mysql_execute_command(THD *thd)
{
/* we warn the slave SQL thread */
my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
- if (thd->one_shot_set)
- reset_one_shot_variables(thd);
- DBUG_RETURN(0);
}
for (table=all_tables; table; table=table->next_global)
@@ -2592,23 +2573,6 @@ mysql_execute_command(THD *thd)
{
/* we warn the slave SQL thread */
my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
- if (thd->one_shot_set)
- {
- /*
- It's ok to check thd->one_shot_set here:
-
- The charsets in a MySQL 5.0 slave can change by both a binlogged
- SET ONE_SHOT statement and the event-internal charset setting,
- and these two ways to change charsets do not seems to work
- together.
-
- At least there seems to be problems in the rli cache for
- charsets if we are using ONE_SHOT. Note that this is normally no
- problem because either the >= 5.0 slave reads a 4.1 binlog (with
- ONE_SHOT) *or* or 5.0 binlog (without ONE_SHOT) but never both."
- */
- reset_one_shot_variables(thd);
- }
DBUG_RETURN(0);
}
/*
@@ -4114,11 +4078,6 @@ end_with_restore_list:
goto error;
if (!(res= sql_set_variables(thd, lex_var_list)))
{
- /*
- If the previous command was a SET ONE_SHOT, we don't want to forget
- about the ONE_SHOT property of that SET. So we use a |= instead of = .
- */
- thd->one_shot_set|= lex->one_shot_set;
my_ok(thd);
}
else
@@ -4218,12 +4177,15 @@ end_with_restore_list:
above was not called. So we have to check rules again here.
*/
#ifdef HAVE_REPLICATION
- if (thd->slave_thread &&
- (!rpl_filter->db_ok(lex->name.str) ||
- !rpl_filter->db_ok_with_wild_table(lex->name.str)))
+ if (thd->slave_thread)
{
- my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
- break;
+ rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter;
+ if (!rpl_filter->db_ok(lex->name.str) ||
+ !rpl_filter->db_ok_with_wild_table(lex->name.str))
+ {
+ my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
+ break;
+ }
}
#endif
if (check_access(thd, CREATE_ACL, lex->name.str, NULL, NULL, 1, 0))
@@ -4247,12 +4209,15 @@ end_with_restore_list:
above was not called. So we have to check rules again here.
*/
#ifdef HAVE_REPLICATION
- if (thd->slave_thread &&
- (!rpl_filter->db_ok(lex->name.str) ||
- !rpl_filter->db_ok_with_wild_table(lex->name.str)))
+ if (thd->slave_thread)
{
- my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
- break;
+ rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter;
+ if (!rpl_filter->db_ok(lex->name.str) ||
+ !rpl_filter->db_ok_with_wild_table(lex->name.str))
+ {
+ my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
+ break;
+ }
}
#endif
if (check_access(thd, DROP_ACL, lex->name.str, NULL, NULL, 1, 0))
@@ -4265,13 +4230,16 @@ end_with_restore_list:
{
LEX_STRING *db= & lex->name;
#ifdef HAVE_REPLICATION
- if (thd->slave_thread &&
- (!rpl_filter->db_ok(db->str) ||
- !rpl_filter->db_ok_with_wild_table(db->str)))
+ if (thd->slave_thread)
{
- res= 1;
- my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
- break;
+ rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter;
+ if (!rpl_filter->db_ok(db->str) ||
+ !rpl_filter->db_ok_with_wild_table(db->str))
+ {
+ res= 1;
+ my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
+ break;
+ }
}
#endif
if (check_db_name(db))
@@ -4309,12 +4277,15 @@ end_with_restore_list:
above was not called. So we have to check rules again here.
*/
#ifdef HAVE_REPLICATION
- if (thd->slave_thread &&
- (!rpl_filter->db_ok(db->str) ||
- !rpl_filter->db_ok_with_wild_table(db->str)))
+ if (thd->slave_thread)
{
- my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
- break;
+ rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter;
+ if (!rpl_filter->db_ok(db->str) ||
+ !rpl_filter->db_ok_with_wild_table(db->str))
+ {
+ my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
+ break;
+ }
}
#endif
if (check_access(thd, ALTER_ACL, db->str, NULL, NULL, 1, 0))
@@ -5536,19 +5507,6 @@ create_sp_error:
THD_STAGE_INFO(thd, stage_query_end);
thd->update_stats();
- /*
- Binlog-related cleanup:
- Reset system variables temporarily modified by SET ONE SHOT.
-
- Exception: If this is a SET, do nothing. This is to allow
- mysqlbinlog to print many SET commands (in this case we want the
- charset temp setting to live until the real query). This is also
- needed so that SET CHARACTER_SET_CLIENT... does not cancel itself
- immediately.
- */
- if (thd->one_shot_set && lex->sql_command != SQLCOM_SET_OPTION)
- reset_one_shot_variables(thd);
-
goto finish;
error:
@@ -5593,7 +5551,6 @@ finish:
}
/* Free tables */
- THD_STAGE_INFO(thd, stage_closing_tables);
close_thread_tables(thd);
#ifdef WITH_WSREP
thd->wsrep_consistency_check= NO_CONSISTENCY_CHECK;
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
index df76c9f6417..1348ebec3c8 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -3213,15 +3213,21 @@ static void plugin_vars_free_values(sys_var *vars)
static SHOW_TYPE pluginvar_show_type(st_mysql_sys_var *plugin_var)
{
- switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) {
+ switch (plugin_var->flags & (PLUGIN_VAR_TYPEMASK | PLUGIN_VAR_UNSIGNED)) {
case PLUGIN_VAR_BOOL:
return SHOW_MY_BOOL;
case PLUGIN_VAR_INT:
- return SHOW_INT;
+ return SHOW_SINT;
+ case PLUGIN_VAR_INT | PLUGIN_VAR_UNSIGNED:
+ return SHOW_UINT;
case PLUGIN_VAR_LONG:
- return SHOW_LONG;
+ return SHOW_SLONG;
+ case PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED:
+ return SHOW_ULONG;
case PLUGIN_VAR_LONGLONG:
- return SHOW_LONGLONG;
+ return SHOW_SLONGLONG;
+ case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED:
+ return SHOW_ULONGLONG;
case PLUGIN_VAR_STR:
return SHOW_CHAR_PTR;
case PLUGIN_VAR_ENUM:
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 240fc953f1d..b97cedb5b05 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -549,6 +549,7 @@ fix_inner_refs(THD *thd, List<Item> &all_fields, SELECT_LEX *select,
static
void remove_redundant_subquery_clauses(st_select_lex *subq_select_lex)
{
+ DBUG_ENTER("remove_redundant_subquery_clauses");
Item_subselect *subq_predicate= subq_select_lex->master_unit()->item;
/*
The removal should happen for IN, ALL, ANY and EXISTS subqueries,
@@ -558,7 +559,7 @@ void remove_redundant_subquery_clauses(st_select_lex *subq_select_lex)
b) SELECT a, (<single row subquery) FROM t1
*/
if (subq_predicate->substype() == Item_subselect::SINGLEROW_SUBS)
- return;
+ DBUG_VOID_RETURN;
/* A subquery that is not single row should be one of IN/ALL/ANY/EXISTS. */
DBUG_ASSERT (subq_predicate->substype() == Item_subselect::EXISTS_SUBS ||
@@ -568,6 +569,7 @@ void remove_redundant_subquery_clauses(st_select_lex *subq_select_lex)
{
subq_select_lex->join->select_distinct= false;
subq_select_lex->options&= ~SELECT_DISTINCT;
+ DBUG_PRINT("info", ("DISTINCT removed"));
}
/*
@@ -577,8 +579,13 @@ void remove_redundant_subquery_clauses(st_select_lex *subq_select_lex)
if (subq_select_lex->group_list.elements &&
!subq_select_lex->with_sum_func && !subq_select_lex->join->having)
{
+ for (ORDER *ord= subq_select_lex->group_list.first; ord; ord= ord->next)
+ {
+ (*ord->item)->walk(&Item::eliminate_subselect_processor, FALSE, NULL);
+ }
subq_select_lex->join->group_list= NULL;
subq_select_lex->group_list.empty();
+ DBUG_PRINT("info", ("GROUP BY removed"));
}
/*
@@ -593,6 +600,7 @@ void remove_redundant_subquery_clauses(st_select_lex *subq_select_lex)
subq_select_lex->group_list.empty();
}
*/
+ DBUG_VOID_RETURN;
}
@@ -700,7 +708,9 @@ JOIN::prepare(Item ***rref_pointer_array,
if (!(select_options & OPTION_SETUP_TABLES_DONE) &&
setup_tables_and_check_access(thd, &select_lex->context, join_list,
tables_list, select_lex->leaf_tables,
- FALSE, SELECT_ACL, SELECT_ACL, FALSE))
+ FALSE, SELECT_ACL, SELECT_ACL,
+ (thd->lex->sql_command ==
+ SQLCOM_UPDATE_MULTI)))
DBUG_RETURN(-1);
/*
@@ -5274,7 +5284,8 @@ static bool sort_and_filter_keyuse(THD *thd, DYNAMIC_ARRAY *keyuse,
{
if (!use->is_for_hash_join())
{
- if (!use->used_tables && use->optimize != KEY_OPTIMIZE_REF_OR_NULL)
+ if (!(use->used_tables & ~OUTER_REF_TABLE_BIT) &&
+ use->optimize != KEY_OPTIMIZE_REF_OR_NULL)
use->table->const_key_parts[use->key]|= use->keypart_map;
if (use->keypart != FT_KEYPART)
{
@@ -5557,7 +5568,20 @@ void set_position(JOIN *join,uint idx,JOIN_TAB *table,KEYUSE *key)
}
-/* Estimate of the number matching candidates in the joined table */
+/*
+ Estimate how many records we will get if we read just this table and apply
+ a part of WHERE that can be checked for it.
+
+ @detail
+ Estimate how many records we will get if we
+ - read the given table with its "independent" access method (either quick
+ select or full table/index scan),
+ - apply the part of WHERE that refers only to this table.
+
+ @seealso
+ table_cond_selectivity() produces selectivity of condition that is checked
+ after joining rows from this table to rows from preceding tables.
+*/
inline
double matching_candidates_in_table(JOIN_TAB *s, bool with_found_constraint,
@@ -7236,14 +7260,25 @@ double table_multi_eq_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s,
/**
@brief
- Get the selectivity of conditions when joining a table
+ Get the selectivity of conditions when joining a table
@param join The optimized join
@param s The table to be joined for evaluation
@param rem_tables The bitmap of tables to be joined later
+ @detail
+ Get selectivity of conditions that can be applied when joining this table
+ with previous tables.
+
+ For quick selects and full table scans, selectivity of COND(this_table)
+ is accounted for in matching_candidates_in_table(). Here, we only count
+ selectivity of COND(this_table, previous_tables).
+
+ For other access methods, we need to calculate selectivity of the whole
+ condition, "COND(this_table) AND COND(this_table, previous_tables)".
+
@retval
- selectivity of the conditions imposed on the rows of s
+ selectivity of the conditions imposed on the rows of s
*/
static
@@ -7255,26 +7290,84 @@ double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s,
TABLE *table= s->table;
MY_BITMAP *read_set= table->read_set;
double sel= s->table->cond_selectivity;
- double table_records= table->stat_records();
POSITION *pos= &join->positions[idx];
uint keyparts= 0;
uint found_part_ref_or_null= 0;
- /* Discount the selectivity of the access method used to join table s */
- if (s->quick && s->quick->index != MAX_KEY)
+ if (pos->key != 0)
{
- if (pos->key == 0 && table_records > 0)
- {
- sel/= table->quick_rows[s->quick->index]/table_records;
- }
- }
- else if (pos->key != 0)
- {
- /* A ref/ access or hash join is used to join table */
+ /*
+ A ref access or hash join is used for this table. ref access is created
+ from
+
+ tbl.keypart1=expr1 AND tbl.keypart2=expr2 AND ...
+
+ and it will only return rows for which this condition is satisified.
+ Suppose, certain expr{i} is a constant. Since ref access only returns
+ rows that satisfy
+
+ tbl.keypart{i}=const (*)
+
+ then selectivity of this equality should not be counted in return value
+ of this function. This function uses the value of
+
+ table->cond_selectivity=selectivity(COND(tbl)) (**)
+
+ as a starting point. This value includes selectivity of equality (*). We
+ should somehow discount it.
+
+ Looking at calculate_cond_selectivity_for_table(), one can see that that
+ the value is not necessarily a direct multiplicand in
+ table->cond_selectivity
+
+ There are three possible ways to discount
+ 1. There is a potential range access on t.keypart{i}=const.
+ (an important special case: the used ref access has a const prefix for
+ which a range estimate is available)
+
+ 2. The field has a histogram. field[x]->cond_selectivity has the data.
+
+ 3. Use index stats on this index:
+ rec_per_key[key_part+1]/rec_per_key[key_part]
+
+ (TODO: more details about the "t.key=othertable.col" case)
+ */
KEYUSE *keyuse= pos->key;
KEYUSE *prev_ref_keyuse= keyuse;
uint key= keyuse->key;
- do
+
+ /*
+ Check if we have a prefix of key=const that matches a quick select.
+ */
+ if (!is_hash_join_key_no(key))
+ {
+ table_map quick_key_map= (table_map(1) << table->quick_key_parts[key]) - 1;
+ if (table->quick_rows[key] &&
+ !(quick_key_map & ~table->const_key_parts[key]))
+ {
+ /*
+ Ok, there is an equality for each of the key parts used by the
+ quick select. This means, quick select's estimate can be reused to
+ discount the selectivity of a prefix of a ref access.
+ */
+ for (; quick_key_map & 1 ; quick_key_map>>= 1)
+ {
+ while (keyuse->table == table && keyuse->key == key &&
+ keyuse->keypart == keyparts)
+ {
+ keyuse++;
+ }
+ keyparts++;
+ }
+ sel /= (double)table->quick_rows[key] / (double) table->stat_records();
+ }
+ }
+
+ /*
+ Go through the "keypart{N}=..." equalities and find those that were
+ already taken into account in table->cond_selectivity.
+ */
+ while (keyuse->table == table && keyuse->key == key)
{
if (!(keyuse->used_tables & (rem_tables | table->map)))
{
@@ -7288,22 +7381,35 @@ double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s,
else
{
if (keyparts == keyuse->keypart &&
- !(~(keyuse->val->used_tables()) & pos->ref_depend_map) &&
+ !((keyuse->val->used_tables()) & ~pos->ref_depend_map) &&
!(found_part_ref_or_null & keyuse->optimize))
{
+ /* Found a KEYUSE object that will be used by ref access */
keyparts++;
found_part_ref_or_null|= keyuse->optimize & ~KEY_OPTIMIZE_EQ;
}
}
+
if (keyparts > keyuse->keypart)
{
+ /* Ok this is the keyuse that will be used for ref access */
uint fldno;
if (is_hash_join_key_no(key))
fldno= keyuse->keypart;
else
fldno= table->key_info[key].key_part[keyparts-1].fieldnr - 1;
if (keyuse->val->const_item())
- sel*= table->field[fldno]->cond_selectivity;
+ {
+ sel /= table->field[fldno]->cond_selectivity;
+ /*
+ TODO: we could do better here:
+ 1. cond_selectivity might be =1 (the default) because quick
+ select on some index prevented us from analyzing
+ histogram for this column.
+ 2. we could get an estimate through this?
+ rec_per_key[key_part-1] / rec_per_key[key_part]
+ */
+ }
if (keyparts > 1)
{
ref_keyuse_steps[keyparts-2]= keyuse - prev_ref_keyuse;
@@ -7313,13 +7419,18 @@ double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s,
}
}
keyuse++;
- } while (keyuse->table == table && keyuse->key == key);
+ }
}
else
{
+ /*
+ The table is accessed with full table scan, or quick select.
+ Selectivity of COND(table) is already accounted for in
+ matching_candidates_in_table().
+ */
sel= 1;
}
-
+
/*
If the field f from the table is equal to a field from one the
earlier joined tables then the selectivity of the range conditions
@@ -14267,7 +14378,7 @@ optimize_cond(JOIN *join, COND *conds,
conds= remove_eq_conds(thd, conds, cond_value);
if (conds && conds->type() == Item::COND_ITEM &&
((Item_cond*) conds)->functype() == Item_func::COND_AND_FUNC)
- join->cond_equal= &((Item_cond_and*) conds)->cond_equal;
+ *cond_equal= &((Item_cond_and*) conds)->cond_equal;
DBUG_EXECUTE("info",print_where(conds,"after remove", QT_ORDINARY););
}
DBUG_RETURN(conds);
@@ -14884,7 +14995,7 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
static bool
test_if_equality_guarantees_uniqueness(Item *l, Item *r)
{
- return r->const_item() &&
+ return (r->const_item() || !(r->used_tables() & ~OUTER_REF_TABLE_BIT)) &&
item_cmp_type(l->cmp_type(), r->cmp_type()) == l->cmp_type() &&
(l->cmp_type() != STRING_RESULT ||
l->collation.collation == r->collation.collation);
@@ -24498,7 +24609,7 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table,
double fanout= 1;
ha_rows table_records= table->stat_records();
bool group= join && join->group && order == join->group_list;
- ha_rows ref_key_quick_rows= HA_POS_ERROR;
+ ha_rows refkey_rows_estimate= table->quick_condition_rows;
const bool has_limit= (select_limit_arg != HA_POS_ERROR);
/*
@@ -24524,10 +24635,6 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table,
else
keys= usable_keys;
- if (ref_key >= 0 && ref_key != MAX_KEY &&
- table->covering_keys.is_set(ref_key))
- ref_key_quick_rows= table->quick_rows[ref_key];
-
if (join)
{
uint tablenr= tab - join->join_tab;
@@ -24538,6 +24645,22 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table,
else
read_time= table->file->scan_time();
+ /*
+ Calculate the selectivity of the ref_key for REF_ACCESS. For
+ RANGE_ACCESS we use table->quick_condition_rows.
+ */
+ if (ref_key >= 0 && tab->type == JT_REF)
+ {
+ if (table->quick_keys.is_set(ref_key))
+ refkey_rows_estimate= table->quick_rows[ref_key];
+ else
+ {
+ const KEY *ref_keyinfo= table->key_info + ref_key;
+ refkey_rows_estimate= ref_keyinfo->rec_per_key[tab->ref.key_parts - 1];
+ }
+ set_if_bigger(refkey_rows_estimate, 1);
+ }
+
for (nr=0; nr < table->s->keys ; nr++)
{
int direction;
@@ -24654,17 +24777,17 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table,
with ref_key. Thus, to select first N records we have to scan
N/selectivity(ref_key) index entries.
selectivity(ref_key) = #scanned_records/#table_records =
- table->quick_condition_rows/table_records.
+ refkey_rows_estimate/table_records.
In any case we can't select more than #table_records.
- N/(table->quick_condition_rows/table_records) > table_records
- <=> N > table->quick_condition_rows.
- */
- if (select_limit > table->quick_condition_rows)
+ N/(refkey_rows_estimate/table_records) > table_records
+ <=> N > refkey_rows_estimate.
+ */
+ if (select_limit > refkey_rows_estimate)
select_limit= table_records;
else
select_limit= (ha_rows) (select_limit *
(double) table_records /
- table->quick_condition_rows);
+ refkey_rows_estimate);
rec_per_key= keyinfo->actual_rec_per_key(keyinfo->user_defined_key_parts-1);
set_if_bigger(rec_per_key, 1);
/*
@@ -24684,8 +24807,12 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table,
index_scan_time < read_time)
{
ha_rows quick_records= table_records;
+ ha_rows refkey_select_limit= (ref_key >= 0 &&
+ table->covering_keys.is_set(ref_key)) ?
+ refkey_rows_estimate :
+ HA_POS_ERROR;
if ((is_best_covering && !is_covering) ||
- (is_covering && ref_key_quick_rows < select_limit))
+ (is_covering && refkey_select_limit < select_limit))
continue;
if (table->quick_keys.is_set(nr))
quick_records= table->quick_rows[nr];
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 4f2fccd01b1..205697e4466 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -945,9 +945,12 @@ public:
is_handled= TRUE;
break;
+ case ER_BAD_FIELD_ERROR:
+ case ER_SP_DOES_NOT_EXIST:
case ER_NO_SUCH_TABLE:
case ER_NO_SUCH_TABLE_IN_ENGINE:
- /* Established behavior: warn if underlying tables are missing. */
+ /* Established behavior: warn if underlying tables, columns, or functions
+ are missing. */
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_VIEW_INVALID,
ER(ER_VIEW_INVALID),
@@ -956,15 +959,6 @@ public:
is_handled= TRUE;
break;
- case ER_SP_DOES_NOT_EXIST:
- /* Established behavior: warn if underlying functions are missing. */
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_VIEW_INVALID,
- ER(ER_VIEW_INVALID),
- m_top_view->get_db_name(),
- m_top_view->get_table_name());
- is_handled= TRUE;
- break;
default:
is_handled= FALSE;
}
@@ -3088,7 +3082,7 @@ static bool show_status_array(THD *thd, const char *wild,
end= int10_to_str((long) *(uint*) value, buff, 10);
break;
case SHOW_SINT:
- end= int10_to_str((long) *(uint*) value, buff, -10);
+ end= int10_to_str((long) *(int*) value, buff, -10);
break;
case SHOW_SLONG:
end= int10_to_str(*(long*) value, buff, -10);
@@ -4636,25 +4630,7 @@ end:
}
-/**
- Trigger_error_handler is intended to intercept and silence SQL conditions
- that might happen during trigger loading for SHOW statements.
- The potential SQL conditions are:
-
- - ER_PARSE_ERROR -- this error is thrown if a trigger definition file
- is damaged or contains invalid CREATE TRIGGER statement. That should
- not happen in normal life.
-
- - ER_TRG_NO_DEFINER -- this warning is thrown when we're loading a
- trigger created/imported in/from the version of MySQL, which does not
- support trigger definers.
-
- - ER_TRG_NO_CREATION_CTX -- this warning is thrown when we're loading a
- trigger created/imported in/from the version of MySQL, which does not
- support trigger creation contexts.
-*/
-
-class Trigger_error_handler : public Internal_error_handler
+class Warnings_only_error_handler : public Internal_error_handler
{
public:
bool handle_condition(THD *thd,
@@ -4669,12 +4645,16 @@ public:
sql_errno == ER_TRG_NO_CREATION_CTX)
return true;
- return false;
+ if (level != Sql_condition::WARN_LEVEL_ERROR)
+ return false;
+
+ if (!thd->get_stmt_da()->is_error())
+ thd->get_stmt_da()->set_error_status(sql_errno, msg, sqlstate, *cond_hdl);
+ return true; // handled!
}
};
-
/**
@brief Fill I_S tables whose data are retrieved
from frm files and storage engine
@@ -4884,25 +4864,11 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
if (!(table_open_method & ~OPEN_FRM_ONLY) &&
db_name != &INFORMATION_SCHEMA_NAME)
{
- /*
- Here we need to filter out warnings, which can happen
- during loading of triggers in fill_schema_table_from_frm(),
- because we don't need those warnings to pollute output of
- SELECT from I_S / SHOW-statements.
- */
-
- Trigger_error_handler err_handler;
- thd->push_internal_handler(&err_handler);
-
- int res= fill_schema_table_from_frm(thd, tables, schema_table,
- db_name, table_name,
- schema_table_idx,
- &open_tables_state_backup,
- can_deadlock);
-
- thd->pop_internal_handler();
-
- if (!res)
+ if (!fill_schema_table_from_frm(thd, tables, schema_table,
+ db_name, table_name,
+ schema_table_idx,
+ &open_tables_state_backup,
+ can_deadlock))
continue;
}
@@ -8050,95 +8016,6 @@ int make_schema_select(THD *thd, SELECT_LEX *sel,
}
-/**
- Fill INFORMATION_SCHEMA-table, leave correct Diagnostics_area /
- Warning_info state after itself.
-
- This function is a wrapper around ST_SCHEMA_TABLE::fill_table(), which
- may "partially silence" some errors. The thing is that during
- fill_table() many errors might be emitted. These errors stem from the
- nature of fill_table().
-
- For example, SELECT ... FROM INFORMATION_SCHEMA.xxx WHERE TABLE_NAME = 'xxx'
- results in a number of 'Table <db name>.xxx does not exist' errors,
- because fill_table() tries to open the 'xxx' table in every possible
- database.
-
- Those errors are cleared (the error status is cleared from
- Diagnostics_area) inside fill_table(), but they remain in Warning_info
- (Warning_info is not cleared because it may contain useful warnings).
-
- This function is responsible for making sure that Warning_info does not
- contain warnings corresponding to the cleared errors.
-
- @note: THD::no_warnings_for_error used to be set before calling
- fill_table(), thus those errors didn't go to Warning_info. This is not
- the case now (THD::no_warnings_for_error was eliminated as a hack), so we
- need to take care of those warnings here.
-
- @param thd Thread context.
- @param table_list I_S table.
- @param join_table JOIN/SELECT table.
-
- @return Error status.
- @retval TRUE Error.
- @retval FALSE Success.
-*/
-static bool do_fill_table(THD *thd,
- TABLE_LIST *table_list,
- JOIN_TAB *join_table)
-{
- // NOTE: fill_table() may generate many "useless" warnings, which will be
- // ignored afterwards. On the other hand, there might be "useful"
- // warnings, which should be presented to the user. Warning_info usually
- // stores no more than THD::variables.max_error_count warnings.
- // The problem is that "useless warnings" may occupy all the slots in the
- // Warning_info, so "useful warnings" get rejected. In order to avoid
- // that problem we create a Warning_info instance, which is capable of
- // storing "unlimited" number of warnings.
- Diagnostics_area *da= thd->get_stmt_da();
- Warning_info wi_tmp(thd->query_id, true, true);
-
- da->push_warning_info(&wi_tmp);
-
- Item *item= join_table->select_cond;
- if (join_table->cache_select &&
- join_table->cache_select->cond)
- {
- /*
- If join buffering is used, we should use the condition that is attached
- to the join cache. Cache condition has a part of WHERE that can be
- checked when we're populating this table.
- join_tab->select_cond is of no interest, because it only has conditions
- that depend on both this table and previous tables in the join order.
- */
- item= join_table->cache_select->cond;
- }
- bool res= table_list->schema_table->fill_table(thd, table_list, item);
-
- da->pop_warning_info();
-
- // Pass an error if any.
-
- if (da->is_error())
- {
- da->push_warning(thd,
- da->sql_errno(),
- da->get_sqlstate(),
- Sql_condition::WARN_LEVEL_ERROR,
- da->message());
- }
-
- // Pass warnings (if any).
- //
- // Filter out warnings with WARN_LEVEL_ERROR level, because they
- // correspond to the errors which were filtered out in fill_table().
- da->copy_non_errors_from_wi(thd, &wi_tmp);
-
- return res;
-}
-
-
/*
Fill temporary schema tables before SELECT
@@ -8158,8 +8035,13 @@ bool get_schema_tables_result(JOIN *join,
THD *thd= join->thd;
LEX *lex= thd->lex;
bool result= 0;
+ const char *old_proc_info;
DBUG_ENTER("get_schema_tables_result");
+ Warnings_only_error_handler err_handler;
+ thd->push_internal_handler(&err_handler);
+ old_proc_info= thd_proc_info(thd, "Filling schema table");
+
for (JOIN_TAB *tab= first_linear_tab(join, WITH_CONST_TABLES);
tab;
tab= next_linear_tab(join, tab, WITHOUT_BUSH_ROOTS))
@@ -8212,20 +8094,56 @@ bool get_schema_tables_result(JOIN *join,
else
table_list->table->file->stats.records= 0;
- if (do_fill_table(thd, table_list, tab))
+
+ Item *cond= tab->select_cond;
+ if (tab->cache_select && tab->cache_select->cond)
+ {
+ /*
+ If join buffering is used, we should use the condition that is
+ attached to the join cache. Cache condition has a part of WHERE that
+ can be checked when we're populating this table.
+ join_tab->select_cond is of no interest, because it only has
+ conditions that depend on both this table and previous tables in the
+ join order.
+ */
+ cond= tab->cache_select->cond;
+ }
+
+ if (table_list->schema_table->fill_table(thd, table_list, cond))
{
result= 1;
join->error= 1;
tab->read_record.table->file= table_list->table->file;
table_list->schema_table_state= executed_place;
- if (!thd->is_error())
- my_error(ER_UNKNOWN_ERROR, MYF(0));
break;
}
tab->read_record.table->file= table_list->table->file;
table_list->schema_table_state= executed_place;
}
}
+ thd->pop_internal_handler();
+ if (thd->is_error())
+ {
+ /*
+ This hack is here, because I_S code uses thd->clear_error() a lot.
+ Which means, a Warnings_only_error_handler cannot handle the error
+ corectly as it does not know whether an error is real (e.g. caused
+ by tab->select_cond->val_int()) or will be cleared later.
+ Thus it ignores all errors, and the real one (that is, the error
+ that was not cleared) is pushed now.
+
+ It also means that an audit plugin cannot process the error correctly
+ either. See also thd->clear_error()
+ */
+ thd->get_stmt_da()->push_warning(thd,
+ thd->get_stmt_da()->sql_errno(),
+ thd->get_stmt_da()->get_sqlstate(),
+ Sql_condition::WARN_LEVEL_ERROR,
+ thd->get_stmt_da()->message());
+ }
+ else if (result)
+ my_error(ER_UNKNOWN_ERROR, MYF(0));
+ thd_proc_info(thd, old_proc_info);
DBUG_RETURN(result);
}
diff --git a/sql/sql_state.c b/sql/sql_state.c
index c733d4b37c0..2bfd61d6696 100644
--- a/sql/sql_state.c
+++ b/sql/sql_state.c
@@ -1,4 +1,5 @@
/* Copyright (C) 2000-2003 MySQL AB
+ Use is subject to license terms
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_table.cc b/sql/sql_table.cc
index 2ffe201e796..d9702472221 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -1,6 +1,6 @@
/*
- Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2010, 2013, Monty Program Ab.
+ Copyright (c) 2000, 2014, Oracle and/or its affiliates.
+ Copyright (c) 2010, 2014, Monty Program 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
@@ -6113,6 +6113,9 @@ static bool fill_alter_inplace_info(THD *thd,
ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_REMOVE_PARTITIONING;
if (alter_info->flags & Alter_info::ALTER_ALL_PARTITION)
ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_ALL_PARTITION;
+ /* Check for: ALTER TABLE FORCE, ALTER TABLE ENGINE and OPTIMIZE TABLE. */
+ if (alter_info->flags & Alter_info::ALTER_RECREATE)
+ ha_alter_info->handler_flags|= Alter_inplace_info::RECREATE_TABLE;
/*
If we altering table with old VARCHAR fields we will be automatically
@@ -6796,12 +6799,8 @@ static bool is_inplace_alter_impossible(TABLE *table,
if (table->s->tmp_table)
DBUG_RETURN(true);
-
/*
- We also test if OPTIMIZE TABLE was given and was mapped to alter table.
- In that case we always do full copy (ALTER_RECREATE is set in this case).
-
- For the ALTER TABLE tbl_name ORDER BY ... we also always use copy
+ For the ALTER TABLE tbl_name ORDER BY ... we always use copy
algorithm. In theory, this operation can be done in-place by some
engine, but since a) no current engine does this and b) our current
API lacks infrastructure for passing information about table ordering
@@ -6811,26 +6810,17 @@ static bool is_inplace_alter_impossible(TABLE *table,
not supported for in-place in combination with other operations.
Alone, it will be done by simple_rename_or_index_change().
*/
- if (alter_info->flags & (Alter_info::ALTER_RECREATE |
- Alter_info::ALTER_ORDER |
+ if (alter_info->flags & (Alter_info::ALTER_ORDER |
Alter_info::ALTER_KEYS_ONOFF))
DBUG_RETURN(true);
/*
- Test also that engine was not given during ALTER TABLE, or
- we are force to run regular alter table (copy).
- E.g. ALTER TABLE tbl_name ENGINE=MyISAM.
- Note that in addition to checking flag in HA_CREATE_INFO we
- also check HA_CREATE_INFO::db_type value. This is done
- to cover cases in which engine is changed implicitly
- (e.g. when non-partitioned table becomes partitioned).
-
- Note that we do copy even if the table is already using the
- given engine. Many users and tools depend on using ENGINE
- to force a table rebuild.
+ If the table engine is changed explicitly (using ENGINE clause)
+ or implicitly (e.g. when non-partitioned table becomes
+ partitioned) a regular alter table (copy) needs to be
+ performed.
*/
- if (create_info->db_type != table->s->db_type() ||
- create_info->used_fields & HA_CREATE_USED_ENGINE)
+ if (create_info->db_type != table->s->db_type())
DBUG_RETURN(true);
/*
@@ -7301,6 +7291,9 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
if (!(used_fields & HA_CREATE_USED_TRANSACTIONAL))
create_info->transactional= table->s->transactional;
+ if (!(used_fields & HA_CREATE_USED_CONNECTION))
+ create_info->connect_string= table->s->connect_string;
+
restore_record(table, s->default_values); // Empty record for DEFAULT
if ((create_info->fields_option_struct= (ha_field_option_struct**)
@@ -8568,6 +8561,15 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
}
/*
+ ALTER TABLE ... ENGINE to the same engine is a common way to
+ request table rebuild. Set ALTER_RECREATE flag to force table
+ rebuild.
+ */
+ if (create_info->db_type == table->s->db_type() &&
+ create_info->used_fields & HA_CREATE_USED_ENGINE)
+ alter_info->flags|= Alter_info::ALTER_RECREATE;
+
+ /*
If the old table had partitions and we are doing ALTER TABLE ...
engine= <new_engine>, the new table must preserve the original
partitioning. This means that the new engine is still the
@@ -9535,12 +9537,14 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
mysql_recreate_table()
thd Thread handler
tables Tables to recreate
+ table_copy Recreate the table by using
+ ALTER TABLE COPY algorithm
RETURN
Like mysql_alter_table().
*/
-bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list)
+bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool table_copy)
{
HA_CREATE_INFO create_info;
Alter_info alter_info;
@@ -9558,6 +9562,10 @@ bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list)
/* Force alter table to recreate table */
alter_info.flags= (Alter_info::ALTER_CHANGE_COLUMN |
Alter_info::ALTER_RECREATE);
+
+ if (table_copy)
+ alter_info.requested_algorithm= Alter_info::ALTER_TABLE_ALGORITHM_COPY;
+
DBUG_RETURN(mysql_alter_table(thd, NullS, NullS, &create_info,
table_list, &alter_info, 0,
(ORDER *) 0, 0));
diff --git a/sql/sql_table.h b/sql/sql_table.h
index cd1c4293c39..444626e0363 100644
--- a/sql/sql_table.h
+++ b/sql/sql_table.h
@@ -1,5 +1,5 @@
-/* Copyright (c) 2006, 2013, Oracle and/or its affiliates.
- Copyright (c) 2011, 2013, Monty Program Ab.
+/* Copyright (c) 2006, 2014, Oracle and/or its affiliates.
+ Copyright (c) 2011, 2014, Monty Program 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
@@ -222,7 +222,7 @@ bool mysql_compare_tables(TABLE *table,
Alter_info *alter_info,
HA_CREATE_INFO *create_info,
bool *metadata_equal);
-bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list);
+bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool table_copy);
bool mysql_create_like_table(THD *thd, TABLE_LIST *table,
TABLE_LIST *src_table,
HA_CREATE_INFO *create_info);
diff --git a/sql/sql_time.cc b/sql/sql_time.cc
index 9b68aba5b30..c8a2c2daf85 100644
--- a/sql/sql_time.cc
+++ b/sql/sql_time.cc
@@ -1118,6 +1118,57 @@ int my_time_compare(const MYSQL_TIME *a, const MYSQL_TIME *b)
}
+/**
+ Convert TIME to DATETIME.
+ @param ltime The value to convert.
+ @return false on success, true of error (negative time).
+*/
+bool time_to_datetime(MYSQL_TIME *ltime)
+{
+ DBUG_ASSERT(ltime->time_type == MYSQL_TIMESTAMP_TIME);
+ DBUG_ASSERT(ltime->year == 0);
+ DBUG_ASSERT(ltime->month == 0);
+ DBUG_ASSERT(ltime->day == 0);
+ if (ltime->neg)
+ return true;
+ uint day= ltime->hour / 24;
+ ltime->hour%= 24;
+ ltime->month= day / 31;
+ ltime->day= day % 31;
+ return false;
+}
+
+
+/**
+ Return a valid DATE or DATETIME value from an arbitrary MYSQL_TIME.
+ If ltime is TIME, it's first converted to DATETIME.
+ If ts_type is DATE, hhmmss is set to zero.
+ The date part of the result is checked against fuzzy_date.
+
+ @param ltime The value to convert.
+ @param fuzzy_date Flags to check date.
+ @param ts_type The type to convert to.
+ @return false on success, true of error (negative time).*/
+bool
+make_date_with_warn(MYSQL_TIME *ltime, ulonglong fuzzy_date,
+ timestamp_type ts_type)
+{
+ DBUG_ASSERT(ts_type == MYSQL_TIMESTAMP_DATE ||
+ ts_type == MYSQL_TIMESTAMP_DATETIME);
+ if (ltime->time_type == MYSQL_TIMESTAMP_TIME && time_to_datetime(ltime))
+ {
+ /* e.g. negative time */
+ ErrConvTime str(ltime);
+ make_truncated_value_warning(current_thd, Sql_condition::WARN_LEVEL_WARN,
+ &str, ts_type, 0);
+ return true;
+ }
+ if ((ltime->time_type= ts_type) == MYSQL_TIMESTAMP_DATE)
+ ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0;
+ return check_date_with_warn(ltime, fuzzy_date, ts_type);
+}
+
+
/*
Convert a TIME value to DAY-TIME interval, e.g. for extraction:
EXTRACT(DAY FROM x), EXTRACT(HOUR FROM x), etc.
diff --git a/sql/sql_time.h b/sql/sql_time.h
index 7513ca7c00a..5a468ef0649 100644
--- a/sql/sql_time.h
+++ b/sql/sql_time.h
@@ -33,6 +33,7 @@ typedef struct st_known_date_time_format KNOWN_DATE_TIME_FORMAT;
ulong convert_period_to_month(ulong period);
ulong convert_month_to_period(ulong month);
+bool time_to_datetime(MYSQL_TIME *ltime);
void time_to_daytime_interval(MYSQL_TIME *l_time);
bool get_date_from_daynr(long daynr,uint *year, uint *month, uint *day);
my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, uint *error_code);
@@ -154,6 +155,8 @@ check_date(const MYSQL_TIME *ltime, ulonglong flags, int *was_cut)
}
bool check_date_with_warn(const MYSQL_TIME *ltime, ulonglong fuzzy_date,
timestamp_type ts_type);
+bool make_date_with_warn(MYSQL_TIME *ltime,
+ ulonglong fuzzy_date, timestamp_type ts_type);
bool adjust_time_range_with_warn(MYSQL_TIME *ltime, uint dec);
#endif /* SQL_TIME_INCLUDED */
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index d137c2ab7aa..c3188305092 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -464,6 +464,13 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
*/
thd->lex->sql_command= backup.sql_command;
+ if (opt_readonly && !(thd->security_ctx->master_access & SUPER_ACL) &&
+ !thd->slave_thread)
+ {
+ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
+ goto end;
+ }
+
if (add_table_for_trigger(thd, thd->lex->spname, if_exists, & tables))
goto end;
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index e9e8033c4fd..f3a1ec18aaf 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -1429,11 +1429,11 @@ int mysql_multi_update_prepare(THD *thd)
be write-locked (for example, trigger to be invoked might try
to update this table).
*/
- tl->lock_type= read_lock_type_for_table(thd, lex, tl);
+ if (using_lock_tables)
+ tl->lock_type= read_lock_type_for_table(thd, lex, tl);
+ else
+ tl->set_lock_type(thd, read_lock_type_for_table(thd, lex, tl));
tl->updating= 0;
- /* Update TABLE::lock_type accordingly. */
- if (!tl->placeholder() && !using_lock_tables)
- tl->table->reginfo.lock_type= tl->lock_type;
}
}
@@ -1921,6 +1921,13 @@ loop_end:
TABLE *tbl= table;
do
{
+ /*
+ Signal each table (including tables referenced by WITH CHECK OPTION
+ clause) for which we will store row position in the temporary table
+ that we need a position to be read first.
+ */
+ tbl->prepare_for_position();
+
Field_string *field= new Field_string(tbl->file->ref_length, 0,
tbl->alias.c_ptr(),
&my_charset_bin);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index ceb4e247848..9ea72676b13 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1,6 +1,6 @@
/*
- Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2010, 2011, Monty Program Ab.
+ Copyright (c) 2000, 2014, Oracle and/or its affiliates.
+ Copyright (c) 2010, 2014, Monty Program 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
@@ -442,6 +442,13 @@ set_system_variable(THD *thd, struct sys_var_with_base *tmp,
if (lex->spcont && tmp->var == Sys_autocommit_ptr)
lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
+ if (val && val->type() == Item::FIELD_ITEM &&
+ ((Item_field*)val)->table_name)
+ {
+ my_error(ER_WRONG_TYPE_FOR_VAR, MYF(0), tmp->var->name.str);
+ return TRUE;
+ }
+
if (! (var= new set_var(var_type, tmp->var, &tmp->base_name, val)))
return TRUE;
@@ -810,7 +817,6 @@ static void sp_create_assignment_lex(THD *thd, bool no_lookahead)
lex->sql_command= SQLCOM_SET_OPTION;
mysql_init_select(lex);
lex->var_list.empty();
- lex->one_shot_set= 0;
lex->autocommit= 0;
/* get_ptr() is only correct with no lookahead. */
DBUG_ASSERT(no_lookahead);
@@ -11305,7 +11311,10 @@ opt_limit_clause:
limit_clause:
LIMIT limit_options
{
- Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT);
+ SELECT_LEX *sel= Select;
+ if (!sel->select_limit->basic_const_item() ||
+ sel->select_limit->val_int() > 0)
+ Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT);
}
| LIMIT limit_options ROWS_SYM EXAMINED_SYM limit_rows_option
{
@@ -14421,7 +14430,6 @@ set:
mysql_init_select(lex);
lex->option_type=OPT_SESSION;
lex->var_list.empty();
- lex->one_shot_set= 0;
lex->autocommit= 0;
sp_create_assignment_lex(thd, yychar == YYEMPTY);
}
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 3d283a5f32b..d9b43f4d5b6 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -287,14 +287,15 @@ static Sys_var_long Sys_pfs_events_stages_history_size(
- 1 for "statement/com/new_packet", for unknown enum_server_command
- 1 for "statement/com/Error", for invalid enum_server_command
- SQLCOM_END for all regular "statement/sql/...",
- - 1 for "statement/sql/error", for invalid enum_sql_command.
+ - 1 for "statement/sql/error", for invalid enum_sql_command
+ - 1 for "statement/rpl/relay_log", for replicated statements.
*/
static Sys_var_ulong Sys_pfs_max_statement_classes(
"performance_schema_max_statement_classes",
"Maximum number of statement instruments.",
PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_statement_class_sizing),
CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 256),
- DEFAULT((ulong) SQLCOM_END + (ulong) COM_END + 3),
+ DEFAULT((ulong) SQLCOM_END + (ulong) COM_END + 4),
BLOCK_SIZE(1));
static Sys_var_long Sys_pfs_events_statements_history_long_size(
@@ -4833,6 +4834,46 @@ static Sys_var_set Sys_log_slow_filter(
log_slow_filter_names,
DEFAULT(MAX_SET(array_elements(log_slow_filter_names)-1)));
+static const char *default_regex_flags_names[]=
+{
+ "DOTALL", // (?s) . matches anything including NL
+ "DUPNAMES", // (?J) Allow duplicate names for subpatterns
+ "EXTENDED", // (?x) Ignore white space and # comments
+ "EXTRA", // (?X) extra features (e.g. error on unknown escape character)
+ "MULTILINE", // (?m) ^ and $ match newlines within data
+ "UNGREEDY", // (?U) Invert greediness of quantifiers
+ 0
+};
+static const int default_regex_flags_to_pcre[]=
+{
+ PCRE_DOTALL,
+ PCRE_DUPNAMES,
+ PCRE_EXTENDED,
+ PCRE_EXTRA,
+ PCRE_MULTILINE,
+ PCRE_UNGREEDY,
+ 0
+};
+int default_regex_flags_pcre(const THD *thd)
+{
+ ulonglong src= thd->variables.default_regex_flags;
+ int i, res;
+ for (i= res= 0; default_regex_flags_to_pcre[i]; i++)
+ {
+ if (src & (1 << i))
+ res|= default_regex_flags_to_pcre[i];
+ }
+ return res;
+}
+static Sys_var_set Sys_default_regex_flags(
+ "default_regex_flags",
+ "Default flags for the regex library. "
+ "Syntax: default-regex-flags='[flag[,flag[,flag...]]]'. "
+ "See the manual for the complete list of valid flags",
+ SESSION_VAR(default_regex_flags), CMD_LINE(REQUIRED_ARG),
+ default_regex_flags_names,
+ DEFAULT(0));
+
static Sys_var_ulong Sys_log_slow_rate_limit(
"log_slow_rate_limit",
"Write to slow log every #th slow query. Set to 1 to log everything. "
diff --git a/sql/table.cc b/sql/table.cc
index f7fe67c8437..ab943e1cf62 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -3439,6 +3439,24 @@ uint calculate_key_len(TABLE *table, uint key, const uchar *buf,
return length;
}
+#ifndef DBUG_OFF
+/**
+ Verifies that database/table name is in lowercase, when it should be
+
+ This is supposed to be used only inside DBUG_ASSERT()
+*/
+bool ok_for_lower_case_names(const char *name)
+{
+ if (!lower_case_table_names || !name)
+ return true;
+
+ char buf[SAFE_NAME_LEN];
+ strmake_buf(buf, name);
+ my_casedn_str(files_charset_info, buf);
+ return strcmp(name, buf) == 0;
+}
+#endif
+
/*
Check if database name is valid
@@ -4000,13 +4018,15 @@ void TABLE::init(THD *thd, TABLE_LIST *tl)
status= STATUS_NO_RECORD;
insert_values= 0;
fulltext_searched= 0;
- file->ha_start_of_new_statement();
+ file->ft_handler= 0;
+#if 0
#ifdef WITH_WSREP
if (file->ht->db_type == DB_TYPE_PARTITION_DB)
{
((ha_partition*)file)->wsrep_reset_files();
}
#endif
+#endif
reginfo.impossible_range= 0;
created= TRUE;
cond_selectivity= 1.0;
@@ -7052,6 +7072,27 @@ bool TABLE_LIST::change_refs_to_fields()
}
+void TABLE_LIST::set_lock_type(THD *thd, enum thr_lock_type lock)
+{
+ if (check_stack_overrun(thd, STACK_MIN_SIZE, (uchar *)&lock))
+ return;
+ /* we call it only when table is opened and it is "leaf" table*/
+ DBUG_ASSERT(table);
+ lock_type= lock;
+ /* table->file->get_table() can be 0 for derived tables */
+ if (table->file && table->file->get_table())
+ table->file->set_lock_type(lock);
+ if (is_merged_derived())
+ {
+ for (TABLE_LIST *table= get_single_select()->get_table_list();
+ table;
+ table= table->next_local)
+ {
+ table->set_lock_type(thd, lock);
+ }
+ }
+}
+
uint TABLE_SHARE::actual_n_key_parts(THD *thd)
{
return use_ext_keys &&
diff --git a/sql/table.h b/sql/table.h
index cd1b934dcdd..86e03cdaaf5 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -1114,7 +1114,11 @@ public:
*/
ha_rows quick_rows[MAX_KEY];
- /* Bitmaps of key parts that =const for the entire join. */
+ /*
+ Bitmaps of key parts that =const for the duration of join execution. If
+ we're in a subquery, then the constant may be different across subquery
+ re-executions.
+ */
key_part_map const_key_parts[MAX_KEY];
uint quick_key_parts[MAX_KEY];
@@ -2241,6 +2245,7 @@ struct TABLE_LIST
}
return false;
}
+ void set_lock_type(THD* thd, enum thr_lock_type lock);
private:
bool prep_check_option(THD *thd, uint8 check_opt_type);
@@ -2507,6 +2512,8 @@ static inline void dbug_tmp_restore_column_maps(MY_BITMAP *read_set,
#endif
}
+bool ok_for_lower_case_names(const char *names);
+
enum get_table_share_flags {
GTS_TABLE = 1,
GTS_VIEW = 2,
diff --git a/sql/transaction.cc b/sql/transaction.cc
index 8770f729b88..72a8c47cdd8 100644
--- a/sql/transaction.cc
+++ b/sql/transaction.cc
@@ -616,6 +616,32 @@ bool trans_rollback_to_savepoint(THD *thd, LEX_STRING name)
DBUG_RETURN(TRUE);
}
+ /**
+ Checking whether it is safe to release metadata locks acquired after
+ savepoint, if rollback to savepoint is successful.
+
+ Whether it is safe to release MDL after rollback to savepoint depends
+ on storage engines participating in transaction:
+
+ - InnoDB doesn't release any row-locks on rollback to savepoint so it
+ is probably a bad idea to release MDL as well.
+ - Binary log implementation in some cases (e.g when non-transactional
+ tables involved) may choose not to remove events added after savepoint
+ from transactional cache, but instead will write them to binary
+ log accompanied with ROLLBACK TO SAVEPOINT statement. Since the real
+ write happens at the end of transaction releasing MDL on tables
+ mentioned in these events (i.e. acquired after savepoint and before
+ rollback ot it) can break replication, as concurrent DROP TABLES
+ statements will be able to drop these tables before events will get
+ into binary log,
+
+ For backward-compatibility reasons we always release MDL if binary
+ logging is off.
+ */
+ bool mdl_can_safely_rollback_to_savepoint=
+ (!(mysql_bin_log.is_open() && thd->variables.sql_log_bin) ||
+ ha_rollback_to_savepoint_can_release_mdl(thd));
+
if (ha_rollback_to_savepoint(thd, sv))
res= TRUE;
else if (((thd->variables.option_bits & OPTION_KEEP_LOG) ||
@@ -627,14 +653,7 @@ bool trans_rollback_to_savepoint(THD *thd, LEX_STRING name)
thd->transaction.savepoints= sv;
- /*
- Release metadata locks that were acquired during this savepoint unit
- unless binlogging is on. Releasing locks with binlogging on can break
- replication as it allows other connections to drop these tables before
- rollback to savepoint is written to the binlog.
- */
- bool binlog_on= mysql_bin_log.is_open() && thd->variables.sql_log_bin;
- if (!res && !binlog_on)
+ if (!res && mdl_can_safely_rollback_to_savepoint)
thd->mdl_context.rollback_to_savepoint(sv->mdl_savepoint);
DBUG_RETURN(MY_TEST(res));
diff --git a/sql/unireg.cc b/sql/unireg.cc
index aeeba6f4f85..b7ac8b17c38 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -46,9 +46,14 @@ static bool pack_fields(uchar *, List<Create_field> &, ulong);
static size_t packed_fields_length(List<Create_field> &);
static bool make_empty_rec(THD *, uchar *, uint, List<Create_field> &, uint, ulong);
+/*
+ write the length as
+ if ( 0 < length <= 255) one byte
+ if (256 < length <= 65535) zero byte, then two bytes, low-endian
+*/
static uchar *extra2_write_len(uchar *pos, size_t len)
{
- if (len < 255)
+ if (len <= 255)
*pos++= len;
else
{