summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/CMakeLists.txt1
-rw-r--r--sql/debug_sync.cc355
-rw-r--r--sql/debug_sync.h14
-rw-r--r--sql/field.cc3
-rw-r--r--sql/filesort.cc205
-rw-r--r--sql/ha_ndbcluster.h3
-rw-r--r--sql/ha_ndbcluster_binlog.h3
-rw-r--r--sql/ha_partition.cc283
-rw-r--r--sql/ha_partition.h42
-rw-r--r--sql/handler.cc2
-rw-r--r--sql/handler.h2
-rw-r--r--sql/item.cc49
-rw-r--r--sql/item.h4
-rw-r--r--sql/item_cmpfunc.cc4
-rw-r--r--sql/item_cmpfunc.h17
-rw-r--r--sql/item_func.cc2
-rw-r--r--sql/item_subselect.cc5
-rw-r--r--sql/item_timefunc.cc8
-rw-r--r--sql/item_xmlfunc.cc3
-rw-r--r--sql/lock.cc2
-rw-r--r--sql/log.cc2
-rw-r--r--sql/log_event.cc25
-rw-r--r--sql/log_event.h5
-rw-r--r--sql/mem_root_array.h175
-rw-r--r--sql/mysqld.cc279
-rw-r--r--sql/mysqld.h2
-rw-r--r--sql/opt_range.cc2
-rw-r--r--sql/opt_subselect.cc281
-rw-r--r--sql/password.c2
-rw-r--r--sql/protocol.cc4
-rw-r--r--sql/records.cc5
-rw-r--r--sql/rpl_filter.cc236
-rw-r--r--sql/rpl_filter.h24
-rw-r--r--sql/rpl_handler.h2
-rw-r--r--sql/rpl_injector.cc3
-rw-r--r--sql/rpl_mi.cc2
-rw-r--r--sql/rpl_mi.h3
-rw-r--r--sql/rpl_rli.cc3
-rw-r--r--sql/rpl_rli.h10
-rw-r--r--sql/set_var.h2
-rw-r--r--sql/share/errmsg-utf8.txt26
-rw-r--r--sql/signal_handler.cc3
-rw-r--r--sql/slave.cc102
-rw-r--r--sql/sp_cache.cc2
-rw-r--r--sql/sp_cache.h2
-rw-r--r--sql/sp_head.cc19
-rw-r--r--sql/sp_head.h12
-rw-r--r--sql/sql_admin.cc10
-rw-r--r--sql/sql_base.cc97
-rw-r--r--sql/sql_cache.cc3
-rw-r--r--sql/sql_class.cc7
-rw-r--r--sql/sql_connect.cc4
-rw-r--r--sql/sql_delete.cc3
-rw-r--r--sql/sql_handler.cc3
-rw-r--r--sql/sql_join_cache.cc18
-rw-r--r--sql/sql_lex.cc28
-rw-r--r--sql/sql_lex.h34
-rw-r--r--sql/sql_list.h1
-rw-r--r--sql/sql_logger.cc183
-rw-r--r--sql/sql_parse.cc7
-rw-r--r--sql/sql_partition.cc39
-rw-r--r--sql/sql_partition.h2
-rw-r--r--sql/sql_plugin.cc12
-rw-r--r--sql/sql_plugin_services.h10
-rw-r--r--sql/sql_prepare.cc18
-rw-r--r--sql/sql_profile.cc5
-rw-r--r--sql/sql_repl.cc22
-rw-r--r--sql/sql_select.cc279
-rw-r--r--sql/sql_select.h32
-rw-r--r--sql/sql_show.cc26
-rw-r--r--sql/sql_table.cc19
-rw-r--r--sql/sql_udf.cc3
-rw-r--r--sql/sql_update.cc6
-rw-r--r--sql/sql_view.cc7
-rw-r--r--sql/sql_yacc.yy12
-rw-r--r--sql/sys_vars.cc148
-rw-r--r--sql/sys_vars.h52
-rw-r--r--sql/table.cc71
-rw-r--r--sql/table.h9
-rw-r--r--sql/threadpool_unix.cc16
-rw-r--r--sql/threadpool_win.cc13
-rw-r--r--sql/transaction.cc2
-rw-r--r--sql/unireg.h2
83 files changed, 2228 insertions, 1215 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index 8834e6a8ae9..a4da6804cb3 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -86,7 +86,6 @@ SET (SQL_SOURCE
gcalc_slicescan.cc gcalc_tools.cc
threadpool_common.cc
../sql-common/mysql_async.c
- sql_logger.cc
${GEN_SOURCES}
${MYSYS_LIBWRAP_SOURCE}
)
diff --git a/sql/debug_sync.cc b/sql/debug_sync.cc
index a789763dd25..4097d7fe6e1 100644
--- a/sql/debug_sync.cc
+++ b/sql/debug_sync.cc
@@ -13,307 +13,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
-/**
- == Debug Sync Facility ==
-
- The Debug Sync Facility allows placement of synchronization points in
- the server code by using the DEBUG_SYNC macro:
-
- open_tables(...)
-
- DEBUG_SYNC(thd, "after_open_tables");
-
- lock_tables(...)
-
- When activated, a sync point can
-
- - Emit a signal and/or
- - Wait for a signal
-
- Nomenclature:
-
- - signal: A value of a global variable that persists
- until overwritten by a new signal. The global
- variable can also be seen as a "signal post"
- or "flag mast". Then the signal is what is
- attached to the "signal post" or "flag mast".
-
- - emit a signal: Assign the value (the signal) to the global
- variable ("set a flag") and broadcast a
- global condition to wake those waiting for
- a signal.
-
- - wait for a signal: Loop over waiting for the global condition until
- the global value matches the wait-for signal.
-
- By default, all sync points are inactive. They do nothing (except to
- burn a couple of CPU cycles for checking if they are active).
-
- A sync point becomes active when an action is requested for it.
- To do so, put a line like this in the test case file:
-
- SET DEBUG_SYNC= 'after_open_tables SIGNAL opened WAIT_FOR flushed';
-
- This activates the sync point 'after_open_tables'. It requests it to
- emit the signal 'opened' and wait for another thread to emit the signal
- 'flushed' when the thread's execution runs through the sync point.
-
- For every sync point there can be one action per thread only. Every
- thread can request multiple actions, but only one per sync point. In
- other words, a thread can activate multiple sync points.
-
- Here is an example how to activate and use the sync points:
-
- --connection conn1
- SET DEBUG_SYNC= 'after_open_tables SIGNAL opened WAIT_FOR flushed';
- send INSERT INTO t1 VALUES(1);
- --connection conn2
- SET DEBUG_SYNC= 'now WAIT_FOR opened';
- SET DEBUG_SYNC= 'after_abort_locks SIGNAL flushed';
- FLUSH TABLE t1;
-
- When conn1 runs through the INSERT statement, it hits the sync point
- 'after_open_tables'. It notices that it is active and executes its
- action. It emits the signal 'opened' and waits for another thread to
- emit the signal 'flushed'.
-
- conn2 waits immediately at the special sync point 'now' for another
- thread to emit the 'opened' signal.
-
- A signal remains in effect until it is overwritten. If conn1 signals
- 'opened' before conn2 reaches 'now', conn2 will still find the 'opened'
- signal. It does not wait in this case.
-
- When conn2 reaches 'after_abort_locks', it signals 'flushed', which lets
- conn1 awake.
-
- Normally the activation of a sync point is cleared when it has been
- executed. Sometimes it is necessary to keep the sync point active for
- another execution. You can add an execute count to the action:
-
- SET DEBUG_SYNC= 'name SIGNAL sig EXECUTE 3';
-
- This sets the signal point's activation counter to 3. Each execution
- decrements the counter. After the third execution the sync point
- becomes inactive.
-
- One of the primary goals of this facility is to eliminate sleeps from
- the test suite. In most cases it should be possible to rewrite test
- cases so that they do not need to sleep. (But this facility cannot
- synchronize multiple processes.) However, to support test development,
- and as a last resort, sync point waiting times out. There is a default
- timeout, but it can be overridden:
-
- SET DEBUG_SYNC= 'name WAIT_FOR sig TIMEOUT 10 EXECUTE 2';
-
- TIMEOUT 0 is special: If the signal is not present, the wait times out
- immediately.
-
- When a wait timed out (even on TIMEOUT 0), a warning is generated so
- that it shows up in the test result.
-
- You can throw an error message and kill the query when a synchronization
- point is hit a certain number of times:
-
- SET DEBUG_SYNC= 'name HIT_LIMIT 3';
-
- Or combine it with signal and/or wait:
-
- SET DEBUG_SYNC= 'name SIGNAL sig EXECUTE 2 HIT_LIMIT 3';
-
- Here the first two hits emit the signal, the third hit returns the error
- message and kills the query.
-
- For cases where you are not sure that an action is taken and thus
- cleared in any case, you can force to clear (deactivate) a sync point:
-
- SET DEBUG_SYNC= 'name CLEAR';
-
- If you want to clear all actions and clear the global signal, use:
-
- SET DEBUG_SYNC= 'RESET';
-
- This is the only way to reset the global signal to an empty string.
-
- For testing of the facility itself you can execute a sync point just
- as if it had been hit:
-
- SET DEBUG_SYNC= 'name TEST';
-
-
- === Formal Syntax ===
-
- The string to "assign" to the DEBUG_SYNC variable can contain:
-
- {RESET |
- <sync point name> TEST |
- <sync point name> CLEAR |
- <sync point name> {{SIGNAL <signal name> |
- WAIT_FOR <signal name> [TIMEOUT <seconds>]}
- [EXECUTE <count>] &| HIT_LIMIT <count>}
-
- Here '&|' means 'and/or'. This means that one of the sections
- separated by '&|' must be present or both of them.
-
-
- === Activation/Deactivation ===
-
- The facility is an optional part of the MySQL server.
- It is enabled in a debug server by default.
-
- ./configure --enable-debug-sync
-
- The Debug Sync Facility, when compiled in, is disabled by default. It
- can be enabled by a mysqld command line option:
-
- --debug-sync-timeout[=default_wait_timeout_value_in_seconds]
-
- 'default_wait_timeout_value_in_seconds' is the default timeout for the
- WAIT_FOR action. If set to zero, the facility stays disabled.
-
- The facility is enabled by default in the test suite, but can be
- disabled with:
-
- mysql-test-run.pl ... --debug-sync-timeout=0 ...
-
- Likewise the default wait timeout can be set:
-
- mysql-test-run.pl ... --debug-sync-timeout=10 ...
-
- The command line option influences the readable value of the system
- variable 'debug_sync'.
-
- * If the facility is not compiled in, the system variable does not exist.
-
- * If --debug-sync-timeout=0 the value of the variable reads as "OFF".
-
- * Otherwise the value reads as "ON - current signal: " followed by the
- current signal string, which can be empty.
-
- The readable variable value is the same, regardless if read as global
- or session value.
-
- Setting the 'debug-sync' system variable requires 'SUPER' privilege.
- You can never read back the string that you assigned to the variable,
- unless you assign the value that the variable does already have. But
- that would give a parse error. A syntactically correct string is
- parsed into a debug sync action and stored apart from the variable value.
-
-
- === Implementation ===
-
- Pseudo code for a sync point:
-
- #define DEBUG_SYNC(thd, sync_point_name)
- if (unlikely(opt_debug_sync_timeout))
- debug_sync(thd, STRING_WITH_LEN(sync_point_name))
-
- The sync point performs a binary search in a sorted array of actions
- for this thread.
-
- The SET DEBUG_SYNC statement adds a requested action to the array or
- overwrites an existing action for the same sync point. When it adds a
- new action, the array is sorted again.
-
-
- === A typical synchronization pattern ===
-
- There are quite a few places in MySQL, where we use a synchronization
- pattern like this:
-
- mysql_mutex_lock(&mutex);
- thd->enter_cond(&condition_variable, &mutex, new_message);
- #if defined(ENABLE_DEBUG_SYNC)
- if (!thd->killed && !end_of_wait_condition)
- DEBUG_SYNC(thd, "sync_point_name");
- #endif
- while (!thd->killed && !end_of_wait_condition)
- mysql_cond_wait(&condition_variable, &mutex);
- thd->exit_cond(old_message);
-
- Here some explanations:
-
- thd->enter_cond() is used to register the condition variable and the
- mutex in thd->mysys_var. This is done to allow the thread to be
- interrupted (killed) from its sleep. Another thread can find the
- condition variable to signal and mutex to use for synchronization in
- this thread's THD::mysys_var.
-
- thd->enter_cond() requires the mutex to be acquired in advance.
-
- thd->exit_cond() unregisters the condition variable and mutex and
- releases the mutex.
-
- If you want to have a Debug Sync point with the wait, please place it
- behind enter_cond(). Only then you can safely decide, if the wait will
- be taken. Also you will have THD::proc_info correct when the sync
- point emits a signal. DEBUG_SYNC sets its own proc_info, but restores
- the previous one before releasing its internal mutex. As soon as
- another thread sees the signal, it does also see the proc_info from
- before entering the sync point. In this case it will be "new_message",
- which is associated with the wait that is to be synchronized.
-
- In the example above, the wait condition is repeated before the sync
- point. This is done to skip the sync point, if no wait takes place.
- The sync point is before the loop (not inside the loop) to have it hit
- once only. It is possible that the condition variable is signaled
- multiple times without the wait condition to be true.
-
- A bit off-topic: At some places, the loop is taken around the whole
- synchronization pattern:
-
- while (!thd->killed && !end_of_wait_condition)
- {
- mysql_mutex_lock(&mutex);
- thd->enter_cond(&condition_variable, &mutex, new_message);
- if (!thd->killed [&& !end_of_wait_condition])
- {
- [DEBUG_SYNC(thd, "sync_point_name");]
- mysql_cond_wait(&condition_variable, &mutex);
- }
- thd->exit_cond(old_message);
- }
-
- Note that it is important to repeat the test for thd->killed after
- enter_cond(). Otherwise the killing thread may kill this thread after
- it tested thd->killed in the loop condition and before it registered
- the condition variable and mutex in enter_cond(). In this case, the
- killing thread does not know that this thread is going to wait on a
- condition variable. It would just set THD::killed. But if we would not
- test it again, we would go asleep though we are killed. If the killing
- thread would kill us when we are after the second test, but still
- before sleeping, we hold the mutex, which is registered in mysys_var.
- The killing thread would try to acquire the mutex before signaling
- the condition variable. Since the mutex is only released implicitly in
- mysql_cond_wait(), the signaling happens at the right place. We
- have a safe synchronization.
-
- === Co-work with the DBUG facility ===
-
- When running the MySQL test suite with the --debug-dbug command line
- option, the Debug Sync Facility writes trace messages to the DBUG
- trace. The following shell commands proved very useful in extracting
- relevant information:
-
- egrep 'query:|debug_sync_exec:' mysql-test/var/log/mysqld.1.trace
-
- It shows all executed SQL statements and all actions executed by
- synchronization points.
-
- Sometimes it is also useful to see, which synchronization points have
- been run through (hit) with or without executing actions. Then add
- "|debug_sync_point:" to the egrep pattern.
-
- === Further reading ===
-
- For a discussion of other methods to synchronize threads see
- http://forge.mysql.com/wiki/MySQL_Internals_Test_Synchronization
-
- For complete syntax tests, functional tests, and examples see the test
- case debug_sync.test.
-
- See also worklog entry WL#4259 - Test Synchronization Facility
-*/
+/* see include/mysql/service_debug_sync.h for debug sync documentation */
#include "debug_sync.h"
@@ -382,57 +82,16 @@ struct st_debug_sync_globals
};
static st_debug_sync_globals debug_sync_global; /* All globals in one object */
-/**
- Callback pointer for C files.
-*/
-extern "C" void (*debug_sync_C_callback_ptr)(const char *, size_t);
+extern uint opt_debug_sync_timeout;
/**
Callbacks from C files.
*/
C_MODE_START
-static void debug_sync_C_callback(const char *, size_t);
+static void debug_sync(THD *thd, const char *sync_point_name, size_t name_len);
static int debug_sync_qsort_cmp(const void *, const void *);
C_MODE_END
-/**
- Callback for debug sync, to be used by C files. See thr_lock.c for example.
-
- @description
-
- We cannot place a sync point directly in C files (like those in mysys or
- certain storage engines written mostly in C like MyISAM or Maria). Because
- they are C code and do not include sql_priv.h. So they do not know the
- macro DEBUG_SYNC(thd, sync_point_name). The macro needs a 'thd' argument.
- Hence it cannot be used in files outside of the sql/ directory.
-
- The workaround is to call back simple functions like this one from
- non-sql/ files.
-
- We want to allow modules like thr_lock to be used without sql/ and
- especially without Debug Sync. So we cannot just do a simple call
- of the callback function. Instead we provide a global pointer in
- the other file, which is to be set to the callback by Debug Sync.
- If the pointer is not set, no call back will be done. If Debug
- Sync sets the pointer to a callback function like this one, it will
- be called. That way thr_lock.c does not have an undefined reference
- to Debug Sync and can be used without it. Debug Sync, in contrast,
- has an undefined reference to that pointer and thus requires
- thr_lock to be linked too. But this is not a problem as it is part
- of the MySQL server anyway.
-
- @note
- The callback pointer in C files is set only if debug sync is
- initialized. And this is done only if opt_debug_sync_timeout is set.
-*/
-
-static void debug_sync_C_callback(const char *sync_point_name,
- size_t name_len)
-{
- if (unlikely(opt_debug_sync_timeout))
- debug_sync(current_thd, sync_point_name, name_len);
-}
-
#ifdef HAVE_PSI_INTERFACE
static PSI_mutex_key key_debug_sync_globals_ds_mutex;
@@ -495,7 +154,7 @@ int debug_sync_init(void)
DBUG_RETURN(rc); /* purecov: inspected */
/* Set the call back pointer in C files. */
- debug_sync_C_callback_ptr= debug_sync_C_callback;
+ debug_sync_C_callback_ptr= debug_sync;
}
DBUG_RETURN(0);
@@ -1857,12 +1516,14 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
@param[in] name_len length of sync point name
*/
-void debug_sync(THD *thd, const char *sync_point_name, size_t name_len)
+static void debug_sync(THD *thd, const char *sync_point_name, size_t name_len)
{
+ if (!thd)
+ thd= current_thd;
+
st_debug_sync_control *ds_control= thd->debug_sync_control;
st_debug_sync_action *action;
DBUG_ENTER("debug_sync");
- DBUG_ASSERT(thd);
DBUG_ASSERT(sync_point_name);
DBUG_ASSERT(name_len);
DBUG_ASSERT(ds_control);
diff --git a/sql/debug_sync.h b/sql/debug_sync.h
index 50881f491fe..4d29d6e7508 100644
--- a/sql/debug_sync.h
+++ b/sql/debug_sync.h
@@ -32,15 +32,6 @@ class THD;
#if defined(ENABLED_DEBUG_SYNC)
-/* Macro to be put in the code at synchronization points. */
-#define DEBUG_SYNC(_thd_, _sync_point_name_) \
- do { if (unlikely(opt_debug_sync_timeout)) \
- debug_sync(_thd_, STRING_WITH_LEN(_sync_point_name_)); \
- } while (0)
-
-/* Command line option --debug-sync-timeout. See mysqld.cc. */
-extern MYSQL_PLUGIN_IMPORT uint opt_debug_sync_timeout;
-
/* Default WAIT_FOR timeout if command line option is given without argument. */
#define DEBUG_SYNC_DEFAULT_WAIT_TIMEOUT 300
@@ -49,13 +40,8 @@ extern int debug_sync_init(void);
extern void debug_sync_end(void);
extern void debug_sync_init_thread(THD *thd);
extern void debug_sync_end_thread(THD *thd);
-extern void debug_sync(THD *thd, const char *sync_point_name, size_t name_len);
extern bool debug_sync_set_action(THD *thd, const char *action_str, size_t len);
-#else /* defined(ENABLED_DEBUG_SYNC) */
-
-#define DEBUG_SYNC(_thd_, _sync_point_name_) /* disabled DEBUG_SYNC */
-
#endif /* defined(ENABLED_DEBUG_SYNC) */
#endif /* DEBUG_SYNC_INCLUDED */
diff --git a/sql/field.cc b/sql/field.cc
index 34cb81f9d66..5975759f51d 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -7876,8 +7876,7 @@ String *Field_set::val_str(String *val_buffer,
ulonglong tmp=(ulonglong) Field_enum::val_int();
uint bitnr=0;
- val_buffer->length(0);
- val_buffer->set_charset(field_charset);
+ val_buffer->set("", 0, field_charset);
while (tmp && bitnr < (uint) typelib->count)
{
if (tmp & 1)
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 2ef9a48e6a2..03379f2738a 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2000, 2011, Oracle and/or its affiliates.
+ Copyright (c) 2000, 2011, Oracle and/or its affiliates.
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
@@ -44,13 +44,11 @@ if (my_b_write((file),(uchar*) (from),param->ref_length)) \
/* functions defined in this file */
-static char **make_char_array(char **old_pos, register uint fields,
- uint length, myf my_flag);
static uchar *read_buffpek_from_file(IO_CACHE *buffer_file, uint count,
uchar *buf);
static ha_rows find_all_keys(SORTPARAM *param,SQL_SELECT *select,
- uchar * *sort_keys, IO_CACHE *buffer_file,
- IO_CACHE *tempfile,IO_CACHE *indexfile);
+ uchar * *sort_keys, uchar *sort_keys_buf,
+ IO_CACHE *buffer_file, IO_CACHE *tempfile);
static int write_keys(SORTPARAM *param,uchar * *sort_keys,
uint count, IO_CACHE *buffer_file, IO_CACHE *tempfile);
static void make_sortkey(SORTPARAM *param,uchar *to, uchar *ref_pos);
@@ -86,8 +84,6 @@ static void unpack_addon_fields(struct st_sort_addon_field *addon_field,
(Needed by UPDATE/INSERT or ALTER TABLE)
@param examined_rows Store number of examined rows here
- @todo
- check why we do this (param.keys--)
@note
If we sort by position (like if sort_positions is 1) filesort() will
call table->prepare_for_position().
@@ -105,12 +101,13 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
bool sort_positions, ha_rows *examined_rows)
{
int error;
- ulong memavl, min_sort_memory;
+ ulong memory_available= thd->variables.sortbuff_size;
+ ulong min_sort_memory;
uint maxbuffer;
BUFFPEK *buffpek;
- ha_rows records= HA_POS_ERROR;
+ ha_rows num_rows= HA_POS_ERROR;
uchar **sort_keys= 0;
- IO_CACHE tempfile, buffpek_pointers, *selected_records_file, *outfile;
+ IO_CACHE tempfile, buffpek_pointers, *outfile;
SORTPARAM param;
bool multi_byte_charset;
DBUG_ENTER("filesort");
@@ -183,75 +180,67 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
param.max_rows= max_rows;
if (select && select->quick)
- {
status_var_increment(thd->status_var.filesort_range_count);
- }
else
- {
status_var_increment(thd->status_var.filesort_scan_count);
- }
thd->query_plan_flags|= QPLAN_FILESORT;
-#ifdef CAN_TRUST_RANGE
- if (select && select->quick && select->quick->records > 0L)
- {
- records=min((ha_rows) (select->quick->records*2+EXTRA_RECORDS*2),
- table->file->stats.records)+EXTRA_RECORDS;
- selected_records_file=0;
- }
- else
-#endif
- {
- records= table->file->estimate_rows_upper_bound();
- /*
- If number of records is not known, use as much of sort buffer
- as possible.
- */
- if (records == HA_POS_ERROR)
- records--; // we use 'records+1' below.
- selected_records_file= 0;
- }
+
+ // If number of rows is not known, use as much of sort buffer as possible.
+ num_rows= table->file->estimate_rows_upper_bound();
if (multi_byte_charset &&
!(param.tmp_buffer= (char*) my_malloc(param.sort_length,MYF(MY_WME))))
goto err;
- memavl= thd->variables.sortbuff_size;
- min_sort_memory= max(MIN_SORT_MEMORY, param.sort_length*MERGEBUFF2);
- while (memavl >= min_sort_memory)
+ min_sort_memory= max(MIN_SORT_MEMORY, param.sort_length * MERGEBUFF2);
+ if (!table_sort.sort_keys)
{
- ulong old_memavl;
- ulong keys= memavl/(param.rec_length+sizeof(char*));
- param.keys=(uint) min(records+1, keys);
- if ((table_sort.sort_keys=
- (uchar **) make_char_array((char **) table_sort.sort_keys,
- param.keys, param.rec_length, MYF(0))))
- break;
- old_memavl=memavl;
- if ((memavl=memavl/4*3) < min_sort_memory && old_memavl > min_sort_memory)
- memavl= min_sort_memory;
+ while (memory_available >= min_sort_memory)
+ {
+ ulong keys= memory_available / (param.rec_length + sizeof(char*));
+ table_sort.keys= (uint) min(num_rows, keys);
+
+ DBUG_EXECUTE_IF("make_sort_keys_alloc_fail",
+ DBUG_SET("+d,simulate_out_of_memory"););
+
+ if ((table_sort.sort_keys=
+ (uchar**) my_malloc(table_sort.keys*(param.rec_length+sizeof(char*)),
+ MYF(0))))
+ break;
+ ulong old_memory_available= memory_available;
+ memory_available= memory_available/4*3;
+ if (memory_available < min_sort_memory &&
+ old_memory_available > min_sort_memory)
+ memory_available= min_sort_memory;
+ }
}
+
sort_keys= table_sort.sort_keys;
- if (memavl < min_sort_memory)
+ param.keys= table_sort.keys;
+ if (memory_available < min_sort_memory)
{
- my_error(ER_OUT_OF_SORTMEMORY,MYF(ME_ERROR+ME_WAITTANG));
+ my_error(ER_OUT_OF_SORTMEMORY,MYF(ME_ERROR + ME_FATALERROR));
goto err;
}
if (open_cached_file(&buffpek_pointers,mysql_tmpdir,TEMP_PREFIX,
DISK_BUFFER_SIZE, MYF(ME_ERROR | MY_WME)))
goto err;
- param.keys--; /* TODO: check why we do this */
param.sort_form= table;
param.end=(param.local_sortorder=sortorder)+s_length;
- if ((records=find_all_keys(&param,select,sort_keys, &buffpek_pointers,
- &tempfile, selected_records_file)) ==
- HA_POS_ERROR)
+ num_rows= find_all_keys(&param,
+ select,
+ sort_keys,
+ (uchar *)(sort_keys+param.keys),
+ &buffpek_pointers,
+ &tempfile);
+ if (num_rows == HA_POS_ERROR)
goto err;
maxbuffer= (uint) (my_b_tell(&buffpek_pointers)/sizeof(*buffpek));
if (maxbuffer == 0) // The whole set is in memory
{
- if (save_index(&param,sort_keys,(uint) records, &table_sort))
+ if (save_index(&param,sort_keys,(uint) num_rows, &table_sort))
goto err;
}
else
@@ -285,8 +274,9 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
Use also the space previously used by string pointers in sort_buffer
for temporary key storage.
*/
- param.keys=((param.keys*(param.rec_length+sizeof(char*))) /
- param.rec_length-1);
+ param.keys=((param.keys *
+ (param.rec_length+sizeof(char*))) /
+ param.rec_length - 1);
maxbuffer--; // Offset from 0
if (merge_many_buff(&param,(uchar*) sort_keys,buffpek,&maxbuffer,
&tempfile))
@@ -294,13 +284,21 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
if (flush_io_cache(&tempfile) ||
reinit_io_cache(&tempfile,READ_CACHE,0L,0,0))
goto err;
- if (merge_index(&param,(uchar*) sort_keys,buffpek,maxbuffer,&tempfile,
+ if (merge_index(&param,
+ (uchar*) sort_keys,
+ buffpek,
+ maxbuffer,
+ &tempfile,
outfile))
goto err;
}
- if (records > param.max_rows)
- records=param.max_rows;
- error =0;
+
+ if (num_rows > param.max_rows)
+ {
+ // If find_all_keys() produced more results than the query LIMIT.
+ num_rows= param.max_rows;
+ }
+ error= 0;
err:
my_free(param.tmp_buffer);
@@ -349,15 +347,15 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
}
else
statistic_add(thd->status_var.filesort_rows,
- (ulong) records, &LOCK_status);
+ (ulong) num_rows, &LOCK_status);
*examined_rows= param.examined_rows;
#ifdef SKIP_DBUG_IN_FILESORT
DBUG_POP(); /* Ok to DBUG */
#endif
memcpy(&table->sort, &table_sort, sizeof(FILESORT_INFO));
- DBUG_PRINT("exit",("records: %ld", (long) records));
- MYSQL_FILESORT_DONE(error, records);
- DBUG_RETURN(error ? HA_POS_ERROR : records);
+ DBUG_PRINT("exit",("num_rows: %ld", (long) num_rows));
+ MYSQL_FILESORT_DONE(error, num_rows);
+ DBUG_RETURN(error ? HA_POS_ERROR : num_rows);
} /* filesort */
@@ -381,29 +379,6 @@ void filesort_free_buffers(TABLE *table, bool full)
table->sort.addon_field= NULL;
}
-/** Make a array of string pointers. */
-
-static char **make_char_array(char **old_pos, register uint fields,
- uint length, myf my_flag)
-{
- register char **pos;
- char *char_pos;
- DBUG_ENTER("make_char_array");
-
- DBUG_EXECUTE_IF("make_char_array_fail",
- DBUG_SET("+d,simulate_out_of_memory"););
-
- if (old_pos ||
- (old_pos= (char**) my_malloc((uint) fields*(length+sizeof(char*)),
- my_flag)))
- {
- pos=old_pos; char_pos=((char*) (pos+fields)) -length;
- while (fields--) *(pos++) = (char_pos+= length);
- }
-
- DBUG_RETURN(old_pos);
-} /* make_char_array */
-
/** Read 'count' number of buffer pointers into memory. */
@@ -490,7 +465,6 @@ static void dbug_print_record(TABLE *table, bool print_rowid)
@param buffpek_pointers File to write BUFFPEKs describing sorted segments
in tempfile.
@param tempfile File to write sorted sequences of sortkeys to.
- @param indexfile If !NULL, use it for source data (contains rowids)
@note
Basic idea:
@@ -518,9 +492,9 @@ static void dbug_print_record(TABLE *table, bool print_rowid)
*/
static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
- uchar **sort_keys,
+ uchar **sort_keys, uchar *sort_keys_buf,
IO_CACHE *buffpek_pointers,
- IO_CACHE *tempfile, IO_CACHE *indexfile)
+ IO_CACHE *tempfile)
{
int error,flag,quick_select;
uint idx,indexpos,ref_length;
@@ -531,6 +505,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
volatile killed_state *killed= &thd->killed;
handler *file;
MY_BITMAP *save_read_set, *save_write_set, *save_vcol_set;
+ uchar *next_sort_key= sort_keys_buf;
DBUG_ENTER("find_all_keys");
DBUG_PRINT("info",("using: %s",
(select ? select->quick ? "ranges" : "where":
@@ -544,12 +519,11 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
ref_pos= ref_buff;
quick_select=select && select->quick;
record=0;
- flag= ((!indexfile && (file->ha_table_flags() & HA_REC_NOT_IN_SEQ))
- || quick_select);
- if (indexfile || flag)
+ flag= ((file->ha_table_flags() & HA_REC_NOT_IN_SEQ) || quick_select);
+ if (flag)
ref_pos= &file->ref[0];
next_pos=ref_pos;
- if (! indexfile && ! quick_select)
+ if (!quick_select)
{
next_pos=(uchar*) 0; /* Find records in sequence */
if (file->ha_rnd_init_with_error(1))
@@ -589,26 +563,16 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
{
if ((error= select->quick->get_next()))
break;
- if (!error)
+ if (!error && sort_form->vfield)
update_virtual_fields(thd, sort_form);
file->position(sort_form->record[0]);
DBUG_EXECUTE_IF("debug_filesort", dbug_print_record(sort_form, TRUE););
}
else /* Not quick-select */
{
- if (indexfile)
{
- if (my_b_read(indexfile,(uchar*) ref_pos,ref_length)) /* purecov: deadcode */
- {
- error= my_errno ? my_errno : -1; /* Abort */
- break;
- }
- error=file->ha_rnd_pos(sort_form->record[0],next_pos);
- }
- else
- {
- error=file->ha_rnd_next(sort_form->record[0]);
- if (!error)
+ error= file->ha_rnd_next(sort_form->record[0]);
+ if (!error && sort_form->vfield)
update_virtual_fields(thd, sort_form);
if (!flag)
{
@@ -625,7 +589,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
if (*killed)
{
DBUG_PRINT("info",("Sort killed by user"));
- if (!indexfile && !quick_select)
+ if (!quick_select)
{
(void) file->extra(HA_EXTRA_NO_CACHE);
file->ha_rnd_end();
@@ -669,12 +633,16 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
{
if (idx == param->keys)
{
- if (write_keys(param,sort_keys,idx,buffpek_pointers,tempfile))
+ if (write_keys(param, sort_keys,
+ idx, buffpek_pointers, tempfile))
DBUG_RETURN(HA_POS_ERROR);
- idx=0;
+ idx= 0;
+ next_sort_key= sort_keys_buf;
indexpos++;
}
- make_sortkey(param,sort_keys[idx++],ref_pos);
+ sort_keys[idx++]= next_sort_key;
+ make_sortkey(param, next_sort_key, ref_pos);
+ next_sort_key+= param->rec_length;
}
else
file->unlock_row();
@@ -699,15 +667,17 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
DBUG_PRINT("test",("error: %d indexpos: %d",error,indexpos));
if (error != HA_ERR_END_OF_FILE)
{
- file->print_error(error,MYF(ME_ERROR | ME_WAITTANG)); /* purecov: inspected */
+ file->print_error(error,MYF(ME_ERROR | ME_WAITTANG)); // purecov: inspected
DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */
}
if (indexpos && idx &&
- write_keys(param,sort_keys,idx,buffpek_pointers,tempfile))
+ write_keys(param, sort_keys,
+ idx, buffpek_pointers, tempfile))
DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */
- DBUG_RETURN(my_b_inited(tempfile) ?
- (ha_rows) (my_b_tell(tempfile)/param->rec_length) :
- idx);
+ const ha_rows retval=
+ my_b_inited(tempfile) ?
+ (ha_rows) (my_b_tell(tempfile)/param->rec_length) : idx;
+ DBUG_RETURN(retval);
} /* find_all_keys */
@@ -1310,8 +1280,9 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
{
buffpek->base= strpos;
buffpek->max_keys= maxcount;
- strpos+= (uint) (error= (int) read_to_buffer(from_file, buffpek,
- rec_length));
+ strpos+=
+ (uint) (error= (int) read_to_buffer(from_file, buffpek, rec_length));
+
if (error == -1)
goto err; /* purecov: inspected */
buffpek->max_keys= buffpek->mem_count; // If less data in buffers than expected
diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h
index f3c9553f524..70e1e9dc7cf 100644
--- a/sql/ha_ndbcluster.h
+++ b/sql/ha_ndbcluster.h
@@ -1,8 +1,7 @@
#ifndef HA_NDBCLUSTER_INCLUDED
#define HA_NDBCLUSTER_INCLUDED
-/* Copyright (c) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc.
- Use is subject to license terms.
+/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
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_ndbcluster_binlog.h b/sql/ha_ndbcluster_binlog.h
index 1cc20c954cb..a02f687d76f 100644
--- a/sql/ha_ndbcluster_binlog.h
+++ b/sql/ha_ndbcluster_binlog.h
@@ -1,8 +1,7 @@
#ifndef HA_NDBCLUSTER_BINLOG_INCLUDED
#define HA_NDBCLUSTER_BINLOG_INCLUDED
-/* Copyright (c) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc.
- Use is subject to license terms.
+/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
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 36d5da94b11..b4181fc6d7f 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2005, 2011, Oracle and/or its affiliates.
+ Copyright (c) 2005, 2012, Oracle and/or its affiliates.
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
@@ -289,6 +289,7 @@ void ha_partition::init_handler_variables()
m_is_sub_partitioned= 0;
m_is_clone_of= NULL;
m_clone_mem_root= NULL;
+ m_part_ids_sorted_by_num_of_records= NULL;
#ifdef DONT_HAVE_TO_BE_INITALIZED
m_start_key.flag= 0;
@@ -325,6 +326,7 @@ ha_partition::~ha_partition()
}
my_free(m_ordered_rec_buffer);
m_ordered_rec_buffer= NULL;
+ my_free(m_part_ids_sorted_by_num_of_records);
clear_handler_file();
@@ -1259,7 +1261,7 @@ bool ha_partition::check_and_repair(THD *thd)
@retval FALSE Cannot be auto repaired
*/
-bool ha_partition::auto_repair() const
+bool ha_partition::auto_repair(int error) const
{
DBUG_ENTER("ha_partition::auto_repair");
@@ -1267,7 +1269,7 @@ bool ha_partition::auto_repair() const
As long as we only support one storage engine per table,
we can use the first partition for this function.
*/
- DBUG_RETURN(m_file[0]->auto_repair());
+ DBUG_RETURN(m_file[0]->auto_repair(error));
}
@@ -2741,6 +2743,16 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
m_start_key.key= (const uchar*)ptr;
}
}
+ if (!m_part_ids_sorted_by_num_of_records)
+ {
+ if (!(m_part_ids_sorted_by_num_of_records=
+ (uint32*) my_malloc(m_tot_parts * sizeof(uint32), MYF(MY_WME))))
+ DBUG_RETURN(error);
+ uint32 i;
+ /* Initialize it with all partition ids. */
+ for (i= 0; i < m_tot_parts; i++)
+ m_part_ids_sorted_by_num_of_records[i]= i;
+ }
/* Initialize the bitmap we use to minimize ha_start_bulk_insert calls */
if (bitmap_init(&m_bulk_insert_started, NULL, m_tot_parts + 1, FALSE))
@@ -3670,14 +3682,14 @@ int ha_partition::truncate_partition(Alter_info *alter_info, bool *binlog_stmt)
uint num_parts= m_part_info->num_parts;
uint num_subparts= m_part_info->num_subparts;
uint i= 0;
- uint num_parts_set= alter_info->partition_names.elements;
- uint num_parts_found= set_part_state(alter_info, m_part_info,
- PART_ADMIN);
DBUG_ENTER("ha_partition::truncate_partition");
/* Only binlog when it starts any call to the partitions handlers */
*binlog_stmt= false;
+ if (set_part_state(alter_info, m_part_info, PART_ADMIN))
+ DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);
+
/*
TRUNCATE also means resetting auto_increment. Hence, reset
it so that it will be initialized again at the next use.
@@ -3687,10 +3699,6 @@ int ha_partition::truncate_partition(Alter_info *alter_info, bool *binlog_stmt)
table_share->ha_part_data->auto_inc_initialized= FALSE;
unlock_auto_increment();
- if (num_parts_set != num_parts_found &&
- (!(alter_info->flags & ALTER_ALL_PARTITION)))
- DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);
-
*binlog_stmt= true;
do
@@ -5318,6 +5326,24 @@ int ha_partition::handle_ordered_prev(uchar *buf)
and read_time calls
*/
+/**
+ Helper function for sorting according to number of rows in descending order.
+*/
+
+int ha_partition::compare_number_of_records(ha_partition *me,
+ const uint32 *a,
+ const uint32 *b)
+{
+ handler **file= me->m_file;
+ /* Note: sorting in descending order! */
+ if (file[*a]->stats.records > file[*b]->stats.records)
+ return -1;
+ if (file[*a]->stats.records < file[*b]->stats.records)
+ return 1;
+ return 0;
+}
+
+
/*
General method to gather info from handler
@@ -5562,6 +5588,15 @@ int ha_partition::info(uint flag)
}
i++;
} while (*(++file_array));
+ /*
+ Sort the array of part_ids by number of records in
+ in descending order.
+ */
+ my_qsort2((void*) m_part_ids_sorted_by_num_of_records,
+ m_tot_parts,
+ sizeof(uint32),
+ (qsort2_cmp) compare_number_of_records,
+ this);
file= m_file[handler_instance];
file->info(HA_STATUS_CONST | no_lock_flag);
@@ -6099,7 +6134,7 @@ int ha_partition::extra(enum ha_extra_function operation)
0 Success
DESCRIPTION
- Called at end of each statement to reste buffers
+ Called at end of each statement to reset buffers
*/
int ha_partition::reset(void)
@@ -6317,21 +6352,73 @@ const key_map *ha_partition::keys_to_use_for_scanning()
DBUG_RETURN(m_file[0]->keys_to_use_for_scanning());
}
-#define MAX_PARTS_FOR_OPTIMIZER_CALLS 10
-/*
- Prepare start variables for estimating optimizer costs.
- @param[out] num_used_parts Number of partitions after pruning.
- @param[out] check_min_num Number of partitions to call.
- @param[out] first first used partition.
+/**
+ Minimum number of rows to base optimizer estimate on.
*/
-void ha_partition::partitions_optimizer_call_preparations(uint *first,
- uint *num_used_parts,
- uint *check_min_num)
+
+ha_rows ha_partition::min_rows_for_estimate()
{
- *first= bitmap_get_first_set(&(m_part_info->used_partitions));
- *num_used_parts= bitmap_bits_set(&(m_part_info->used_partitions));
- *check_min_num= min(MAX_PARTS_FOR_OPTIMIZER_CALLS, *num_used_parts);
+ uint i, max_used_partitions, tot_used_partitions;
+ DBUG_ENTER("ha_partition::min_rows_for_estimate");
+
+ tot_used_partitions= bitmap_bits_set(&m_part_info->used_partitions);
+ DBUG_ASSERT(tot_used_partitions);
+
+ /*
+ Allow O(log2(tot_partitions)) increase in number of used partitions.
+ This gives O(tot_rows/log2(tot_partitions)) rows to base the estimate on.
+ I.e when the total number of partitions doubles, allow one more
+ partition to be checked.
+ */
+ i= 2;
+ max_used_partitions= 1;
+ while (i < m_tot_parts)
+ {
+ max_used_partitions++;
+ i= i << 1;
+ }
+ if (max_used_partitions > tot_used_partitions)
+ max_used_partitions= tot_used_partitions;
+
+ /* stats.records is already updated by the info(HA_STATUS_VARIABLE) call. */
+ DBUG_PRINT("info", ("max_used_partitions: %u tot_rows: %lu",
+ max_used_partitions,
+ (ulong) stats.records));
+ DBUG_PRINT("info", ("tot_used_partitions: %u min_rows_to_check: %lu",
+ tot_used_partitions,
+ (ulong) stats.records * max_used_partitions
+ / tot_used_partitions));
+ DBUG_RETURN(stats.records * max_used_partitions / tot_used_partitions);
+}
+
+
+/**
+ Get the biggest used partition.
+
+ Starting at the N:th biggest partition and skips all non used
+ partitions, returning the biggest used partition found
+
+ @param[in,out] part_index Skip the *part_index biggest partitions
+
+ @return The biggest used partition with index not lower than *part_index.
+ @retval NO_CURRENT_PART_ID No more partition used.
+ @retval != NO_CURRENT_PART_ID partition id of biggest used partition with
+ index >= *part_index supplied. Note that
+ *part_index will be updated to the next
+ partition index to use.
+*/
+
+uint ha_partition::get_biggest_used_partition(uint *part_index)
+{
+ uint part_id;
+ while ((*part_index) < m_tot_parts)
+ {
+ part_id= m_part_ids_sorted_by_num_of_records[(*part_index)++];
+ if (bitmap_is_set(&m_part_info->used_partitions, part_id))
+ return part_id;
+ }
+ return NO_CURRENT_PART_ID;
}
@@ -6347,115 +6434,107 @@ void ha_partition::partitions_optimizer_call_preparations(uint *first,
double ha_partition::scan_time()
{
- double scan_time= 0.0;
- uint first, part_id, num_used_parts, check_min_num, partitions_called= 0;
+ double scan_time= 0;
+ handler **file;
DBUG_ENTER("ha_partition::scan_time");
- partitions_optimizer_call_preparations(&first, &num_used_parts, &check_min_num);
- for (part_id= first; partitions_called < num_used_parts ; part_id++)
- {
- if (!bitmap_is_set(&(m_part_info->used_partitions), part_id))
- continue;
- scan_time+= m_file[part_id]->scan_time();
- partitions_called++;
- if (partitions_called >= check_min_num && scan_time != 0.0)
- {
- DBUG_RETURN(scan_time *
- (double) num_used_parts / (double) partitions_called);
- }
- }
+ for (file= m_file; *file; file++)
+ if (bitmap_is_set(&(m_part_info->used_partitions), (file - m_file)))
+ scan_time+= (*file)->scan_time();
DBUG_RETURN(scan_time);
}
-/*
- Estimate rows for records_in_range or estimate_rows_upper_bound.
+/**
+ Find number of records in a range.
+ @param inx Index number
+ @param min_key Start of range
+ @param max_key End of range
- @param is_records_in_range call records_in_range instead of
- estimate_rows_upper_bound.
- @param inx (only for records_in_range) index to use.
- @param min_key (only for records_in_range) start of range.
- @param max_key (only for records_in_range) end of range.
+ @return Number of rows in range.
- @return Number of rows or HA_POS_ERROR.
+ Given a starting key, and an ending key estimate the number of rows that
+ will exist between the two. max_key may be empty which in case determine
+ if start_key matches any rows.
*/
-ha_rows ha_partition::estimate_rows(bool is_records_in_range, uint inx,
- key_range *min_key, key_range *max_key)
+
+ha_rows ha_partition::records_in_range(uint inx, key_range *min_key,
+ key_range *max_key)
{
- ha_rows rows, estimated_rows= 0;
- uint first, part_id, num_used_parts, check_min_num, partitions_called= 0;
+ ha_rows min_rows_to_check, rows, estimated_rows=0, checked_rows= 0;
+ uint partition_index= 0, part_id;
DBUG_ENTER("ha_partition::records_in_range");
- partitions_optimizer_call_preparations(&first, &num_used_parts, &check_min_num);
- for (part_id= first; partitions_called < num_used_parts ; part_id++)
+ min_rows_to_check= min_rows_for_estimate();
+
+ while ((part_id= get_biggest_used_partition(&partition_index))
+ != NO_CURRENT_PART_ID)
{
- if (!bitmap_is_set(&(m_part_info->used_partitions), part_id))
- continue;
- if (is_records_in_range)
- rows= m_file[part_id]->records_in_range(inx, min_key, max_key);
- else
- rows= m_file[part_id]->estimate_rows_upper_bound();
+ rows= m_file[part_id]->records_in_range(inx, min_key, max_key);
+
+ DBUG_PRINT("info", ("part %u match %lu rows of %lu", part_id, (ulong) rows,
+ (ulong) m_file[part_id]->stats.records));
+
if (rows == HA_POS_ERROR)
DBUG_RETURN(HA_POS_ERROR);
estimated_rows+= rows;
- partitions_called++;
- if (partitions_called >= check_min_num && estimated_rows)
+ checked_rows+= m_file[part_id]->stats.records;
+ /*
+ Returning 0 means no rows can be found, so we must continue
+ this loop as long as we have estimated_rows == 0.
+ Also many engines return 1 to indicate that there may exist
+ a matching row, we do not normalize this by dividing by number of
+ used partitions, but leave it to be returned as a sum, which will
+ reflect that we will need to scan each partition's index.
+
+ Note that this statistics may not always be correct, so we must
+ continue even if the current partition has 0 rows, since we might have
+ deleted rows from the current partition, or inserted to the next
+ partition.
+ */
+ if (estimated_rows && checked_rows &&
+ checked_rows >= min_rows_to_check)
{
- DBUG_RETURN(estimated_rows * num_used_parts / partitions_called);
+ DBUG_PRINT("info",
+ ("records_in_range(inx %u): %lu (%lu * %lu / %lu)",
+ inx,
+ (ulong) (estimated_rows * stats.records / checked_rows),
+ (ulong) estimated_rows,
+ (ulong) stats.records,
+ (ulong) checked_rows));
+ DBUG_RETURN(estimated_rows * stats.records / checked_rows);
}
}
+ DBUG_PRINT("info", ("records_in_range(inx %u): %lu",
+ inx,
+ (ulong) estimated_rows));
DBUG_RETURN(estimated_rows);
}
-/*
- Find number of records in a range
-
- SYNOPSIS
- records_in_range()
- inx Index number
- min_key Start of range
- max_key End of range
-
- RETURN VALUE
- Number of rows in range
-
- DESCRIPTION
- Given a starting key, and an ending key estimate the number of rows that
- will exist between the two. end_key may be empty which in case determine
- if start_key matches any rows.
-
- Called from opt_range.cc by check_quick_keys().
-
- monty: MUST be called for each range and added.
- Note that MySQL will assume that if this returns 0 there is no
- matching rows for the range!
-*/
-
-ha_rows ha_partition::records_in_range(uint inx, key_range *min_key,
- key_range *max_key)
-{
- DBUG_ENTER("ha_partition::records_in_range");
-
- DBUG_RETURN(estimate_rows(TRUE, inx, min_key, max_key));
-}
-
-
-/*
- Estimate upper bound of number of rows
-
- SYNOPSIS
- estimate_rows_upper_bound()
+/**
+ Estimate upper bound of number of rows.
- RETURN VALUE
- Number of rows
+ @return Number of rows.
*/
ha_rows ha_partition::estimate_rows_upper_bound()
{
+ ha_rows rows, tot_rows= 0;
+ handler **file= m_file;
DBUG_ENTER("ha_partition::estimate_rows_upper_bound");
- DBUG_RETURN(estimate_rows(FALSE, 0, NULL, NULL));
+ do
+ {
+ if (bitmap_is_set(&(m_part_info->used_partitions), (file - m_file)))
+ {
+ rows= (*file)->estimate_rows_upper_bound();
+ if (rows == HA_POS_ERROR)
+ DBUG_RETURN(HA_POS_ERROR);
+ tot_rows+= rows;
+ }
+ } while (*(++file));
+ DBUG_RETURN(tot_rows);
}
diff --git a/sql/ha_partition.h b/sql/ha_partition.h
index 8723682904a..aa9179f9f69 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -2,7 +2,7 @@
#define HA_PARTITION_INCLUDED
/*
- Copyright (c) 2005, 2011, Oracle and/or its affiliates.
+ Copyright (c) 2005, 2012, Oracle and/or its affiliates.
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
@@ -176,6 +176,12 @@ private:
ha_rows m_bulk_inserted_rows;
/** used for prediction of start_bulk_insert rows */
enum_monotonicity_info m_part_func_monotonicity_info;
+ /** Sorted array of partition ids in descending order of number of rows. */
+ uint32 *m_part_ids_sorted_by_num_of_records;
+ /* Compare function for my_qsort2, for reversed order. */
+ static int compare_number_of_records(ha_partition *me,
+ const uint32 *a,
+ const uint32 *b);
public:
handler *clone(const char *name, MEM_ROOT *mem_root);
virtual void set_part_info(partition_info *part_info)
@@ -196,9 +202,9 @@ public:
*/
ha_partition(handlerton *hton, TABLE_SHARE * table);
ha_partition(handlerton *hton, partition_info * part_info);
- ha_partition(handlerton *hton, TABLE_SHARE *share,
- partition_info *part_info_arg,
- ha_partition *clone_arg,
+ ha_partition(handlerton *hton, TABLE_SHARE *share,
+ partition_info *part_info_arg,
+ ha_partition *clone_arg,
MEM_ROOT *clone_mem_root_arg);
~ha_partition();
/*
@@ -538,6 +544,20 @@ public:
virtual int extra(enum ha_extra_function operation);
virtual int extra_opt(enum ha_extra_function operation, ulong cachesize);
virtual int reset(void);
+ /*
+ Do not allow caching of partitioned tables, since we cannot return
+ a callback or engine_data that would work for a generic engine.
+ */
+ virtual my_bool register_query_cache_table(THD *thd, char *table_key,
+ uint key_length,
+ qc_engine_callback
+ *engine_callback,
+ ulonglong *engine_data)
+ {
+ *engine_callback= NULL;
+ *engine_data= 0;
+ return FALSE;
+ }
private:
static const uint NO_CURRENT_PART_ID;
@@ -567,15 +587,9 @@ public:
*/
private:
- /*
- Helper function to get the minimum number of partitions to use for
- the optimizer hints/cost calls.
- */
- void partitions_optimizer_call_preparations(uint *num_used_parts,
- uint *check_min_num,
- uint *first);
- ha_rows estimate_rows(bool is_records_in_range, uint inx,
- key_range *min_key, key_range *max_key);
+ /* Helper functions for optimizer hints. */
+ ha_rows min_rows_for_estimate();
+ uint get_biggest_used_partition(uint *part_index);
public:
/*
@@ -1085,7 +1099,7 @@ public:
virtual int check(THD* thd, HA_CHECK_OPT *check_opt);
virtual int repair(THD* thd, HA_CHECK_OPT *check_opt);
virtual bool check_and_repair(THD *thd);
- virtual bool auto_repair() const;
+ virtual bool auto_repair(int error) const;
virtual bool is_crashed() const;
private:
diff --git a/sql/handler.cc b/sql/handler.cc
index 0310180759c..cdc367bbb18 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -1185,7 +1185,7 @@ int ha_commit_trans(THD *thd, bool all)
}
#ifdef WITH_ARIA_STORAGE_ENGINE
- ha_maria::implicit_commit(thd, FALSE);
+ ha_maria::implicit_commit(thd, TRUE);
#endif
if (!ha_info)
diff --git a/sql/handler.h b/sql/handler.h
index d56e3242ddd..f118f1d3c5b 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -2446,7 +2446,7 @@ public:
virtual uint checksum() const { return 0; }
virtual bool is_crashed() const { return 0; }
- virtual bool auto_repair() const { return 0; }
+ virtual bool auto_repair(int error) const { return 0; }
void update_global_table_stats();
void update_global_index_stats();
diff --git a/sql/item.cc b/sql/item.cc
index c4bb1a399ab..f9032c79c12 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2000, 2011, Oracle and/or its affiliates.
+ Copyright (c) 2000, 2012, Oracle and/or its affiliates.
Copyright (c) 2010, 2012, Monty Program Ab
This program is free software; you can redistribute it and/or modify
@@ -1001,6 +1001,21 @@ void Item::set_name(const char *str, uint length, CHARSET_INFO *cs)
}
+void Item::set_name_for_rollback(THD *thd, const char *str, uint length,
+ CHARSET_INFO *cs)
+{
+ char *old_name, *new_name;
+ old_name= name;
+ set_name(str, length, cs);
+ new_name= name;
+ if (old_name != new_name)
+ {
+ name= old_name;
+ thd->change_item_tree((Item **) &name, (Item *) new_name);
+ }
+}
+
+
/**
@details
This function is called when:
@@ -2606,17 +2621,20 @@ void Item_field::fix_after_pullout(st_select_lex *new_parent, Item **ref)
{
if (new_parent == get_depended_from())
depended_from= NULL;
- Name_resolution_context *ctx= new Name_resolution_context();
- ctx->outer_context= NULL; // We don't build a complete name resolver
- ctx->table_list= NULL; // We rely on first_name_resolution_table instead
- ctx->select_lex= new_parent;
- ctx->first_name_resolution_table= context->first_name_resolution_table;
- ctx->last_name_resolution_table= context->last_name_resolution_table;
- ctx->error_processor= context->error_processor;
- ctx->error_processor_data= context->error_processor_data;
- ctx->resolve_in_select_list= context->resolve_in_select_list;
- ctx->security_ctx= context->security_ctx;
- this->context=ctx;
+ if (context)
+ {
+ Name_resolution_context *ctx= new Name_resolution_context();
+ ctx->outer_context= NULL; // We don't build a complete name resolver
+ ctx->table_list= NULL; // We rely on first_name_resolution_table instead
+ ctx->select_lex= new_parent;
+ ctx->first_name_resolution_table= context->first_name_resolution_table;
+ ctx->last_name_resolution_table= context->last_name_resolution_table;
+ ctx->error_processor= context->error_processor;
+ ctx->error_processor_data= context->error_processor_data;
+ ctx->resolve_in_select_list= context->resolve_in_select_list;
+ ctx->security_ctx= context->security_ctx;
+ this->context=ctx;
+ }
}
@@ -3557,7 +3575,7 @@ String *Item_param::val_str(String* str)
that binary log contains wrong statement
*/
-const String *Item_param::query_val_str(String* str) const
+const String *Item_param::query_val_str(THD *thd, String* str) const
{
switch (state) {
case INT_VALUE:
@@ -3595,7 +3613,8 @@ const String *Item_param::query_val_str(String* str) const
case LONG_DATA_VALUE:
{
str->length(0);
- append_query_string(value.cs_info.character_set_client, &str_value, str);
+ append_query_string(thd, value.cs_info.character_set_client, &str_value,
+ str);
break;
}
case NULL_VALUE:
@@ -3728,7 +3747,7 @@ void Item_param::print(String *str, enum_query_type query_type)
char buffer[STRING_BUFFER_USUAL_SIZE];
String tmp(buffer, sizeof(buffer), &my_charset_bin);
const String *res;
- res= query_val_str(&tmp);
+ res= query_val_str(current_thd, &tmp);
str->append(*res);
}
}
diff --git a/sql/item.h b/sql/item.h
index cf13f501c69..b3801e6c488 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -656,6 +656,8 @@ public:
#endif
} /*lint -e1509 */
void set_name(const char *str, uint length, CHARSET_INFO *cs);
+ void set_name_for_rollback(THD *thd, const char *str, uint length,
+ CHARSET_INFO *cs);
void rename(char *new_name);
void init_make_field(Send_field *tmp_field,enum enum_field_types type);
virtual void cleanup();
@@ -2258,7 +2260,7 @@ public:
*/
void (*set_param_func)(Item_param *param, uchar **pos, ulong len);
- const String *query_val_str(String *str) const;
+ const String *query_val_str(THD *thd, String *str) const;
bool convert_str_value(THD *thd);
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index f5dc74c389c..d3251bc1fb3 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -5463,7 +5463,7 @@ Item *Item_bool_rowready_func2::negated_item()
*/
Item_equal::Item_equal(Item *f1, Item *f2, bool with_const_item)
- : Item_bool_func(), eval_item(0), cond_false(0)
+ : Item_bool_func(), eval_item(0), cond_false(0), context_field(NULL)
{
const_item_cache= 0;
with_const= with_const_item;
@@ -5486,7 +5486,7 @@ Item_equal::Item_equal(Item *f1, Item *f2, bool with_const_item)
*/
Item_equal::Item_equal(Item_equal *item_equal)
- : Item_bool_func(), eval_item(0), cond_false(0)
+ : Item_bool_func(), eval_item(0), cond_false(0), context_field(NULL)
{
const_item_cache= 0;
List_iterator_fast<Item> li(item_equal->equal_items);
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 384c91d5d2e..5558b77d67d 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -1,7 +1,7 @@
#ifndef ITEM_CMPFUNC_INCLUDED
#define ITEM_CMPFUNC_INCLUDED
-/* Copyright (c) 2000, 2010, Oracle and/or its affiliates.
- Copyright (c) 2009-2011, Monty Program Ab
+/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2011, 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
@@ -249,7 +249,7 @@ public:
Item_in_optimizer(Item *a, Item_in_subselect *b):
Item_bool_func(a, reinterpret_cast<Item *>(b)), cache(0), expr_cache(0),
save_cache(0), result_for_null_param(UNKNOWN)
- {}
+ { with_subselect= true; }
bool fix_fields(THD *, Item **);
bool fix_left(THD *thd, Item **ref);
bool is_null();
@@ -1693,9 +1693,16 @@ class Item_equal: public Item_bool_func
as datetimes. The comparator is used only if compare_as_dates=TRUE
*/
Arg_comparator cmp;
+
+ /*
+ For Item_equal objects inside an OR clause: one of the fields that were
+ used in the original equality.
+ */
+ Item_field *context_field;
public:
inline Item_equal()
- : Item_bool_func(), with_const(FALSE), eval_item(0), cond_false(0)
+ : Item_bool_func(), with_const(FALSE), eval_item(0), cond_false(0),
+ context_field(NULL)
{ const_item_cache=0 ;}
Item_equal(Item *f1, Item *f2, bool with_const_item);
Item_equal(Item_equal *item_equal);
@@ -1722,6 +1729,8 @@ public:
Item *transform(Item_transformer transformer, uchar *arg);
virtual void print(String *str, enum_query_type query_type);
CHARSET_INFO *compare_collation();
+
+ void set_context_field(Item_field *ctx_field) { context_field= ctx_field; }
friend class Item_equal_fields_iterator;
friend Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
Item_equal *item_equal);
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 92431a552c4..9b2e8e5e614 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -6733,7 +6733,7 @@ Item_func_sp::fix_fields(THD *thd, Item **ref)
if (res)
DBUG_RETURN(res);
- if (thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW)
+ if (thd->lex->is_view_context_analysis())
{
/*
Here we check privileges of the stored routine only during view
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index d5f85e7ff5d..b1829c1892a 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -2508,7 +2508,7 @@ bool Item_in_subselect::fix_fields(THD *thd_arg, Item **ref)
}
}
- if ((thd_arg->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW) &&
+ if (thd_arg->lex->is_view_context_analysis() &&
left_expr && !left_expr->fixed &&
left_expr->fix_fields(thd_arg, &left_expr))
return TRUE;
@@ -2531,7 +2531,8 @@ void Item_in_subselect::update_used_tables()
{
Item_subselect::update_used_tables();
left_expr->update_used_tables();
- used_tables_cache |= left_expr->used_tables();
+ //used_tables_cache |= left_expr->used_tables();
+ used_tables_cache= Item_subselect::used_tables() | left_expr->used_tables();
}
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 80914f499fe..857d9bc2080 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -1,6 +1,6 @@
/*
- Copyright (c) 2000, 2011, Oracle and/or its affiliates.
- Copyright (c) 2009-2011, Monty Program Ab
+ Copyright (c) 2000, 2012, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2011, 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
@@ -2435,7 +2435,7 @@ bool Item_time_typecast::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
bool Item_date_typecast::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
{
- if (get_arg0_date(ltime, TIME_FUZZY_DATE))
+ if (get_arg0_date(ltime, fuzzy_date & ~TIME_TIME_ONLY))
return 1;
ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0;
@@ -3145,7 +3145,7 @@ bool Item_func_str_to_date::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
bool Item_func_last_day::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
{
- if (get_arg0_date(ltime, fuzzy_date & ~TIME_FUZZY_DATE) ||
+ if (get_arg0_date(ltime, fuzzy_date) ||
(ltime->month == 0))
return (null_value=1);
uint month_idx= ltime->month-1;
diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc
index 150c2c212d7..0fa2d39aea9 100644
--- a/sql/item_xmlfunc.cc
+++ b/sql/item_xmlfunc.cc
@@ -1,5 +1,4 @@
-/*
- Copyright (c) 2005, 2010, Oracle and/or its affiliates.
+/* Copyright (c) 2005, 2011, Oracle and/or its affiliates.
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/lock.cc b/sql/lock.cc
index a7029548493..c5a4674bfb0 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -399,7 +399,7 @@ void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count)
{
MYSQL_LOCK *sql_lock;
if ((sql_lock= get_lock_data(thd, table, count, GET_LOCK_UNLOCK)))
- mysql_unlock_tables(thd, sql_lock);
+ mysql_unlock_tables(thd, sql_lock, 1);
}
diff --git a/sql/log.cc b/sql/log.cc
index 577297fa1a4..e80a2aaec51 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -3709,8 +3709,6 @@ int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included)
mysql_mutex_lock(&rli->log_space_lock);
rli->relay_log.purge_logs(to_purge_if_included, included,
0, 0, &rli->log_space_total);
- // Tell the I/O thread to take the relay_log_space_limit into account
- rli->ignore_log_space_limit= 0;
mysql_mutex_unlock(&rli->log_space_lock);
/*
diff --git a/sql/log_event.cc b/sql/log_event.cc
index cec0785a088..f8fdbae6214 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -629,7 +629,7 @@ char *str_to_hex(char *to, const char *from, uint len)
*/
int
-append_query_string(CHARSET_INFO *csinfo,
+append_query_string(THD *thd, CHARSET_INFO *csinfo,
String const *from, String *to)
{
char *beg, *ptr;
@@ -644,9 +644,26 @@ append_query_string(CHARSET_INFO *csinfo,
else
{
*ptr++= '\'';
- ptr+= escape_string_for_mysql(csinfo, ptr, 0,
- from->ptr(), from->length());
- *ptr++='\'';
+ if (!(thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES))
+ {
+ ptr+= escape_string_for_mysql(csinfo, ptr, 0,
+ from->ptr(), from->length());
+ }
+ else
+ {
+ const char *frm_str= from->ptr();
+
+ for (; frm_str < (from->ptr() + from->length()); frm_str++)
+ {
+ /* Using '' way to represent "'" */
+ if (*frm_str == '\'')
+ *ptr++= *frm_str;
+
+ *ptr++= *frm_str;
+ }
+ }
+
+ *ptr++= '\'';
}
to->length(orig_len + ptr - beg);
return 0;
diff --git a/sql/log_event.h b/sql/log_event.h
index de9cd65514c..78dccb3cac1 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -1,5 +1,4 @@
-/*
- Copyright (c) 2000, 2010, Oracle and/or its affiliates.
+/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
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
@@ -4261,7 +4260,7 @@ private:
};
#endif
-int append_query_string(CHARSET_INFO *csinfo,
+int append_query_string(THD *thd, CHARSET_INFO *csinfo,
String const *from, String *to);
bool rpl_get_position_info(const char **log_file_name, ulonglong *log_pos,
diff --git a/sql/mem_root_array.h b/sql/mem_root_array.h
new file mode 100644
index 00000000000..5ce4dcb584d
--- /dev/null
+++ b/sql/mem_root_array.h
@@ -0,0 +1,175 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+ 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
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#ifndef MEM_ROOT_ARRAY_INCLUDED
+#define MEM_ROOT_ARRAY_INCLUDED
+
+#include <my_alloc.h>
+
+/**
+ A typesafe replacement for DYNAMIC_ARRAY.
+ We use MEM_ROOT for allocating storage, rather than the C++ heap.
+ The interface is chosen to be similar to std::vector.
+
+ @remark
+ Unlike DYNAMIC_ARRAY, elements are properly copied
+ (rather than memcpy()d) if the underlying array needs to be expanded.
+
+ @remark
+ Depending on has_trivial_destructor, we destroy objects which are
+ removed from the array (including when the array object itself is destroyed).
+
+ @remark
+ Note that MEM_ROOT has no facility for reusing free space,
+ so don't use this if multiple re-expansions are likely to happen.
+
+ @param Element_type The type of the elements of the container.
+ Elements must be copyable.
+ @param has_trivial_destructor If true, we don't destroy elements.
+ We could have used type traits to determine this.
+ __has_trivial_destructor is supported by some (but not all)
+ compilers we use.
+*/
+template<typename Element_type, bool has_trivial_destructor>
+class Mem_root_array
+{
+public:
+ Mem_root_array(MEM_ROOT *root)
+ : m_root(root), m_array(NULL), m_size(0), m_capacity(0)
+ {
+ DBUG_ASSERT(m_root != NULL);
+ }
+
+ ~Mem_root_array()
+ {
+ clear();
+ }
+
+ Element_type &at(size_t n)
+ {
+ DBUG_ASSERT(n < size());
+ return m_array[n];
+ }
+
+ const Element_type &at(size_t n) const
+ {
+ DBUG_ASSERT(n < size());
+ return m_array[n];
+ }
+
+ // Returns a pointer to the first element in the array.
+ Element_type *begin() { return &m_array[0]; }
+
+ // Returns a pointer to the past-the-end element in the array.
+ Element_type *end() { return &m_array[size()]; }
+
+ // Erases all of the elements.
+ void clear()
+ {
+ if (!empty())
+ chop(0);
+ }
+
+ /*
+ Chops the tail off the array, erasing all tail elements.
+ @param pos Index of first element to erase.
+ */
+ void chop(const size_t pos)
+ {
+ DBUG_ASSERT(pos < m_size);
+ if (!has_trivial_destructor)
+ {
+ for (size_t ix= pos; ix < m_size; ++ix)
+ {
+ Element_type *p= &m_array[ix];
+ p->~Element_type(); // Destroy discarded element.
+ }
+ }
+ m_size= pos;
+ }
+
+ /*
+ Reserves space for array elements.
+ Copies over existing elements, in case we are re-expanding the array.
+
+ @param n number of elements.
+ @retval true if out-of-memory, false otherwise.
+ */
+ bool reserve(size_t n)
+ {
+ if (n <= m_capacity)
+ return false;
+
+ void *mem= alloc_root(m_root, n * element_size());
+ if (!mem)
+ return true;
+ Element_type *array= static_cast<Element_type*>(mem);
+
+ // Copy all the existing elements into the new array.
+ for (size_t ix= 0; ix < m_size; ++ix)
+ {
+ Element_type *new_p= &array[ix];
+ Element_type *old_p= &m_array[ix];
+ new (new_p) Element_type(*old_p); // Copy into new location.
+ if (!has_trivial_destructor)
+ old_p->~Element_type(); // Destroy the old element.
+ }
+
+ // Forget the old array.
+ m_array= array;
+ m_capacity= n;
+ return false;
+ }
+
+ /*
+ Adds a new element at the end of the array, after its current last
+ element. The content of this new element is initialized to a copy of
+ the input argument.
+
+ @param element Object to copy.
+ @retval true if out-of-memory, false otherwise.
+ */
+ bool push_back(const Element_type &element)
+ {
+ const size_t min_capacity= 20;
+ const size_t expansion_factor= 2;
+ if (0 == m_capacity && reserve(min_capacity))
+ return true;
+ if (m_size == m_capacity && reserve(m_capacity * expansion_factor))
+ return true;
+ Element_type *p= &m_array[m_size++];
+ new (p) Element_type(element);
+ return false;
+ }
+
+ size_t capacity() const { return m_capacity; }
+ size_t element_size() const { return sizeof(Element_type); }
+ bool empty() const { return size() == 0; }
+ size_t size() const { return m_size; }
+
+private:
+ MEM_ROOT *const m_root;
+ Element_type *m_array;
+ size_t m_size;
+ size_t m_capacity;
+
+ // Not (yet) implemented.
+ Mem_root_array(const Mem_root_array&);
+ Mem_root_array &operator=(const Mem_root_array&);
+};
+
+
+#endif // MEM_ROOT_ARRAY_INCLUDED
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 42a70094e2c..7b7c73f147c 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2000, 2011, Oracle and/or its affiliates.
- Copyright (c) 2008-2012 Monty Program Ab
+/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
+ Copyright (c) 2008, 2012, 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
@@ -677,7 +677,7 @@ int mysqld_server_started= 0;
File_parser_dummy_hook file_parser_dummy_hook;
/* replication parameters, if master_host is not NULL, we are a slave */
-uint report_port= MYSQL_PORT;
+uint report_port= 0;
ulong master_retry_count=0;
char *master_info_file;
char *relay_log_info_file, *report_user, *report_password, *report_host;
@@ -686,9 +686,8 @@ char *opt_logname, *opt_slow_logname, *opt_bin_logname;
/* Static variables */
-my_bool opt_stack_trace;
static volatile sig_atomic_t kill_in_progress;
-
+my_bool opt_stack_trace;
my_bool opt_expect_abort= 0;
static my_bool opt_bootstrap, opt_myisam_log;
static int cleanup_done;
@@ -749,7 +748,6 @@ PSI_mutex_key key_LOCK_stats,
key_LOCK_wakeup_ready;
PSI_mutex_key key_LOCK_prepare_ordered, key_LOCK_commit_ordered;
-PSI_mutex_key key_LOCK_logger_service;
static PSI_mutex_info all_server_mutexes[]=
{
@@ -809,8 +807,6 @@ static PSI_mutex_info all_server_mutexes[]=
{ &key_LOCK_commit_ordered, "LOCK_commit_ordered", PSI_FLAG_GLOBAL},
{ &key_LOG_INFO_lock, "LOG_INFO::lock", 0},
{ &key_LOCK_thread_count, "LOCK_thread_count", PSI_FLAG_GLOBAL},
- { &key_LOCK_logger_service, "logger_service_file_st::lock",
- PSI_FLAG_GLOBAL},
{ &key_PARTITION_LOCK_auto_inc, "HA_DATA_PARTITION::LOCK_auto_inc", 0}
};
@@ -2234,6 +2230,11 @@ static void network_init(void)
set_ports();
+ if (report_port == 0)
+ {
+ report_port= mysqld_port;
+ }
+ DBUG_ASSERT(report_port != 0);
if (!opt_disable_networking && !opt_bootstrap)
{
if (mysqld_port)
@@ -2338,10 +2339,6 @@ static void network_init(void)
}
-#endif /*!EMBEDDED_LIBRARY*/
-
-
-#ifndef EMBEDDED_LIBRARY
/**
Close a connection.
@@ -2755,10 +2752,6 @@ static void check_data_home(const char *path)
#endif /* __WIN__ */
-#ifdef HAVE_LINUXTHREADS
-#define UNSAFE_DEFAULT_LINUX_THREADS 200
-#endif
-
#if BACKTRACE_DEMANGLE
#include <cxxabi.h>
@@ -2768,13 +2761,84 @@ extern "C" char *my_demangle(const char *mangled_name, int *status)
}
#endif
+
+/*
+ pthread_attr_setstacksize() without so much platform-dependency
+
+ Return: The actual stack size if possible.
+*/
+
+#ifndef EMBEDDED_LIBRARY
+static size_t my_setstacksize(pthread_attr_t *attr, size_t stacksize)
+{
+ size_t guard_size __attribute__((unused))= 0;
+
+#if defined(__ia64__) || defined(__ia64)
+ /*
+ On IA64, half of the requested stack size is used for "normal stack"
+ and half for "register stack". The space measured by check_stack_overrun
+ is the "normal stack", so double the request to make sure we have the
+ caller-expected amount of normal stack.
+
+ NOTE: there is no guarantee that the register stack can't grow faster
+ than normal stack, so it's very unclear that we won't dump core due to
+ stack overrun despite check_stack_overrun's efforts. Experimentation
+ shows that in the execution_constants test, the register stack grows
+ less than half as fast as normal stack, but perhaps other scenarios are
+ less forgiving. If it turns out that more space is needed for the
+ register stack, that could be forced (rather inefficiently) by using a
+ multiplier higher than 2 here.
+ */
+ stacksize *= 2;
+#endif
+
+ /*
+ On many machines, the "guard space" is subtracted from the requested
+ stack size, and that space is quite large on some platforms. So add
+ it to our request, if we can find out what it is.
+ */
+#ifdef HAVE_PTHREAD_ATTR_GETGUARDSIZE
+ if (pthread_attr_getguardsize(attr, &guard_size))
+ guard_size = 0; /* if can't find it out, treat as 0 */
+#endif
+
+ pthread_attr_setstacksize(attr, stacksize + guard_size);
+
+ /* Retrieve actual stack size if possible */
+#ifdef HAVE_PTHREAD_ATTR_GETSTACKSIZE
+ {
+ size_t real_stack_size= 0;
+ /* We must ignore real_stack_size = 0 as Solaris 2.9 can return 0 here */
+ if (pthread_attr_getstacksize(attr, &real_stack_size) == 0 &&
+ real_stack_size > guard_size)
+ {
+ real_stack_size -= guard_size;
+ if (real_stack_size < stacksize)
+ {
+ if (global_system_variables.log_warnings)
+ sql_print_warning("Asked for %zu thread stack, but got %zu",
+ stacksize, real_stack_size);
+ stacksize= real_stack_size;
+ }
+ }
+ }
+#endif /* !EMBEDDED_LIBRARY */
+
+#if defined(__ia64__) || defined(__ia64)
+ stacksize /= 2;
+#endif
+ return stacksize;
+}
+#endif
+
+
#if !defined(__WIN__)
#ifndef SA_RESETHAND
#define SA_RESETHAND 0
-#endif
+#endif /* SA_RESETHAND */
#ifndef SA_NODEFER
#define SA_NODEFER 0
-#endif
+#endif /* SA_NODEFER */
#ifndef EMBEDDED_LIBRARY
@@ -2792,9 +2856,7 @@ static void init_signals(void)
sigemptyset(&sa.sa_mask);
sigprocmask(SIG_SETMASK,&sa.sa_mask,NULL);
-#ifdef HAVE_STACKTRACE
my_init_stacktrace();
-#endif
#if defined(__amiga__)
sa.sa_handler=(void(*)())handle_fatal_signal;
#else
@@ -2866,15 +2928,7 @@ static void start_signal_handler(void)
#if !defined(HAVE_DEC_3_2_THREADS)
pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_SYSTEM);
(void) pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
-#if defined(__ia64__) || defined(__ia64)
- /*
- Peculiar things with ia64 platforms - it seems we only have half the
- stack size in reality, so we have to double it here
- */
- pthread_attr_setstacksize(&thr_attr,my_thread_stack_size*2);
-#else
- pthread_attr_setstacksize(&thr_attr,my_thread_stack_size);
-#endif
+ (void) my_setstacksize(&thr_attr,my_thread_stack_size);
#endif
mysql_mutex_lock(&LOCK_thread_count);
@@ -4700,37 +4754,9 @@ int mysqld_main(int argc, char **argv)
unireg_abort(1); // Will do exit
init_signals();
-#if defined(__ia64__) || defined(__ia64)
- /*
- Peculiar things with ia64 platforms - it seems we only have half the
- stack size in reality, so we have to double it here
- */
- pthread_attr_setstacksize(&connection_attrib,my_thread_stack_size*2);
-#else
- pthread_attr_setstacksize(&connection_attrib,my_thread_stack_size);
-#endif
-#ifdef HAVE_PTHREAD_ATTR_GETSTACKSIZE
- {
- /* Retrieve used stack size; Needed for checking stack overflows */
- size_t stack_size= 0;
- pthread_attr_getstacksize(&connection_attrib, &stack_size);
-#if defined(__ia64__) || defined(__ia64)
- stack_size/= 2;
-#endif
- /* We must check if stack_size = 0 as Solaris 2.9 can return 0 here */
- if (stack_size && stack_size < my_thread_stack_size)
- {
- if (global_system_variables.log_warnings)
- sql_print_warning("Asked for %llu thread stack, but got %zu",
- my_thread_stack_size, stack_size);
-#if defined(__ia64__) || defined(__ia64)
- my_thread_stack_size= stack_size*2;
-#else
- my_thread_stack_size= stack_size;
-#endif
- }
- }
-#endif
+
+ my_thread_stack_size= my_setstacksize(&connection_attrib,
+ my_thread_stack_size);
(void) thr_setconcurrency(concurrency); // 10 by default
@@ -5427,8 +5453,10 @@ void handle_connections_sockets()
uint error_count=0;
THD *thd;
struct sockaddr_storage cAddr;
- int ip_flags=0,socket_flags=0,flags=0,retval;
- int extra_ip_flags=0;
+ int ip_flags __attribute__((unused))=0;
+ int socket_flags __attribute__((unused))= 0;
+ int extra_ip_flags __attribute__((unused))=0;
+ int flags=0,retval;
st_vio *vio_tmp;
#ifdef HAVE_POLL
int socket_count= 0;
@@ -6018,17 +6046,6 @@ struct my_option my_long_options[]=
{"help", '?', "Display this help and exit.",
&opt_help, &opt_help, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
0, 0},
-#ifdef DBUG_OFF
- {"debug", '#', "Built in DBUG debugger. Disabled in this build.",
- &current_dbug_option, &current_dbug_option, 0, GET_STR, OPT_ARG,
- 0, 0, 0, 0, 0, 0},
-#endif
-#ifdef HAVE_REPLICATION
- {"debug-abort-slave-event-count", 0,
- "Option used by mysql-test for debugging and testing of replication.",
- &abort_slave_event_count, &abort_slave_event_count,
- 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
-#endif /* HAVE_REPLICATION */
{"allow-suspicious-udfs", 0,
"Allows use of UDFs consisting of only one symbol xxx() "
"without corresponding xxx_init() or xxx_deinit(). That also means "
@@ -6097,30 +6114,86 @@ struct my_option my_long_options[]=
/* default-storage-engine should have "MyISAM" as def_value. Instead
of initializing it here it is done in init_common_variables() due
to a compiler bug in Sun Studio compiler. */
+#ifdef DBUG_OFF
+ {"debug", '#', "Built in DBUG debugger. Disabled in this build.",
+ &current_dbug_option, &current_dbug_option, 0, GET_STR, OPT_ARG,
+ 0, 0, 0, 0, 0, 0},
+#endif
+#ifdef HAVE_REPLICATION
+ {"debug-abort-slave-event-count", 0,
+ "Option used by mysql-test for debugging and testing of replication.",
+ &abort_slave_event_count, &abort_slave_event_count,
+ 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+#endif /* HAVE_REPLICATION */
+#ifndef DBUG_OFF
+ {"debug-assert-on-error", 0,
+ "Do an assert in various functions if we get a fatal error",
+ &my_assert_on_error, &my_assert_on_error,
+ 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"debug-assert-if-crashed-table", 0,
+ "Do an assert in handler::print_error() if we get a crashed table",
+ &debug_assert_if_crashed_table, &debug_assert_if_crashed_table,
+ 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+#endif
+#ifdef HAVE_REPLICATION
+ {"debug-disconnect-slave-event-count", 0,
+ "Option used by mysql-test for debugging and testing of replication.",
+ &disconnect_slave_event_count, &disconnect_slave_event_count,
+ 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+#endif /* HAVE_REPLICATION */
+ {"debug-exit-info", 'T', "Used for debugging. Use at your own risk.",
+ 0, 0, 0, GET_LONG, OPT_ARG, 0, 0, 0, 0, 0, 0},
+ {"debug-gdb", 0,
+ "Set up signals usable for debugging.",
+ &opt_debugging, &opt_debugging,
+ 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+#ifdef HAVE_REPLICATION
+ {"debug-max-binlog-dump-events", 0,
+ "Option used by mysql-test for debugging and testing of replication.",
+ &max_binlog_dump_events, &max_binlog_dump_events, 0,
+ GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+#endif /* HAVE_REPLICATION */
+#ifdef SAFE_MUTEX
+ {"debug-mutex-deadlock-detector", 0,
+ "Enable checking of wrong mutex usage.",
+ &safe_mutex_deadlock_detector,
+ &safe_mutex_deadlock_detector,
+ 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
+#endif
+ {"debug-no-sync", 0,
+ "Disables system sync calls. Only for running tests or debugging!",
+ &my_disable_sync, &my_disable_sync, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
+#ifdef HAVE_REPLICATION
+ {"debug-sporadic-binlog-dump-fail", 0,
+ "Option used by mysql-test for debugging and testing of replication.",
+ &opt_sporadic_binlog_dump_fail,
+ &opt_sporadic_binlog_dump_fail, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
+ 0},
+#endif /* HAVE_REPLICATION */
{"default-storage-engine", 0, "The default storage engine for new tables",
&default_storage_engine, 0, 0, GET_STR, REQUIRED_ARG,
0, 0, 0, 0, 0, 0 },
{"default-time-zone", 0, "Set the default time zone.",
&default_tz_name, &default_tz_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
+#if defined(ENABLED_DEBUG_SYNC)
+ {"debug-sync-timeout", OPT_DEBUG_SYNC_TIMEOUT,
+ "Enable the debug sync facility "
+ "and optionally specify a default wait timeout in seconds. "
+ "A zero value keeps the facility disabled.",
+ &opt_debug_sync_timeout, 0,
+ 0, GET_UINT, OPT_ARG, 0, 0, UINT_MAX, 0, 0, 0},
+#endif /* defined(ENABLED_DEBUG_SYNC) */
#ifdef HAVE_OPENSSL
{"des-key-file", 0,
"Load keys for des_encrypt() and des_encrypt from given file.",
&des_key_file, &des_key_file, 0, GET_STR, REQUIRED_ARG,
0, 0, 0, 0, 0, 0},
#endif /* HAVE_OPENSSL */
-#ifdef HAVE_REPLICATION
- {"debug-disconnect-slave-event-count", 0,
- "Option used by mysql-test for debugging and testing of replication.",
- &disconnect_slave_event_count, &disconnect_slave_event_count,
- 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
-#endif /* HAVE_REPLICATION */
#ifdef HAVE_STACKTRACE
{"stack-trace", 0 , "Print a symbolic stack trace on failure",
&opt_stack_trace, &opt_stack_trace, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
#endif /* HAVE_STACKTRACE */
- {"debug-exit-info", 'T', "Used for debugging. Use at your own risk.", 0, 0, 0,
- GET_LONG, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"external-locking", 0, "Use system (external) locking (disabled by "
"default). With this option enabled you can run myisamchk to test "
"(not repair) tables while the MySQL server is running. Disable with "
@@ -6132,10 +6205,6 @@ struct my_option my_long_options[]=
"Set up signals usable for debugging. Deprecated, use --debug-gdb instead.",
&opt_debugging, &opt_debugging,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"debug-gdb", 0,
- "Set up signals usable for debugging.",
- &opt_debugging, &opt_debugging,
- 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
#ifdef HAVE_LARGE_PAGE_OPTION
{"super-large-pages", 0, "Enable support for super large pages.",
&opt_super_large_pages, &opt_super_large_pages, 0,
@@ -6226,10 +6295,6 @@ struct my_option my_long_options[]=
{"init-rpl-role", 0, "Set the replication role.",
&rpl_status, &rpl_status, &rpl_role_typelib,
GET_ENUM, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"debug-max-binlog-dump-events", 0,
- "Option used by mysql-test for debugging and testing of replication.",
- &max_binlog_dump_events, &max_binlog_dump_events, 0,
- GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#endif /* HAVE_REPLICATION */
{"memlock", 0, "Lock mysqld in memory.", &locked_in_memory,
&locked_in_memory, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
@@ -6340,13 +6405,6 @@ struct my_option my_long_options[]=
"(Default: 15000).", &slow_start_timeout, &slow_start_timeout, 0,
GET_ULONG, REQUIRED_ARG, 15000, 0, 0, 0, 0, 0},
#endif
-#ifdef HAVE_REPLICATION
- {"debug-sporadic-binlog-dump-fail", 0,
- "Option used by mysql-test for debugging and testing of replication.",
- &opt_sporadic_binlog_dump_fail,
- &opt_sporadic_binlog_dump_fail, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
- 0},
-#endif /* HAVE_REPLICATION */
#ifdef HAVE_OPENSSL
{"ssl", 0,
"Enable SSL for connection (automatically enabled with other flags).",
@@ -6368,9 +6426,6 @@ struct my_option my_long_options[]=
files.
*/
IF_VALGRIND(0,IF_WIN(0,1)), 0, 0, 0, 0, 0},
- {"debug-no-sync", 0,
- "Disables system sync calls. Only for running tests or debugging!",
- &my_disable_sync, &my_disable_sync, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
{"sysdate-is-now", 0,
"Non-default option to alias SYSDATE() to NOW() to make it safe-replicable. "
"Since 5.0, SYSDATE() returns a `dynamic' value different for different "
@@ -6381,14 +6436,6 @@ struct my_option my_long_options[]=
"Decision to use in heuristic recover process. Possible values are COMMIT "
"or ROLLBACK.", &tc_heuristic_recover, &tc_heuristic_recover,
&tc_heuristic_recover_typelib, GET_ENUM, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
-#if defined(ENABLED_DEBUG_SYNC)
- {"debug-sync-timeout", OPT_DEBUG_SYNC_TIMEOUT,
- "Enable the debug sync facility "
- "and optionally specify a default wait timeout in seconds. "
- "A zero value keeps the facility disabled.",
- &opt_debug_sync_timeout, 0,
- 0, GET_UINT, OPT_ARG, 0, 0, UINT_MAX, 0, 0, 0},
-#endif /* defined(ENABLED_DEBUG_SYNC) */
{"temp-pool", 0,
#if (ENABLE_TEMP_POOL)
"Using this option will cause most temporary files created to use a small "
@@ -6418,16 +6465,6 @@ struct my_option my_long_options[]=
{"table_cache", 0, "Deprecated; use --table-open-cache instead.",
&table_cache_size, &table_cache_size, 0, GET_ULONG,
REQUIRED_ARG, TABLE_OPEN_CACHE_DEFAULT, 1, 512*1024L, 0, 1, 0},
-#ifndef DBUG_OFF
- {"debug-assert-on-error", 0,
- "Do an assert in various functions if we get a fatal error",
- &my_assert_on_error, &my_assert_on_error,
- 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"debug-assert-if-crashed-table", 0,
- "Do an assert in handler::print_error() if we get a crashed table",
- &debug_assert_if_crashed_table, &debug_assert_if_crashed_table,
- 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
-#endif
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
@@ -7911,6 +7948,14 @@ static int get_options(int *argc_ptr, char ***argv_ptr)
one_thread_scheduler(thread_scheduler);
one_thread_scheduler(extra_thread_scheduler);
#else
+
+#ifdef _WIN32
+ /* workaround: disable thread pool on XP */
+ if (GetProcAddress(GetModuleHandle("kernel32"),"CreateThreadpool") == 0 &&
+ thread_handling > SCHEDULER_NO_THREADS)
+ thread_handling = SCHEDULER_ONE_THREAD_PER_CONNECTION;
+#endif
+
if (thread_handling <= SCHEDULER_ONE_THREAD_PER_CONNECTION)
one_thread_per_connection_scheduler(thread_scheduler, &max_connections,
&connection_count);
diff --git a/sql/mysqld.h b/sql/mysqld.h
index 617ecbb8da2..6d2da80d7c8 100644
--- a/sql/mysqld.h
+++ b/sql/mysqld.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
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/opt_range.cc b/sql/opt_range.cc
index 61f73b95050..41f6047ff17 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -1396,7 +1396,7 @@ SEL_IMERGE::SEL_IMERGE(SEL_IMERGE *arg, uint cnt,
for (SEL_TREE **tree = trees, **arg_tree= arg->trees; tree < trees_next;
tree++, arg_tree++)
{
- if (!(*tree= new SEL_TREE(*arg_tree, FALSE, param)))
+ if (!(*tree= new SEL_TREE(*arg_tree, TRUE, param)))
goto mem_err;
}
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index dcb5181acc3..56b76f5982e 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -188,6 +188,252 @@
*/
+/*
+EqualityPropagationAndSjmNests
+******************************
+
+Equalities are used for:
+P1. Equality propagation
+P2. Equality substitution [for a certain join order]
+
+The equality propagation is not affected by SJM nests. In fact, it is done
+before we determine the execution plan, i.e. before we even know we will use
+SJM-nests for execution.
+
+The equality substitution is affected.
+
+Substitution without SJMs
+=========================
+When one doesn't have SJM nests, tables have a strict join order:
+
+ --------------------------------->
+ t1 -- t2 -- t3 -- t4 --- t5
+
+
+ ? ^
+ \
+ --(part-of-WHERE)
+
+
+parts WHERE/ON and ref. expressions are attached at some point along the axis.
+Expression is allowed to refer to a table column if the table is to the left of
+the attachment point. For any given expression, we have a goal:
+
+ "Move leftmost allowed attachment point as much as possible to the left"
+
+Substitution with SJMs - task setting
+=====================================
+
+When SJM nests are present, there is no global strict table ordering anymore:
+
+
+ --------------------------------->
+
+ ot1 -- ot2 --- sjm -- ot4 --- ot5
+ |
+ | Main execution
+ - - - - - - - - - - - - - - - - - - - - - - - -
+ | Materialization
+ it1 -- it2 --/
+
+
+Besides that, we must take into account that
+ - values for outer table columns, otN.col, are inaccessible at
+ materialization step (SJM-RULE)
+ - values for inner table columns, itN.col, are inaccessible at Main execution
+ step, except for SJ-Materialization-Scan and columns that are in the
+ subquery's select list. (SJM-RULE)
+
+Substitution with SJMs - solution
+=================================
+
+First, we introduce global strict table ordering like this:
+
+ ot1 - ot2 --\ /--- ot3 -- ot5
+ \--- it1 --- it2 --/
+
+Now, let's see how to meet (SJM-RULE).
+
+SJ-Materialization is only applicable for uncorrelated subqueries. From this, it
+follows that any multiple equality will either
+1. include only columns of outer tables, or
+2. include only columns of inner tables, or
+3. include columns of inner and outer tables, joined together through one
+ of IN-equalities.
+
+Cases #1 and #2 can be handled in the same way as with regular inner joins.
+
+Case #3 requires special handling, so that we don't construct violations of
+(SJM-RULE). Let's consider possible ways to build violations.
+
+Equality propagation starts with the clause in this form
+
+ top_query_where AND subquery_where AND in_equalities
+
+First, it builds multi-equalities. It can also build a mixed multi-equality
+
+ multiple-equal(ot1.col, ot2.col, ... it1.col, itN.col)
+
+Multi-equalities are pushed down the OR-clauses in top_query_where and in
+subquery_where, so it's possible that clauses like this one are built:
+
+ subquery_cond OR (multiple-equal(it1.col, ot1.col,...) AND ...)
+ ^^^^^^^^^^^^^ \
+ | this must be evaluated
+ \- can only be evaluated at the main phase.
+ at the materialization phase
+
+Finally, equality substitution is started. It does two operations:
+
+
+1. Field reference substitution
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+(In the code, this is Item_field::replace_equal_field)
+
+This is a process of replacing each reference to "tblX.col"
+with the first element of the multi-equality. (REF-SUBST-ORIG)
+
+This behaviour can cause problems with Semi-join nests. Suppose, we have a
+condition:
+
+ func(it1.col, it2.col)
+
+and a multi-equality(ot1.col, it1.col). Then, reference to "it1.col" will be
+replaced with "ot1.col", constructing a condition
+
+ func(ot1.col, it2.col)
+
+which will be a violation of (SJM-RULE).
+
+In order to avoid this, (REF-SUBST-ORIG) is amended as follows:
+
+- references to tables "itX.col" that are inner wrt some SJM nest, are
+ replaced with references to the first inner table from the same SJM nest.
+
+- references to top-level tables "otX.col" are replaced with references to
+ the first element of the multi-equality, no matter if that first element is
+ a column of a top-level table or of table from some SJM nest.
+ (REF-SUBST-SJM)
+
+ The case where the first element is a table from an SJM nest $SJM is ok,
+ because it can be proven that $SJM uses SJ-Materialization-Scan, and
+ "unpacks" correct column values to the first element during the main
+ execution phase.
+
+2. Item_equal elimination
+~~~~~~~~~~~~~~~~~~~~~~~~~
+(In the code: eliminate_item_equal) This is a process of taking
+
+ multiple-equal(a,b,c,d,e)
+
+and replacing it with an equivalent expression which is an AND of pair-wise
+equalities:
+
+ a=b AND a=c AND ...
+
+The equalities are picked such that for any given join prefix (t1,t2...) the
+subset of equalities that can be evaluated gives the most restrictive
+filtering.
+
+Without SJM nests, it is sufficient to compare every multi-equality member
+with the first one:
+
+ elem1=elem2 AND elem1=elem3 AND elem1=elem4 ...
+
+When SJM nests are present, we should take care not to construct equalities
+that violate the (SJM-RULE). This is achieved by generating separate sets of
+equalites for top-level tables and for inner tables. That is, for the join
+order
+
+ ot1 - ot2 --\ /--- ot3 -- ot5
+ \--- it1 --- it2 --/
+
+we will generate
+ ot1.col=ot2.col
+ ot1.col=ot3.col
+ ot1.col=ot5.col
+ it2.col=it1.col
+
+
+2.1 The problem with Item_equals and ORs
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+As has been mentioned above, multiple equalities are pushed down into OR
+clauses, possibly building clauses like this:
+
+ func(it.col2) OR multiple-equal(it1.col1, it1.col2, ot1.col) (1)
+
+where the first part of the clause has references to inner tables, while the
+second has references to the top-level tables, which is a violation of
+(SJM-RULE).
+
+AND-clauses of this kind do not create problems, because make_cond_for_table()
+will take them apart. OR-clauses will not be split. It is possible to
+split-out the part that's dependent on the inner table:
+
+ func(it.col2) OR it1.col1=it1.col2
+
+but this is a less-restrictive condition than condition (1). Current execution
+scheme will still try to generate the "remainder" condition:
+
+ func(it.col2) OR it1.col1=ot1.col
+
+which is a violation of (SJM-RULE).
+
+QQ: "ot1.col=it1.col" is checked at the upper level. Why was it not removed
+here?
+AA: because has a proper subset of conditions that are found on this level.
+ consider a join order of ot, sjm(it)
+ and a condition
+ ot.col=it.col AND ( ot.col=it.col='foo' OR it.col2='bar')
+
+ we will produce:
+ table ot: nothing
+ table it: ot.col=it.col AND (ot.col='foo' OR it.col2='bar')
+ ^^^^ ^^^^^^^^^^^^^^^^
+ | \ the problem is that
+ | this part condition didnt
+ | receive a substitution
+ |
+ +--- it was correct to subst, 'ot' is
+ the left-most.
+
+
+Does it make sense to push "inner=outer" down into ORs?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Yes. Consider the query:
+
+ select * from ot
+ where ot.col in (select it.col from it where (it.col='foo' OR it.col='bar'))
+
+here, it may be useful to infer that
+
+ (ot.col='foo' OR ot.col='bar') (CASE-FOR-SUBST)
+
+and attach that condition to the table 'ot'.
+
+Possible solutions for Item_equals and ORs
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Solution #1
+~~~~~~~~~~~
+Let make_cond_for_table() chop analyze the OR clauses it has produced and
+discard them if they violate (SJM-RULE). This solution would allow to handle
+cases like (CASE-FOR-SUBST) at the expense of making semantics of
+make_cond_for_table() complicated.
+
+Solution #2
+~~~~~~~~~~~
+Before the equality propagation phase, none of the OR clauses violate the
+(SJM-RULE). This way, if we remember which tables the original equality
+referred to, we can only generate equalities that refer to the outer (or inner)
+tables. Note that this will disallow handling of cases like (CASE-FOR-SUBST).
+
+Currently, solution #2 is implemented.
+
+*/
+
static
bool subquery_types_allow_materialization(Item_in_subselect *in_subs);
@@ -346,8 +592,8 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
TODO: for PS, make the whole block execute only on the first execution
*/
Item_subselect *subselect;
- if (!(thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW) && // (1)
- (subselect= parent_unit->item)) // (2)
+ if (!thd->lex->is_view_context_analysis() && // (1)
+ (subselect= parent_unit->item)) // (2)
{
Item_in_subselect *in_subs= NULL;
Item_allany_subselect *allany_subs= NULL;
@@ -1229,6 +1475,8 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
sj_nest->embedding= emb_tbl_nest;
sj_nest->alias= (char*) "(sj-nest)";
sj_nest->sj_subq_pred= subq_pred;
+ sj_nest->original_subq_pred_used_tables= subq_pred->used_tables() |
+ subq_pred->left_expr->used_tables();
/* Nests do not participate in those 'chains', so: */
/* sj_nest->next_leaf= sj_nest->next_local= sj_nest->next_global == NULL*/
emb_join_list->push_back(sj_nest);
@@ -1267,7 +1515,10 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
(a theory: a next_local chain always starts with ::leaf_tables
because view's tables are inserted after the view)
*/
- for (tl= parent_lex->leaf_tables.head(); tl->next_local; tl= tl->next_local) ;
+
+ for (tl= (TABLE_LIST*)(parent_lex->table_list.first); tl->next_local; tl= tl->next_local)
+ {}
+
tl->next_local= subq_lex->leaf_tables.head();
/* A theory: no need to re-connect the next_global chain */
@@ -1480,7 +1731,7 @@ static bool convert_subq_to_jtbm(JOIN *parent_join,
(a theory: a next_local chain always starts with ::leaf_tables
because view's tables are inserted after the view)
*/
- for (tl= parent_lex->leaf_tables.head(); tl->next_local; tl= tl->next_local)
+ for (tl= (TABLE_LIST*)(parent_lex->table_list.first); tl->next_local; tl= tl->next_local)
{}
tl->next_local= jtbm;
@@ -2670,6 +2921,8 @@ bool Firstmatch_picker::check_qep(JOIN *join,
}
}
}
+ else
+ invalidate_firstmatch_prefix();
return FALSE;
}
@@ -3097,7 +3350,22 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
record_count, join->best_positions + idx,
&loose_scan_pos);
if (idx==first)
+ {
join->best_positions[idx]= loose_scan_pos;
+ /*
+ If LooseScan is based on ref access (including the "degenerate"
+ one with 0 key parts), we should use full index scan.
+
+ Unfortunately, lots of code assumes that if tab->type==JT_ALL &&
+ tab->quick!=NULL, then quick select should be used. The only
+ simple way to fix this is to remove the quick select:
+ */
+ if (join->best_positions[idx].key)
+ {
+ delete join->best_positions[idx].table->quick;
+ join->best_positions[idx].table->quick= NULL;
+ }
+ }
}
rem_tables &= ~join->best_positions[idx].table->table->map;
record_count *= join->best_positions[idx].records_read;
@@ -4950,7 +5218,6 @@ bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list,
bool JOIN::choose_subquery_plan(table_map join_tables)
{
- Join_plan_state save_qep; /* The original QEP of the subquery. */
enum_reopt_result reopt_result= REOPT_NONE;
Item_in_subselect *in_subs;
@@ -4969,12 +5236,16 @@ bool JOIN::choose_subquery_plan(table_map join_tables)
}
else
return false;
+
/* A strategy must be chosen earlier. */
DBUG_ASSERT(in_subs->has_strategy());
DBUG_ASSERT(in_to_exists_where || in_to_exists_having);
DBUG_ASSERT(!in_to_exists_where || in_to_exists_where->fixed);
DBUG_ASSERT(!in_to_exists_having || in_to_exists_having->fixed);
+ /* The original QEP of the subquery. */
+ Join_plan_state save_qep(table_count);
+
/*
Compute and compare the costs of materialization and in-exists if both
strategies are possible and allowed by the user (checked during the prepare
diff --git a/sql/password.c b/sql/password.c
index f4ff3156bec..1a12a81f7c6 100644
--- a/sql/password.c
+++ b/sql/password.c
@@ -503,7 +503,7 @@ check_scramble(const uchar *scramble_arg, const char *message,
mysql_sha1_reset(&sha1_context);
mysql_sha1_input(&sha1_context, buf, SHA1_HASH_SIZE);
mysql_sha1_result(&sha1_context, hash_stage2_reassured);
- return memcmp(hash_stage2, hash_stage2_reassured, SHA1_HASH_SIZE);
+ return test(memcmp(hash_stage2, hash_stage2_reassured, SHA1_HASH_SIZE));
}
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 63b945f7078..10c85939986 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2000, 2010, Oracle and/or its affiliates.
- Copyright (c) 2008-2011 Monty Program Ab
+/* Copyright (c) 2000, 2011, Oracle and/or its affiliates.
+ Copyright (c) 2008, 2011, 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/records.cc b/sql/records.cc
index 77fdc427b86..d52481c36f5 100644
--- a/sql/records.cc
+++ b/sql/records.cc
@@ -344,7 +344,8 @@ static int rr_quick(READ_RECORD *info)
break;
}
}
- update_virtual_fields(info->thd, info->table);
+ if (info->table->vfield)
+ update_virtual_fields(info->thd, info->table);
return tmp;
}
@@ -460,7 +461,7 @@ int rr_sequential(READ_RECORD *info)
break;
}
}
- if (!tmp)
+ if (!tmp && info->table->vfield)
update_virtual_fields(info->thd, info->table);
return tmp;
}
diff --git a/sql/rpl_filter.cc b/sql/rpl_filter.cc
index 5f5473e09ab..0380bc323a3 100644
--- a/sql/rpl_filter.cc
+++ b/sql/rpl_filter.cc
@@ -42,8 +42,8 @@ Rpl_filter::~Rpl_filter()
free_string_array(&wild_do_table);
if (wild_ignore_table_inited)
free_string_array(&wild_ignore_table);
- free_list(&do_db);
- free_list(&ignore_db);
+ free_string_list(&do_db);
+ free_string_list(&ignore_db);
free_list(&rewrite_db);
}
@@ -263,6 +263,57 @@ Rpl_filter::is_on()
}
+/**
+ Parse and add the given comma-separated sequence of filter rules.
+
+ @param spec Comma-separated sequence of filter rules.
+ @param add Callback member function to add a filter rule.
+
+ @return true if error, false otherwise.
+*/
+
+int
+Rpl_filter::parse_filter_rule(const char* spec, Add_filter add)
+{
+ int status= 0;
+ char *arg, *ptr, *pstr;
+
+ if (! (ptr= my_strdup(spec, MYF(MY_WME))))
+ return true;
+
+ pstr= ptr;
+
+ while (pstr)
+ {
+ arg= pstr;
+
+ /* Parse token string. */
+ pstr= strpbrk(arg, ",");
+
+ /* NUL terminate the token string. */
+ if (pstr)
+ *pstr++= '\0';
+
+ /* Skip an empty token string. */
+ if (arg[0] == '\0')
+ continue;
+
+ /* Skip leading spaces. */
+ while (my_isspace(system_charset_info, *arg))
+ arg++;
+
+ status= (this->*add)(arg);
+
+ if (status)
+ break;
+ }
+
+ my_free(ptr);
+
+ return status;
+}
+
+
int
Rpl_filter::add_do_table(const char* table_spec)
{
@@ -285,6 +336,46 @@ Rpl_filter::add_ignore_table(const char* table_spec)
}
+int
+Rpl_filter::set_do_table(const char* table_spec)
+{
+ int status;
+
+ if (do_table_inited)
+ my_hash_reset(&do_table);
+
+ status= parse_filter_rule(table_spec, &Rpl_filter::add_do_table);
+
+ if (!do_table.records)
+ {
+ my_hash_free(&do_table);
+ do_table_inited= 0;
+ }
+
+ return status;
+}
+
+
+int
+Rpl_filter::set_ignore_table(const char* table_spec)
+{
+ int status;
+
+ if (ignore_table_inited)
+ my_hash_reset(&ignore_table);
+
+ status= parse_filter_rule(table_spec, &Rpl_filter::add_ignore_table);
+
+ if (!ignore_table.records)
+ {
+ my_hash_free(&ignore_table);
+ ignore_table_inited= 0;
+ }
+
+ return status;
+}
+
+
int
Rpl_filter::add_wild_do_table(const char* table_spec)
{
@@ -307,6 +398,46 @@ Rpl_filter::add_wild_ignore_table(const char* table_spec)
}
+int
+Rpl_filter::set_wild_do_table(const char* table_spec)
+{
+ int status;
+
+ if (wild_do_table_inited)
+ free_string_array(&wild_do_table);
+
+ status= parse_filter_rule(table_spec, &Rpl_filter::add_wild_do_table);
+
+ if (!wild_do_table.elements)
+ {
+ delete_dynamic(&wild_do_table);
+ wild_do_table_inited= 0;
+ }
+
+ return status;
+}
+
+
+int
+Rpl_filter::set_wild_ignore_table(const char* table_spec)
+{
+ int status;
+
+ if (wild_ignore_table_inited)
+ free_string_array(&wild_ignore_table);
+
+ status= parse_filter_rule(table_spec, &Rpl_filter::add_wild_ignore_table);
+
+ if (!wild_ignore_table.elements)
+ {
+ delete_dynamic(&wild_ignore_table);
+ wild_ignore_table_inited= 0;
+ }
+
+ return status;
+}
+
+
void
Rpl_filter::add_db_rewrite(const char* from_db, const char* to_db)
{
@@ -355,25 +486,59 @@ Rpl_filter::add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec)
}
-void
+int
+Rpl_filter::add_string_list(I_List<i_string> *list, const char* spec)
+{
+ char *str;
+ i_string *node;
+
+ if (! (str= my_strdup(spec, MYF(MY_WME))))
+ return true;
+
+ if (! (node= new i_string(str)))
+ {
+ my_free(str);
+ return true;
+ }
+
+ list->push_back(node);
+
+ return false;
+}
+
+
+int
Rpl_filter::add_do_db(const char* table_spec)
{
DBUG_ENTER("Rpl_filter::add_do_db");
- i_string *db = new i_string(table_spec);
- do_db.push_back(db);
- DBUG_VOID_RETURN;
+ DBUG_RETURN(add_string_list(&do_db, table_spec));
}
-void
+int
Rpl_filter::add_ignore_db(const char* table_spec)
{
DBUG_ENTER("Rpl_filter::add_ignore_db");
- i_string *db = new i_string(table_spec);
- ignore_db.push_back(db);
- DBUG_VOID_RETURN;
+ DBUG_RETURN(add_string_list(&ignore_db, table_spec));
}
+
+int
+Rpl_filter::set_do_db(const char* db_spec)
+{
+ free_string_list(&do_db);
+ return parse_filter_rule(db_spec, &Rpl_filter::add_do_db);
+}
+
+
+int
+Rpl_filter::set_ignore_db(const char* db_spec)
+{
+ free_string_list(&ignore_db);
+ return parse_filter_rule(db_spec, &Rpl_filter::add_ignore_db);
+}
+
+
extern "C" uchar *get_table_key(const uchar *, size_t *, my_bool);
extern "C" void free_table_ent(void* a);
@@ -448,6 +613,23 @@ Rpl_filter::free_string_array(DYNAMIC_ARRAY *a)
}
+void
+Rpl_filter::free_string_list(I_List<i_string> *l)
+{
+ void *ptr;
+ i_string *tmp;
+
+ while ((tmp= l->get()))
+ {
+ ptr= (void *) tmp->ptr;
+ my_free(ptr);
+ delete tmp;
+ }
+
+ l->empty();
+}
+
+
/*
Builds a String from a HASH of TABLE_RULE_ENT. Cannot be used for any other
hash, as it assumes that the hash entries are TABLE_RULE_ENT.
@@ -564,3 +746,37 @@ Rpl_filter::get_ignore_db()
{
return &ignore_db;
}
+
+
+void
+Rpl_filter::db_rule_ent_list_to_str(String* str, I_List<i_string>* list)
+{
+ I_List_iterator<i_string> it(*list);
+ i_string* s;
+
+ str->length(0);
+
+ while ((s= it++))
+ {
+ str->append(s->ptr);
+ str->append(',');
+ }
+
+ // Remove last ','
+ if (!str->is_empty())
+ str->chop();
+}
+
+
+void
+Rpl_filter::get_do_db(String* str)
+{
+ db_rule_ent_list_to_str(str, get_do_db());
+}
+
+
+void
+Rpl_filter::get_ignore_db(String* str)
+{
+ db_rule_ent_list_to_str(str, get_ignore_db());
+}
diff --git a/sql/rpl_filter.h b/sql/rpl_filter.h
index d32fb36d6fb..2eb0340b714 100644
--- a/sql/rpl_filter.h
+++ b/sql/rpl_filter.h
@@ -61,11 +61,20 @@ public:
int add_do_table(const char* table_spec);
int add_ignore_table(const char* table_spec);
+ int set_do_table(const char* table_spec);
+ int set_ignore_table(const char* table_spec);
+
int add_wild_do_table(const char* table_spec);
int add_wild_ignore_table(const char* table_spec);
- void add_do_db(const char* db_spec);
- void add_ignore_db(const char* db_spec);
+ int set_wild_do_table(const char* table_spec);
+ int set_wild_ignore_table(const char* table_spec);
+
+ int add_do_db(const char* db_spec);
+ int add_ignore_db(const char* db_spec);
+
+ int set_do_db(const char* db_spec);
+ int set_ignore_db(const char* db_spec);
void add_db_rewrite(const char* from_db, const char* to_db);
@@ -83,6 +92,9 @@ public:
I_List<i_string>* get_do_db();
I_List<i_string>* get_ignore_db();
+ void get_do_db(String* str);
+ void get_ignore_db(String* str);
+
private:
bool table_rules_on;
@@ -92,13 +104,21 @@ private:
int add_table_rule(HASH* h, const char* table_spec);
int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec);
+ typedef int (Rpl_filter::*Add_filter)(char const*);
+
+ int parse_filter_rule(const char* spec, Add_filter func);
+
void free_string_array(DYNAMIC_ARRAY *a);
+ void free_string_list(I_List<i_string> *l);
void table_rule_ent_hash_to_str(String* s, HASH* h, bool inited);
void table_rule_ent_dynamic_array_to_str(String* s, DYNAMIC_ARRAY* a,
bool inited);
+ void db_rule_ent_list_to_str(String* s, I_List<i_string>* l);
TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len);
+ int add_string_list(I_List<i_string> *list, const char* spec);
+
/*
Those 4 structures below are uninitialized memory unless the
corresponding *_inited variables are "true".
diff --git a/sql/rpl_handler.h b/sql/rpl_handler.h
index 4d1bce45c54..4743fffb9a0 100644
--- a/sql/rpl_handler.h
+++ b/sql/rpl_handler.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
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/rpl_injector.cc b/sql/rpl_injector.cc
index c015ce62a99..ec1a96e8a2b 100644
--- a/sql/rpl_injector.cc
+++ b/sql/rpl_injector.cc
@@ -1,5 +1,4 @@
-/*
- Copyright (c) 2006, 2010, Oracle and/or its affiliates.
+/* Copyright (c) 2006, 2011, Oracle and/or its affiliates.
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/rpl_mi.cc b/sql/rpl_mi.cc
index ae2a4bbec01..3c5a99121fa 100644
--- a/sql/rpl_mi.cc
+++ b/sql/rpl_mi.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2006, 2010, Oracle and/or its affiliates.
+/* Copyright (c) 2006, 2012, Oracle and/or its affiliates.
Copyright (c) 2010, 2011, Monty Program Ab
This program is free software; you can redistribute it and/or modify
diff --git a/sql/rpl_mi.h b/sql/rpl_mi.h
index c98f7253b18..a885576ef1c 100644
--- a/sql/rpl_mi.h
+++ b/sql/rpl_mi.h
@@ -1,5 +1,4 @@
-/*
- Copyright (c) 2006, 2010, Oracle and/or its affiliates.
+/* Copyright (c) 2006, 2012, Oracle and/or its affiliates.
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/rpl_rli.cc b/sql/rpl_rli.cc
index da1fc98c3e1..e1efbc7ee4c 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -1,5 +1,4 @@
-/*
- Copyright (c) 2006, 2011, Oracle and/or its affiliates.
+/* Copyright (c) 2006, 2012, Oracle and/or its affiliates.
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/rpl_rli.h b/sql/rpl_rli.h
index fef910de65d..958002561bc 100644
--- a/sql/rpl_rli.h
+++ b/sql/rpl_rli.h
@@ -1,5 +1,4 @@
-/*
- Copyright (c) 2005, 2010, Oracle and/or its affiliates.
+/* Copyright (c) 2005, 2012, Oracle and/or its affiliates.
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
@@ -204,6 +203,13 @@ public:
bool ignore_log_space_limit;
/*
+ Used by the SQL thread to instructs the IO thread to rotate
+ the logs when the SQL thread needs to purge to release some
+ disk space.
+ */
+ bool sql_force_rotate_relay;
+
+ /*
When it commits, InnoDB internally stores the master log position it has
processed so far; the position to store is the one of the end of the
committing event (the COMMIT query event, or the event if in autocommit
diff --git a/sql/set_var.h b/sql/set_var.h
index c074f3f4399..6edfd6adb39 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -1,6 +1,6 @@
#ifndef SET_VAR_INCLUDED
#define SET_VAR_INCLUDED
-/* Copyright (c) 2002, 2010, Oracle and/or its affiliates.
+/* Copyright (c) 2002, 2011, Oracle and/or its affiliates.
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 73357b6c4a2..8510eb1f1ac 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -4701,14 +4701,14 @@ ER_NOT_SUPPORTED_YET 42000
spa "Esta versión de MariaDB no soporta todavia '%s'"
swe "Denna version av MariaDB kan ännu inte utföra '%s'"
ER_MASTER_FATAL_ERROR_READING_BINLOG
- nla "Kreeg fatale fout %d: '%-.512s' van master tijdens lezen van data uit binaire log"
- eng "Got fatal error %d from master when reading data from binary log: '%-.512s'"
- ger "Schwerer Fehler %d: '%-.512s vom Master beim Lesen des binären Logs"
- ita "Errore fatale %d: '%-.512s' dal master leggendo i dati dal log binario"
- por "Obteve fatal erro %d: '%-.512s' do master quando lendo dados do binary log"
- rus "Получена неисправимая ошибка %d: '%-.512s' от головного сервера в процессе выборки данных из двоичного журнала"
- spa "Recibió fatal error %d: '%-.512s' del master cuando leyendo datos del binary log"
- swe "Fick fatalt fel %d: '%-.512s' från master vid läsning av binärloggen"
+ nla "Kreeg fatale fout %d: '%-.320s' van master tijdens lezen van data uit binaire log"
+ eng "Got fatal error %d from master when reading data from binary log: '%-.320s'"
+ ger "Schwerer Fehler %d: '%-.320s vom Master beim Lesen des binären Logs"
+ ita "Errore fatale %d: '%-.320s' dal master leggendo i dati dal log binario"
+ por "Obteve fatal erro %d: '%-.320s' do master quando lendo dados do binary log"
+ rus "Получена неисправимая ошибка %d: '%-.320s' от головного сервера в процессе выборки данных из двоичного журнала"
+ spa "Recibió fatal error %d: '%-.320s' del master cuando leyendo datos del binary log"
+ swe "Fick fatalt fel %d: '%-.320s' från master vid läsning av binärloggen"
ER_SLAVE_IGNORED_TABLE
eng "Slave SQL thread ignored the query because of replicate-*-table rules"
ger "Slave-SQL-Thread hat die Abfrage aufgrund von replicate-*-table-Regeln ignoriert"
@@ -6486,6 +6486,16 @@ ER_PLUGIN_NO_UNINSTALL
ER_PLUGIN_NO_INSTALL
eng "Plugin '%s' is marked as not dynamically installable. You have to stop the server to install it."
+ER_BINLOG_UNSAFE_WRITE_AUTOINC_SELECT
+ eng "Statements writing to a table with an auto-increment column after selecting from another table are unsafe because the order in which rows are retrieved determines what (if any) rows will be written. This order cannot be predicted and may differ on master and the slave."
+
+ER_BINLOG_UNSAFE_CREATE_SELECT_AUTOINC
+ eng "CREATE TABLE... SELECT... on a table with an auto-increment column is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are inserted. This order cannot be predicted and may differ on master and the slave."
+
+#
+# End of 5.5 error messages.
+#
+
#
# MariaDB error messages section starts here
#
diff --git a/sql/signal_handler.cc b/sql/signal_handler.cc
index 0b5fce7758f..3e194805dbc 100644
--- a/sql/signal_handler.cc
+++ b/sql/signal_handler.cc
@@ -77,7 +77,7 @@ extern "C" sig_handler handle_fatal_signal(int sig)
curr_time= my_time(0);
localtime_r(&curr_time, &tm);
- fprintf(stderr, "%02d%02d%02d %2d:%02d:%02d ",
+ my_safe_printf_stderr("%02d%02d%02d %2d:%02d:%02d ",
tm.tm_year % 100, tm.tm_mon+1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec);
if (opt_expect_abort
@@ -139,6 +139,7 @@ extern "C" sig_handler handle_fatal_signal(int sig)
"Hope that's ok; if not, decrease some variables in the equation.\n\n");
#if defined(HAVE_LINUXTHREADS)
+#define UNSAFE_DEFAULT_LINUX_THREADS 200
if (sizeof(char*) == 4 && thread_count > UNSAFE_DEFAULT_LINUX_THREADS)
{
my_safe_printf_stderr(
diff --git a/sql/slave.cc b/sql/slave.cc
index 56f9c14703c..9f593b3075e 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2000, 2011, Oracle and/or its affiliates.
- Copyright (c) 2008-2011 Monty Program Ab
+/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
+ Copyright (c) 2008, 2011, 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
@@ -1339,7 +1339,7 @@ static int get_master_version_and_clock(MYSQL* mysql, Master_info* mi)
const char act[]=
"now "
"wait_for signal.get_unix_timestamp";
- DBUG_ASSERT(opt_debug_sync_timeout > 0);
+ DBUG_ASSERT(debug_sync_service);
DBUG_ASSERT(!debug_sync_set_action(current_thd,
STRING_WITH_LEN(act)));
};);
@@ -1389,7 +1389,7 @@ static int get_master_version_and_clock(MYSQL* mysql, Master_info* mi)
const char act[]=
"now "
"wait_for signal.get_server_id";
- DBUG_ASSERT(opt_debug_sync_timeout > 0);
+ DBUG_ASSERT(debug_sync_service);
DBUG_ASSERT(!debug_sync_set_action(current_thd,
STRING_WITH_LEN(act)));
};);
@@ -1788,6 +1788,54 @@ Waiting for the slave SQL thread to free enough relay log space");
!(slave_killed=io_slave_killed(thd,mi)) &&
!rli->ignore_log_space_limit)
mysql_cond_wait(&rli->log_space_cond, &rli->log_space_lock);
+
+ /*
+ Makes the IO thread read only one event at a time
+ until the SQL thread is able to purge the relay
+ logs, freeing some space.
+
+ Therefore, once the SQL thread processes this next
+ event, it goes to sleep (no more events in the queue),
+ sets ignore_log_space_limit=true and wakes the IO thread.
+ However, this event may have been enough already for
+ the SQL thread to purge some log files, freeing
+ rli->log_space_total .
+
+ This guarantees that the SQL and IO thread move
+ forward only one event at a time (to avoid deadlocks),
+ when the relay space limit is reached. It also
+ guarantees that when the SQL thread is prepared to
+ rotate (to be able to purge some logs), the IO thread
+ will know about it and will rotate.
+
+ NOTE: The ignore_log_space_limit is only set when the SQL
+ thread sleeps waiting for events.
+
+ */
+ if (rli->ignore_log_space_limit)
+ {
+#ifndef DBUG_OFF
+ {
+ char llbuf1[22], llbuf2[22];
+ DBUG_PRINT("info", ("log_space_limit=%s "
+ "log_space_total=%s "
+ "ignore_log_space_limit=%d "
+ "sql_force_rotate_relay=%d",
+ llstr(rli->log_space_limit,llbuf1),
+ llstr(rli->log_space_total,llbuf2),
+ (int) rli->ignore_log_space_limit,
+ (int) rli->sql_force_rotate_relay));
+ }
+#endif
+ if (rli->sql_force_rotate_relay)
+ {
+ rotate_relay_log(rli->mi);
+ rli->sql_force_rotate_relay= false;
+ }
+
+ rli->ignore_log_space_limit= false;
+ }
+
thd->exit_cond(save_proc_info);
DBUG_RETURN(slave_killed);
}
@@ -3034,7 +3082,7 @@ connected:
const char act[]=
"now "
"wait_for signal.io_thread_let_running";
- DBUG_ASSERT(opt_debug_sync_timeout > 0);
+ DBUG_ASSERT(debug_sync_service);
DBUG_ASSERT(!debug_sync_set_action(thd,
STRING_WITH_LEN(act)));
};);
@@ -5058,19 +5106,45 @@ static Log_event* next_event(Relay_log_info* rli)
constraint, because we do not want the I/O thread to block because of
space (it's ok if it blocks for any other reason (e.g. because the
master does not send anything). Then the I/O thread stops waiting
- and reads more events.
- The SQL thread decides when the I/O thread should take log_space_limit
- into account again : ignore_log_space_limit is reset to 0
- in purge_first_log (when the SQL thread purges the just-read relay
- log), and also when the SQL thread starts. We should also reset
- ignore_log_space_limit to 0 when the user does RESET SLAVE, but in
- fact, no need as RESET SLAVE requires that the slave
+ and reads one more event and starts honoring log_space_limit again.
+
+ If the SQL thread needs more events to be able to rotate the log (it
+ might need to finish the current group first), then it can ask for one
+ more at a time. Thus we don't outgrow the relay log indefinitely,
+ but rather in a controlled manner, until the next rotate.
+
+ When the SQL thread starts it sets ignore_log_space_limit to false.
+ We should also reset ignore_log_space_limit to 0 when the user does
+ RESET SLAVE, but in fact, no need as RESET SLAVE requires that the slave
be stopped, and the SQL thread sets ignore_log_space_limit to 0 when
it stops.
*/
mysql_mutex_lock(&rli->log_space_lock);
- // prevent the I/O thread from blocking next times
- rli->ignore_log_space_limit= 1;
+
+ /*
+ If we have reached the limit of the relay space and we
+ are going to sleep, waiting for more events:
+
+ 1. If outside a group, SQL thread asks the IO thread
+ to force a rotation so that the SQL thread purges
+ logs next time it processes an event (thus space is
+ freed).
+
+ 2. If in a group, SQL thread asks the IO thread to
+ ignore the limit and queues yet one more event
+ so that the SQL thread finishes the group and
+ is are able to rotate and purge sometime soon.
+ */
+ if (rli->log_space_limit &&
+ rli->log_space_limit < rli->log_space_total)
+ {
+ /* force rotation if not in an unfinished group */
+ rli->sql_force_rotate_relay= !rli->is_in_group();
+
+ /* ask for one more event */
+ rli->ignore_log_space_limit= true;
+ }
+
/*
If the I/O thread is blocked, unblock it. Ok to broadcast
after unlock, because the mutex is only destroyed in
diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc
index f88aed7ab3d..14f49ecc077 100644
--- a/sql/sp_cache.cc
+++ b/sql/sp_cache.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
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/sp_cache.h b/sql/sp_cache.h
index ba70bf32400..b21d4c4bf25 100644
--- a/sql/sp_cache.h
+++ b/sql/sp_cache.h
@@ -1,5 +1,5 @@
/* -*- C++ -*- */
-/* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
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/sp_head.cc b/sql/sp_head.cc
index 355b6f1788c..9a356cb3321 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -158,7 +158,7 @@ sp_get_item_value(THD *thd, Item *item, String *str)
buf.append(result->charset()->csname);
if (cs->escape_with_backslash_is_dangerous)
buf.append(' ');
- append_query_string(cs, result, &buf);
+ append_query_string(thd, cs, result, &buf);
buf.append(" COLLATE '");
buf.append(item->collation.collation->name);
buf.append('\'');
@@ -3557,6 +3557,23 @@ sp_instr_hpush_jump::opt_mark(sp_head *sp, List<sp_instr> *leads)
m_optdest= sp->get_instr(m_dest);
}
sp->add_mark_lead(m_dest, leads);
+
+ /*
+ For continue handlers, all instructions in the scope of the handler
+ are possible leads. For example, the instruction after freturn might
+ be executed if the freturn triggers the condition handled by the
+ continue handler.
+
+ m_dest marks the start of the handler scope. It's added as a lead
+ above, so we start on m_dest+1 here.
+ m_opt_hpop is the hpop marking the end of the handler scope.
+ */
+ if (m_type == SP_HANDLER_CONTINUE)
+ {
+ for (uint scope_ip= m_dest+1; scope_ip <= m_opt_hpop; scope_ip++)
+ sp->add_mark_lead(scope_ip, leads);
+ }
+
return m_ip+1;
}
diff --git a/sql/sp_head.h b/sql/sp_head.h
index c79b5dfbd0b..409db33ef02 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -1017,7 +1017,7 @@ class sp_instr_hpush_jump : public sp_instr_jump
public:
sp_instr_hpush_jump(uint ip, sp_pcontext *ctx, int htype, uint fp)
- : sp_instr_jump(ip, ctx), m_type(htype), m_frame(fp)
+ : sp_instr_jump(ip, ctx), m_type(htype), m_frame(fp), m_opt_hpop(0)
{
m_cond.empty();
}
@@ -1039,6 +1039,15 @@ public:
return m_ip;
}
+ virtual void backpatch(uint dest, sp_pcontext *dst_ctx)
+ {
+ DBUG_ASSERT(!m_dest || !m_opt_hpop);
+ if (!m_dest)
+ m_dest= dest;
+ else
+ m_opt_hpop= dest;
+ }
+
inline void add_condition(struct sp_cond_type *cond)
{
m_cond.push_front(cond);
@@ -1048,6 +1057,7 @@ private:
int m_type; ///< Handler type
uint m_frame;
+ uint m_opt_hpop; // hpop marking end of handler scope.
List<struct sp_cond_type> m_cond;
}; // class sp_instr_hpush_jump : public sp_instr_jump
diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc
index b33442d66b3..46637bf10a4 100644
--- a/sql/sql_admin.cc
+++ b/sql/sql_admin.cc
@@ -443,12 +443,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0));
DBUG_RETURN(TRUE);
}
- uint num_parts_found;
- uint num_parts_opt= alter_info->partition_names.elements;
- num_parts_found= set_part_state(alter_info, table->table->part_info,
- PART_ADMIN);
- if (num_parts_found != num_parts_opt &&
- (!(alter_info->flags & ALTER_ALL_PARTITION)))
+ if (set_part_state(alter_info, table->table->part_info, PART_ADMIN))
{
char buff[FN_REFLEN + MYSQL_ERRMSG_SIZE];
size_t length;
@@ -910,6 +905,9 @@ send_result_message:
DBUG_RETURN(FALSE);
err:
+ /* Make sure this table instance is not reused after the failure. */
+ if (table && table->table)
+ table->table->m_needs_reopen= true;
trans_rollback_stmt(thd);
trans_rollback(thd);
close_thread_tables(thd); // Shouldn't be needed
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 63cc075918b..62db3b2e823 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2000, 2011, Oracle and/or its affiliates.
+/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
Copyright (c) 2010, 2011 Monty Program Ab
This program is free software; you can redistribute it and/or modify
@@ -217,7 +217,8 @@ static bool auto_repair_table(THD *thd, TABLE_LIST *table_list);
static void free_cache_entry(TABLE *entry);
static bool
has_write_table_with_auto_increment(TABLE_LIST *tables);
-
+static bool
+has_write_table_with_auto_increment_and_select(TABLE_LIST *tables);
uint cached_open_tables(void)
{
@@ -520,7 +521,7 @@ static void table_def_use_table(THD *thd, TABLE *table)
static void table_def_unuse_table(TABLE *table)
{
- THD *thd= table->in_use;
+ THD *thd __attribute__((unused))= table->in_use;
DBUG_ASSERT(table->in_use);
/* We shouldn't put the table to 'unused' list if the share is old. */
@@ -5736,9 +5737,20 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count,
*(ptr++)= table->table;
}
+ /*
+ DML statements that modify a table with an auto_increment column based on
+ rows selected from a table are unsafe as the order in which the rows are
+ fetched fron the select tables cannot be determined and may differ on
+ master and slave.
+ */
+ if (thd->variables.binlog_format != BINLOG_FORMAT_ROW && tables &&
+ has_write_table_with_auto_increment_and_select(tables))
+ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_WRITE_AUTOINC_SELECT);
+
/* We have to emulate LOCK TABLES if we are statement needs prelocking. */
if (thd->lex->requires_prelocking())
{
+
/*
A query that modifies autoinc column in sub-statement can make the
master and slave inconsistent.
@@ -6157,15 +6169,22 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list,
*/
if (*ref && !(*ref)->is_autogenerated_name)
{
- if (register_tree_change &&
- thd->stmt_arena->is_stmt_prepare_or_first_stmt_execute())
- arena= thd->activate_stmt_arena_if_needed(&backup);
- item->set_name((*ref)->name, (*ref)->name_length,
- system_charset_info);
- item->real_item()->set_name((*ref)->name, (*ref)->name_length,
- system_charset_info);
- if (arena)
- thd->restore_active_arena(arena, &backup);
+ if (register_tree_change)
+ {
+ item->set_name_for_rollback(thd, (*ref)->name,
+ (*ref)->name_length,
+ system_charset_info);
+ item->real_item()->set_name_for_rollback(thd, (*ref)->name,
+ (*ref)->name_length,
+ system_charset_info);
+ }
+ else
+ {
+ item->set_name((*ref)->name, (*ref)->name_length,
+ system_charset_info);
+ item->real_item()->set_name((*ref)->name, (*ref)->name_length,
+ system_charset_info);
+ }
}
if (register_tree_change)
thd->change_item_tree(ref, item);
@@ -7447,6 +7466,14 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
*/
result= FALSE;
+ /*
+ Save the lists made during natural join matching (because
+ the matching done only once but we need the list in case
+ of prepared statements).
+ */
+ table_ref_1->persistent_used_items= table_ref_1->used_items;
+ table_ref_2->persistent_used_items= table_ref_2->used_items;
+
err:
if (arena)
thd->restore_active_arena(arena, &backup);
@@ -8810,14 +8837,9 @@ fill_record(THD * thd, List<Item> &fields, List<Item> &values,
}
/* Update virtual fields*/
thd->abort_on_warning= FALSE;
- if (vcol_table)
- {
- if (vcol_table->vfield)
- {
- if (update_virtual_fields(thd, vcol_table, TRUE))
- goto err;
- }
- }
+ if (vcol_table && vcol_table->vfield &&
+ update_virtual_fields(thd, vcol_table, TRUE))
+ goto err;
thd->abort_on_warning= save_abort_on_warning;
thd->no_errors= save_no_errors;
DBUG_RETURN(thd->is_error());
@@ -9418,6 +9440,41 @@ has_write_table_with_auto_increment(TABLE_LIST *tables)
return 0;
}
+/*
+ checks if we have select tables in the table list and write tables
+ with auto-increment column.
+
+ SYNOPSIS
+ has_two_write_locked_tables_with_auto_increment_and_select
+ tables Table list
+
+ RETURN VALUES
+
+ -true if the table list has atleast one table with auto-increment column
+
+
+ and atleast one table to select from.
+ -false otherwise
+*/
+
+static bool
+has_write_table_with_auto_increment_and_select(TABLE_LIST *tables)
+{
+ bool has_select= false;
+ bool has_auto_increment_tables = has_write_table_with_auto_increment(tables);
+ for(TABLE_LIST *table= tables; table; table= table->next_global)
+ {
+ if (!table->placeholder() &&
+ (table->lock_type <= TL_READ_NO_INSERT))
+ {
+ has_select= true;
+ break;
+ }
+ }
+ return(has_select && has_auto_increment_tables);
+}
+
+
/*
Open and lock system tables for read.
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 9c86b2838c4..210d259f364 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -1,5 +1,4 @@
-/*
- Copyright (c) 2000, 2010, Oracle and/or its affiliates.
+/* Copyright (c) 2000, 2011, Oracle and/or its affiliates.
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_class.cc b/sql/sql_class.cc
index d7d0c8d3f68..169c68c1918 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -142,9 +142,9 @@ Key::Key(const Key &rhs, MEM_ROOT *mem_root)
*/
Foreign_key::Foreign_key(const Foreign_key &rhs, MEM_ROOT *mem_root)
- :Key(rhs),
+ :Key(rhs,mem_root),
ref_table(rhs.ref_table),
- ref_columns(rhs.ref_columns),
+ ref_columns(rhs.ref_columns,mem_root),
delete_opt(rhs.delete_opt),
update_opt(rhs.update_opt),
match_opt(rhs.match_opt)
@@ -3735,6 +3735,9 @@ void THD::restore_backup_open_tables_state(Open_tables_backup *backup)
extern "C" int thd_killed(const MYSQL_THD thd)
{
+ if (!thd)
+ thd= current_thd;
+
if (!(thd->killed & KILL_HARD_BIT))
return 0;
return thd->killed;
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
index 7157b1b109f..81a85f10a16 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -1,6 +1,6 @@
/*
- Copyright (c) 2007, 2011, Oracle and/or its affiliates.
- Copyright (c) 2008-2012 Monty Program Ab
+ Copyright (c) 2007, 2012, Oracle and/or its affiliates.
+ Copyright (c) 2008, 2012, 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/sql_delete.cc b/sql/sql_delete.cc
index 351e38ec4f1..bbcc212b1ba 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -328,7 +328,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
while (!(error=info.read_record(&info)) && !thd->killed &&
! thd->is_error())
{
- update_virtual_fields(thd, table);
+ if (table->vfield)
+ update_virtual_fields(thd, table);
thd->examined_row_count++;
// thd->is_error() is tested to disallow delete row on error
if (!select || select->skip_record(thd) > 0)
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index c67618f0680..d03b38171fc 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -922,7 +922,8 @@ retry:
goto ok;
}
/* Generate values for virtual fields */
- update_virtual_fields(thd, table);
+ if (table->vfield)
+ update_virtual_fields(thd, table);
if (cond && !cond->val_int())
{
if (thd->is_error())
diff --git a/sql/sql_join_cache.cc b/sql/sql_join_cache.cc
index ba28cb8d0b0..f6fc2ebfd1e 100644
--- a/sql/sql_join_cache.cc
+++ b/sql/sql_join_cache.cc
@@ -3345,23 +3345,26 @@ int JOIN_TAB_SCAN::next()
int skip_rc;
READ_RECORD *info= &join_tab->read_record;
SQL_SELECT *select= join_tab->cache_select;
+ TABLE *table= join_tab->table;
+ THD *thd= join->thd;
+
if (is_first_record)
is_first_record= FALSE;
else
err= info->read_record(info);
- if (!err)
- update_virtual_fields(join->thd, join_tab->table);
- while (!err && select && (skip_rc= select->skip_record(join->thd)) <= 0)
+ if (!err && table->vfield)
+ update_virtual_fields(thd, table);
+ while (!err && select && (skip_rc= select->skip_record(thd)) <= 0)
{
- if (join->thd->killed || skip_rc < 0)
+ if (thd->killed || skip_rc < 0)
return 1;
/*
Move to the next record if the last retrieved record does not
meet the condition pushed to the table join_tab.
*/
err= info->read_record(info);
- if (!err)
- update_virtual_fields(join->thd, join_tab->table);
+ if (!err && table->vfield)
+ update_virtual_fields(thd, table);
}
return err;
}
@@ -3875,7 +3878,8 @@ int JOIN_TAB_SCAN_MRR::next()
*/
DBUG_ASSERT(cache->buff <= (uchar *) (*ptr) &&
(uchar *) (*ptr) <= cache->end_pos);
- update_virtual_fields(join->thd, join_tab->table);
+ if (join_tab->table->vfield)
+ update_virtual_fields(join->thd, join_tab->table);
}
return rc;
}
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index b2dfae5ded4..246f03a7754 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1,5 +1,4 @@
-/*
- Copyright (c) 2000, 2011, Oracle and/or its affiliates.
+/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
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
@@ -63,9 +62,11 @@ Query_tables_list::binlog_stmt_unsafe_errcode[BINLOG_STMT_UNSAFE_COUNT] =
ER_BINLOG_UNSAFE_MIXED_STATEMENT,
ER_BINLOG_UNSAFE_INSERT_IGNORE_SELECT,
ER_BINLOG_UNSAFE_INSERT_SELECT_UPDATE,
+ ER_BINLOG_UNSAFE_WRITE_AUTOINC_SELECT,
ER_BINLOG_UNSAFE_REPLACE_SELECT,
ER_BINLOG_UNSAFE_CREATE_IGNORE_SELECT,
ER_BINLOG_UNSAFE_CREATE_REPLACE_SELECT,
+ ER_BINLOG_UNSAFE_CREATE_SELECT_AUTOINC,
ER_BINLOG_UNSAFE_UPDATE_IGNORE
};
@@ -470,6 +471,8 @@ void lex_start(THD *thd)
lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED;
lex->select_lex.init_order();
lex->select_lex.group_list.empty();
+ if (lex->select_lex.group_list_ptrs)
+ lex->select_lex.group_list_ptrs->clear();
lex->describe= 0;
lex->subqueries= FALSE;
lex->context_analysis_only= 0;
@@ -1880,6 +1883,8 @@ void st_select_lex::init_select()
sj_nests.empty();
sj_subselects.empty();
group_list.empty();
+ if (group_list_ptrs)
+ group_list_ptrs->clear();
type= db= 0;
having= 0;
table_join_options= 0;
@@ -3287,6 +3292,8 @@ static void fix_prepare_info_in_table_list(THD *thd, TABLE_LIST *tbl)
The passed WHERE and HAVING are to be saved for the future executions.
This function saves it, and returns a copy which can be thrashed during
this execution of the statement. By saving/thrashing here we mean only
+ We also save the chain of ORDER::next in group_list, in case
+ the list is modified by remove_const().
AND/OR trees.
The function also calls fix_prepare_info_in_table_list that saves all
ON expressions.
@@ -3298,6 +3305,19 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds,
if (!thd->stmt_arena->is_conventional() && first_execution)
{
first_execution= 0;
+ if (group_list.first)
+ {
+ if (!group_list_ptrs)
+ {
+ void *mem= thd->stmt_arena->alloc(sizeof(Group_list_ptrs));
+ group_list_ptrs= new (mem) Group_list_ptrs(thd->stmt_arena->mem_root);
+ }
+ group_list_ptrs->reserve(group_list.elements);
+ for (ORDER *order= group_list.first; order; order= order->next)
+ {
+ group_list_ptrs->push_back(order);
+ }
+ }
if (*conds)
{
thd->check_and_register_item_tree(&prep_where, conds);
@@ -4186,3 +4206,7 @@ void binlog_unsafe_map_init()
BINLOG_DIRECT_OFF & TRX_CACHE_NOT_EMPTY);
}
#endif
+
+#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
+template class Mem_root_array<ORDER*, true>;
+#endif
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 718c9c7e6a2..f1ee6cf22ec 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -1,5 +1,4 @@
-/*
- Copyright (c) 2000, 2011, Oracle and/or its affiliates.
+/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
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
@@ -25,6 +24,7 @@
#include "sql_trigger.h"
#include "item.h" /* From item_subselect.h: subselect_union_engine */
#include "thr_lock.h" /* thr_lock_type, TL_UNLOCK */
+#include "mem_root_array.h"
/* YACC and LEX Definitions */
@@ -262,6 +262,7 @@ enum enum_drop_mode
#define TL_OPTION_ALIAS 8
typedef List<Item> List_item;
+typedef Mem_root_array<ORDER*, true> Group_list_ptrs;
/* SERVERS CACHE CHANGES */
typedef struct st_lex_server_options
@@ -736,7 +737,16 @@ public:
enum olap_type olap;
/* FROM clause - points to the beginning of the TABLE_LIST::next_local list. */
SQL_I_List<TABLE_LIST> table_list;
- SQL_I_List<ORDER> group_list; /* GROUP BY clause. */
+
+ /*
+ GROUP BY clause.
+ This list may be mutated during optimization (by remove_const()),
+ so for prepared statements, we keep a copy of the ORDER.next pointers in
+ group_list_ptrs, and re-establish the original list before each execution.
+ */
+ SQL_I_List<ORDER> group_list;
+ Group_list_ptrs *group_list_ptrs;
+
List<Item> item_list; /* list of fields & expressions */
List<String> interval_list;
bool is_item_list_lookup;
@@ -942,7 +952,8 @@ public:
bool test_limit();
friend void lex_start(THD *thd);
- st_select_lex() : n_sum_items(0), n_child_sum_items(0) {}
+ st_select_lex() : group_list_ptrs(NULL), n_sum_items(0), n_child_sum_items(0)
+ {}
void make_empty_select()
{
init_query();
@@ -1374,6 +1385,13 @@ public:
BINLOG_STMT_UNSAFE_INSERT_SELECT_UPDATE,
/**
+ Query that writes to a table with auto_inc column after selecting from
+ other tables are unsafe as the order in which the rows are retrieved by
+ select may differ on master and slave.
+ */
+ BINLOG_STMT_UNSAFE_WRITE_AUTOINC_SELECT,
+
+ /**
INSERT...REPLACE SELECT is unsafe because which rows are replaced depends
on the order that rows are retrieved by SELECT. This order cannot be
predicted and may differ on master and the slave.
@@ -1395,6 +1413,14 @@ public:
BINLOG_STMT_UNSAFE_CREATE_REPLACE_SELECT,
/**
+ CREATE TABLE...SELECT on a table with auto-increment column is unsafe
+ because which rows are replaced depends on the order that rows are
+ retrieved from SELECT. This order cannot be predicted and may differ on
+ master and the slave
+ */
+ BINLOG_STMT_UNSAFE_CREATE_SELECT_AUTOINC,
+
+ /**
UPDATE...IGNORE is unsafe because which rows are ignored depends on the
order that rows are updated. This order cannot be predicted and may differ
on master and the slave.
diff --git a/sql/sql_list.h b/sql/sql_list.h
index 6cc05ff1f62..e3a04c36071 100644
--- a/sql/sql_list.h
+++ b/sql/sql_list.h
@@ -260,6 +260,7 @@ public:
last= &first;
return tmp->info;
}
+
/*
Remove from this list elements that are contained in the passed list.
We assume that the passed list is a tail of this list (that is, the whole
diff --git a/sql/sql_logger.cc b/sql/sql_logger.cc
deleted file mode 100644
index fe3c9a87d20..00000000000
--- a/sql/sql_logger.cc
+++ /dev/null
@@ -1,183 +0,0 @@
-/* Copyright (C) 2012 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
- the Free Software Foundation; version 2 of the License.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-
-#include "my_global.h"
-#include <my_sys.h>
-#include <mysql/service_logger.h>
-
-extern char *mysql_data_home;
-extern PSI_mutex_key key_LOCK_logger_service;
-
-typedef struct logger_handle_st {
- File file;
- char path[FN_REFLEN];
- unsigned long long size_limit;
- unsigned int rotations;
- size_t path_len;
- mysql_mutex_t lock;
-} LSFS;
-
-
-#define LOG_FLAGS (O_APPEND | O_CREAT | O_WRONLY)
-
-static unsigned int n_dig(unsigned int i)
-{
- return (i == 0) ? 0 : ((i < 10) ? 1 : ((i < 100) ? 2 : 3));
-}
-
-
-LOGGER_HANDLE *logger_open(const char *path,
- unsigned long long size_limit,
- unsigned int rotations)
-{
- LOGGER_HANDLE new_log, *l_perm;
-
- /*
- I don't think we ever need more rotations,
- but if it's so, the rotation procedure should be adapted to it.
- */
- if (rotations > 999)
- return 0;
-
- new_log.rotations= rotations;
- new_log.size_limit= size_limit;
- new_log.path_len= strlen(fn_format(new_log.path, path,
- mysql_data_home, "", MY_UNPACK_FILENAME));
-
- if (new_log.path_len+n_dig(rotations)+1 > FN_REFLEN)
- {
- errno= ENAMETOOLONG;
- /* File path too long */
- return 0;
- }
- if ((new_log.file= my_open(new_log.path, LOG_FLAGS, MYF(0))) < 0)
- {
- errno= my_errno;
- /* Check errno for the cause */
- return 0;
- }
-
- if (!(l_perm= (LOGGER_HANDLE *) my_malloc(sizeof(LOGGER_HANDLE), MYF(0))))
- {
- my_close(new_log.file, MYF(0));
- new_log.file= -1;
- return 0; /* End of memory */
- }
- *l_perm= new_log;
- mysql_mutex_init(key_LOCK_logger_service, &l_perm->lock, MY_MUTEX_INIT_FAST);
- return l_perm;
-}
-
-int logger_close(LOGGER_HANDLE *log)
-{
- int result;
- File file= log->file;
- mysql_mutex_destroy(&log->lock);
- my_free(log);
- if ((result= my_close(file, MYF(0))))
- errno= my_errno;
- return result;
-}
-
-
-static char *logname(LOGGER_HANDLE *log, char *buf, unsigned int n_log)
-{
- sprintf(buf+log->path_len, ".%0*u", n_dig(log->rotations), n_log);
- return buf;
-}
-
-
-static int do_rotate(LOGGER_HANDLE *log)
-{
- char namebuf[FN_REFLEN];
- int result;
- unsigned int i;
- char *buf_old, *buf_new, *tmp;
-
- memcpy(namebuf, log->path, log->path_len);
-
- buf_new= logname(log, namebuf, log->rotations);
- buf_old= log->path;
- for (i=log->rotations-1; i>0; i--)
- {
- logname(log, buf_old, i);
- if (!access(buf_old, F_OK) &&
- (result= my_rename(buf_old, buf_new, MYF(0))))
- goto exit;
- tmp= buf_old;
- buf_old= buf_new;
- buf_new= tmp;
- }
- if ((result= my_close(log->file, MYF(0))))
- goto exit;
- namebuf[log->path_len]= 0;
- result= my_rename(namebuf, logname(log, log->path, 1), MYF(0));
- log->file= my_open(namebuf, LOG_FLAGS, MYF(0));
-exit:
- errno= my_errno;
- return log->file < 0 || result;
-}
-
-
-int logger_vprintf(LOGGER_HANDLE *log, const char* fmt, va_list ap)
-{
- int result;
- my_off_t filesize;
- char cvtbuf[1024];
- size_t n_bytes;
-
- mysql_mutex_lock(&log->lock);
- if ((filesize= my_tell(log->file, MYF(0))) == (my_off_t) -1 ||
- ((unsigned long long)filesize >= log->size_limit &&
- do_rotate(log)))
- {
- result= -1;
- errno= my_errno;
- goto exit; /* Log rotation needed but failed */
- }
-
- n_bytes= my_vsnprintf(cvtbuf, sizeof(cvtbuf), fmt, ap);
- if (n_bytes >= sizeof(cvtbuf))
- n_bytes= sizeof(cvtbuf) - 1;
-
- result= my_write(log->file, (uchar *) cvtbuf, n_bytes, MYF(0));
-
-exit:
- mysql_mutex_unlock(&log->lock);
- return result;
-}
-
-
-int logger_rotate(LOGGER_HANDLE *log)
-{
- int result;
- mysql_mutex_lock(&log->lock);
- result= do_rotate(log);
- mysql_mutex_unlock(&log->lock);
- return result;
-}
-
-
-int logger_printf(LOGGER_HANDLE *log, const char *fmt, ...)
-{
- int result;
- va_list args;
- va_start(args,fmt);
- result= logger_vprintf(log, fmt, args);
- va_end(args);
- return result;
-}
-
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index e0b2acd199d..70258629197 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1,6 +1,5 @@
-/*
- Copyright (c) 2000, 2011, Oracle and/or its affiliates.
- Copyright (c) 2008-2012 Monty Program Ab
+/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
+ Copyright (c) 2008, 2012, 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
@@ -2935,7 +2934,7 @@ end_with_restore_list:
const char act2[]=
"now "
"signal signal.continued";
- DBUG_ASSERT(opt_debug_sync_timeout > 0);
+ DBUG_ASSERT(debug_sync_service);
DBUG_ASSERT(!debug_sync_set_action(thd,
STRING_WITH_LEN(act1)));
DBUG_ASSERT(!debug_sync_set_action(thd,
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index 070b48f7a7b..9ba0569f1e0 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -4398,11 +4398,20 @@ error:
}
-/*
- Sets which partitions to be used in the command
+/**
+ Sets which partitions to be used in the command.
+
+ @param alter_info Alter_info pointer holding partition names and flags.
+ @param tab_part_info partition_info holding all partitions.
+ @param part_state Which state to set for the named partitions.
+
+ @return Operation status
+ @retval false Success
+ @retval true Failure
*/
-uint set_part_state(Alter_info *alter_info, partition_info *tab_part_info,
- enum partition_state part_state)
+
+bool set_part_state(Alter_info *alter_info, partition_info *tab_part_info,
+ enum partition_state part_state)
{
uint part_count= 0;
uint num_parts_found= 0;
@@ -4428,7 +4437,21 @@ uint set_part_state(Alter_info *alter_info, partition_info *tab_part_info,
else
part_elem->part_state= PART_NORMAL;
} while (++part_count < tab_part_info->num_parts);
- return num_parts_found;
+
+ if (num_parts_found != alter_info->partition_names.elements &&
+ !(alter_info->flags & ALTER_ALL_PARTITION))
+ {
+ /* Not all given partitions found, revert and return failure */
+ part_it.rewind();
+ part_count= 0;
+ do
+ {
+ partition_element *part_elem= part_it++;
+ part_elem->part_state= PART_NORMAL;
+ } while (++part_count < tab_part_info->num_parts);
+ return true;
+ }
+ return false;
}
@@ -4947,11 +4970,7 @@ that are reorganised.
}
else if (alter_info->flags & ALTER_REBUILD_PARTITION)
{
- uint num_parts_found;
- uint num_parts_opt= alter_info->partition_names.elements;
- num_parts_found= set_part_state(alter_info, tab_part_info, PART_CHANGED);
- if (num_parts_found != num_parts_opt &&
- (!(alter_info->flags & ALTER_ALL_PARTITION)))
+ if (set_part_state(alter_info, tab_part_info, PART_CHANGED))
{
my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "REBUILD");
goto err;
diff --git a/sql/sql_partition.h b/sql/sql_partition.h
index cc11d859903..2fd9b4c3d75 100644
--- a/sql/sql_partition.h
+++ b/sql/sql_partition.h
@@ -254,7 +254,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
char *db,
const char *table_name,
TABLE *fast_alter_table);
-uint set_part_state(Alter_info *alter_info, partition_info *tab_part_info,
+bool set_part_state(Alter_info *alter_info, partition_info *tab_part_info,
enum partition_state part_state);
uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
HA_CREATE_INFO *create_info,
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
index 39f69b2656d..0dc71550b73 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2005, 2011, Oracle and/or its affiliates.
+ Copyright (c) 2005, 2012, Oracle and/or its affiliates.
Copyright (c) 2010, 2011, Monty Program Ab
This program is free software; you can redistribute it and/or modify
@@ -1520,6 +1520,10 @@ int plugin_init(int *argc, char **argv, int flags)
goto err;
}
+ /* prepare debug_sync service */
+ DBUG_ASSERT(strcmp(list_of_services[5].name, "debug_sync_service") == 0);
+ list_of_services[5].service= *(void**)&debug_sync_C_callback_ptr;
+
mysql_mutex_lock(&LOCK_plugin);
initialized= 1;
@@ -2381,11 +2385,11 @@ static int check_func_bool(THD *thd, struct st_mysql_sys_var *var,
{
if (value->val_int(value, &tmp) < 0)
goto err;
- if (tmp > 1)
+ if (tmp != 0 && tmp != 1)
goto err;
result= (int) tmp;
}
- *(my_bool *) save= -result;
+ *(my_bool *) save= result ? 1 : 0;
return 0;
err:
return 1;
@@ -2575,7 +2579,7 @@ err:
static void update_func_bool(THD *thd, struct st_mysql_sys_var *var,
void *tgt, const void *save)
{
- *(my_bool *) tgt= *(my_bool *) save ? TRUE : FALSE;
+ *(my_bool *) tgt= *(my_bool *) save ? 1 : 0;
}
diff --git a/sql/sql_plugin_services.h b/sql/sql_plugin_services.h
index bd6d136585a..c779547059d 100644
--- a/sql/sql_plugin_services.h
+++ b/sql/sql_plugin_services.h
@@ -54,14 +54,6 @@ static struct progress_report_service_st progress_report_handler= {
set_thd_proc_info
};
-static struct logger_service_st logger_handler= {
- logger_open,
- logger_close,
- logger_vprintf,
- logger_printf,
- logger_rotate
-};
-
static struct st_service_ref list_of_services[]=
{
{ "my_snprintf_service", VERSION_my_snprintf, &my_snprintf_handler },
@@ -69,6 +61,6 @@ static struct st_service_ref list_of_services[]=
{ "thd_wait_service", VERSION_thd_wait, &thd_wait_handler },
{ "my_thread_scheduler_service", VERSION_my_thread_scheduler, &my_thread_scheduler_handler },
{ "progress_report_service", VERSION_progress_report, &progress_report_handler },
- { "logger_service", VERSION_logger, &logger_handler },
+ { "debug_sync_service", VERSION_debug_sync, 0 } // updated in plugin_init()
};
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index e25751a4b88..ed437c498e6 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2002, 2011, Oracle and/or its affiliates.
- Copyright (c) 2008-2011 Monty Program Ab
+/* Copyright (c) 2002, 2012, Oracle and/or its affiliates.
+ Copyright (c) 2008, 2011, 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
@@ -888,7 +888,7 @@ static bool insert_params_with_log(Prepared_statement *stmt, uchar *null_array,
*/
else if (! is_param_long_data_type(param))
DBUG_RETURN(1);
- res= param->query_val_str(&str);
+ res= param->query_val_str(thd, &str);
if (param->convert_str_value(thd))
DBUG_RETURN(1); /* out of memory */
@@ -1062,7 +1062,7 @@ static bool emb_insert_params_with_log(Prepared_statement *stmt,
DBUG_RETURN(1);
}
}
- res= param->query_val_str(&str);
+ res= param->query_val_str(thd, &str);
if (param->convert_str_value(thd))
DBUG_RETURN(1); /* out of memory */
@@ -1208,7 +1208,7 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
setup_one_conversion_function(thd, param, param->param_type);
if (param->set_from_user_var(thd, entry))
DBUG_RETURN(1);
- val= param->query_val_str(&buf);
+ val= param->query_val_str(thd, &buf);
if (param->convert_str_value(thd))
DBUG_RETURN(1); /* out of memory */
@@ -2512,6 +2512,14 @@ void reinit_stmt_before_use(THD *thd, LEX *lex)
DBUG_ASSERT(sl->join == 0);
ORDER *order;
/* Fix GROUP list */
+ if (sl->group_list_ptrs && sl->group_list_ptrs->size() > 0)
+ {
+ for (uint ix= 0; ix < sl->group_list_ptrs->size() - 1; ++ix)
+ {
+ order= sl->group_list_ptrs->at(ix);
+ order->next= sl->group_list_ptrs->at(ix+1);
+ }
+ }
for (order= sl->group_list.first; order; order= order->next)
order->item= &order->item_ptr;
/* Fix ORDER list */
diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc
index e743e474747..b3348698a35 100644
--- a/sql/sql_profile.cc
+++ b/sql/sql_profile.cc
@@ -1,6 +1,5 @@
-/*
- Copyright (c) 2007, 2010, Oracle and/or its affiliates.
- Copyright (c) 2008-2011 Monty Program Ab
+/* Copyright (c) 2007, 2011, Oracle and/or its affiliates.
+ Copyright (c) 2008, 2011, 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/sql_repl.cc b/sql/sql_repl.cc
index eb17ef0812c..b5c852f9b29 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -1,6 +1,5 @@
-/*
- Copyright (c) 2000, 2011, Oracle and/or its affiliates.
- Copyright (c) 2008-2011 Monty Program Ab
+/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
+ Copyright (c) 2008, 2011, 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
@@ -625,7 +624,6 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos,
String* const packet = &thd->packet;
int error;
const char *errmsg = "Unknown error", *tmp_msg;
- char llbuff0[22], llbuff1[22], llbuff2[22];
char error_text[MAX_SLAVE_ERRMSG]; // to be send to slave via my_message()
NET* net = &thd->net;
mysql_mutex_t *log_lock;
@@ -906,7 +904,7 @@ impossible position";
const char act[]=
"now "
"wait_for signal.continue";
- DBUG_ASSERT(opt_debug_sync_timeout > 0);
+ DBUG_ASSERT(debug_sync_service);
DBUG_ASSERT(!debug_sync_set_action(thd,
STRING_WITH_LEN(act)));
const char act2[]=
@@ -1181,12 +1179,14 @@ err:
detailing the fatal error message with coordinates
of the last position read.
*/
- const char *fmt= "%s; the start event position from '%s' at %s, the last event was read from '%s' at %s, the last byte read was read from '%s' at %s.";
- my_snprintf(error_text, sizeof(error_text), fmt, errmsg,
- my_basename(p_start_coord->file_name),
- (llstr(p_start_coord->pos, llbuff0), llbuff0),
- my_basename(p_coord->file_name), (llstr(p_coord->pos, llbuff1), llbuff1),
- my_basename(log_file_name), (llstr(my_b_tell(&log), llbuff2), llbuff2));
+ my_snprintf(error_text, sizeof(error_text),
+ "%s; the first event '%s' at %lld, "
+ "the last event read from '%s' at %lld, "
+ "the last byte read from '%s' at %lld.",
+ errmsg,
+ my_basename(p_start_coord->file_name), p_start_coord->pos,
+ my_basename(p_coord->file_name), p_coord->pos,
+ my_basename(log_file_name), my_b_tell(&log));
}
else
strcpy(error_text, errmsg);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 9d8a4265260..5279db17029 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -643,7 +643,7 @@ JOIN::prepare(Item ***rref_pointer_array,
*/
if (select_lex->master_unit()->item && // 1)
select_lex->first_cond_optimization && // 2)
- !(thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW)) // 3)
+ !thd->lex->is_view_context_analysis()) // 3)
{
remove_redundant_subquery_clauses(select_lex);
}
@@ -3085,12 +3085,11 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
key_map const_ref, eq_part;
bool has_expensive_keyparts;
TABLE **table_vector;
- JOIN_TAB *stat,*stat_end,*s,**stat_ref;
+ JOIN_TAB *stat,*stat_end,*s,**stat_ref, **stat_vector;
KEYUSE *keyuse,*start_keyuse;
table_map outer_join=0;
table_map no_rows_const_tables= 0;
SARGABLE_PARAM *sargables= 0;
- JOIN_TAB *stat_vector[MAX_TABLES+1];
List_iterator<TABLE_LIST> ti(tables_list);
TABLE_LIST *tables;
DBUG_ENTER("make_join_statistics");
@@ -3099,9 +3098,19 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
table_count=join->table_count;
stat=(JOIN_TAB*) join->thd->calloc(sizeof(JOIN_TAB)*(table_count));
- stat_ref=(JOIN_TAB**) join->thd->alloc(sizeof(JOIN_TAB*)*MAX_TABLES);
+ stat_ref=(JOIN_TAB**) join->thd->alloc(sizeof(JOIN_TAB*)*
+ (MAX_TABLES + table_count + 1));
+ stat_vector= stat_ref + MAX_TABLES;
table_vector=(TABLE**) join->thd->alloc(sizeof(TABLE*)*(table_count*2));
- if (!stat || !stat_ref || !table_vector)
+ join->positions= new (join->thd->mem_root) POSITION[(table_count+1)];
+ /*
+ best_positions is ok to allocate with alloc() as we copy things to it with
+ memcpy()
+ */
+ join->best_positions= (POSITION*) join->thd->alloc(sizeof(POSITION)*
+ (table_count +1));
+
+ if (join->thd->is_fatal_error)
DBUG_RETURN(1); // Eom /* purecov: inspected */
join->best_ref=stat_vector;
@@ -3123,6 +3132,12 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
error= tables->fetch_number_of_rows();
set_statistics_for_table(join->thd, table);
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ const bool no_partitions_used= table->no_partitions_used;
+#else
+ const bool no_partitions_used= FALSE;
+#endif
+
DBUG_EXECUTE_IF("bug11747970_raise_error",
{
if (!error)
@@ -3154,13 +3169,10 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
if (*s->on_expr_ref)
{
/* s is the only inner table of an outer join */
-#ifdef WITH_PARTITION_STORAGE_ENGINE
if (!table->is_filled_at_execution() &&
- (!table->stat_records() || table->no_partitions_used) && !embedding)
-#else
- if (!table->is_filled_at_execution() &&
- !table->stat_records() && !embedding)
-#endif
+ ((!table->file->stats.records &&
+ (table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT)) ||
+ no_partitions_used) && !embedding)
{ // Empty table
s->dependent= 0; // Ignore LEFT JOIN depend.
no_rows_const_tables |= table->map;
@@ -3200,16 +3212,12 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
if (inside_an_outer_join)
continue;
}
-#ifdef WITH_PARTITION_STORAGE_ENGINE
- const bool no_partitions_used= table->no_partitions_used;
-#else
- const bool no_partitions_used= FALSE;
-#endif
- if (!table->is_filled_at_execution() &&
- (table->s->system || table->stat_records() <= 1 ||
+ if (!table->is_filled_at_execution() &&
+ (table->s->system ||
+ (table->file->stats.records <= 1 &&
+ (table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT)) ||
no_partitions_used) &&
!s->dependent &&
- (table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT) &&
!table->fulltext_searched && !join->no_const_tables)
{
set_position(join,const_count++,s,(KEYUSE*) 0);
@@ -5758,6 +5766,114 @@ best_access_path(JOIN *join,
}
+/*
+ Find JOIN_TAB's embedding (i.e, parent) subquery.
+ - For merged semi-joins, tables inside the semi-join nest have their
+ semi-join nest as parent. We intentionally ignore results of table
+ pullout action here.
+ - For non-merged semi-joins (JTBM tabs), the embedding subquery is the
+ JTBM join tab itself.
+*/
+
+static TABLE_LIST* get_emb_subq(JOIN_TAB *tab)
+{
+ TABLE_LIST *tlist= tab->table->pos_in_table_list;
+ if (tlist->jtbm_subselect)
+ return tlist;
+ TABLE_LIST *embedding= tlist->embedding;
+ if (!embedding || !embedding->sj_subq_pred)
+ return NULL;
+ return embedding;
+}
+
+
+/*
+ Choose initial table order that "helps" semi-join optimizations.
+
+ The idea is that we should start with the order that is the same as the one
+ we would have had if we had semijoin=off:
+ - Top-level tables go first
+ - subquery tables are grouped together by the subquery they are in,
+ - subquery tables are attached where the subquery predicate would have been
+ attached if we had semi-join off.
+
+ This function relies on join_tab_cmp()/join_tab_cmp_straight() to produce
+ certain pre-liminary ordering, see compare_embedding_subqueries() for its
+ description.
+*/
+
+static void choose_initial_table_order(JOIN *join)
+{
+ TABLE_LIST *emb_subq;
+ JOIN_TAB **tab= join->best_ref + join->const_tables;
+ JOIN_TAB **tabs_end= tab + join->table_count - join->const_tables;
+ /* Find where the top-level JOIN_TABs end and subquery JOIN_TABs start */
+ for (; tab != tabs_end; tab++)
+ {
+ if ((emb_subq= get_emb_subq(*tab)))
+ break;
+ }
+ uint n_subquery_tabs= tabs_end - tab;
+
+ if (!n_subquery_tabs)
+ return;
+
+ /* Copy the subquery JOIN_TABs to a separate array */
+ JOIN_TAB *subquery_tabs[MAX_TABLES];
+ memcpy(subquery_tabs, tab, sizeof(JOIN_TAB*) * n_subquery_tabs);
+
+ JOIN_TAB **last_top_level_tab= tab;
+ JOIN_TAB **subq_tab= subquery_tabs;
+ JOIN_TAB **subq_tabs_end= subquery_tabs + n_subquery_tabs;
+ TABLE_LIST *cur_subq_nest= NULL;
+ for (; subq_tab < subq_tabs_end; subq_tab++)
+ {
+ if (get_emb_subq(*subq_tab)!= cur_subq_nest)
+ {
+ /*
+ Reached the part of subquery_tabs that covers tables in some subquery.
+ */
+ cur_subq_nest= get_emb_subq(*subq_tab);
+
+ /* Determine how many tables the subquery has */
+ JOIN_TAB **last_tab_for_subq;
+ for (last_tab_for_subq= subq_tab;
+ last_tab_for_subq < subq_tabs_end &&
+ get_emb_subq(*last_tab_for_subq) == cur_subq_nest;
+ last_tab_for_subq++) {}
+ uint n_subquery_tables= last_tab_for_subq - subq_tab;
+
+ /*
+ Walk the original array and find where this subquery would have been
+ attached to
+ */
+ table_map need_tables= cur_subq_nest->original_subq_pred_used_tables;
+ need_tables &= ~(join->const_table_map | PSEUDO_TABLE_BITS);
+ for (JOIN_TAB **top_level_tab= join->best_ref + join->const_tables;
+ top_level_tab < last_top_level_tab;
+ //top_level_tab < join->best_ref + join->table_count;
+ top_level_tab++)
+ {
+ need_tables &= ~(*top_level_tab)->table->map;
+ /* Check if this is the place where subquery should be attached */
+ if (!need_tables)
+ {
+ /* Move away the top-level tables that are after top_level_tab */
+ uint top_tail_len= last_top_level_tab - top_level_tab - 1;
+ memmove(top_level_tab + 1 + n_subquery_tables, top_level_tab + 1,
+ sizeof(JOIN_TAB*)*top_tail_len);
+ last_top_level_tab += n_subquery_tables;
+ memcpy(top_level_tab + 1, subq_tab, sizeof(JOIN_TAB*)*n_subquery_tables);
+ break;
+ }
+ }
+ DBUG_ASSERT(!need_tables);
+ subq_tab += n_subquery_tables - 1;
+ }
+ }
+}
+
+
/**
Selects and invokes a search strategy for an optimal query plan.
@@ -5813,9 +5929,21 @@ choose_plan(JOIN *join, table_map join_tables)
*/
jtab_sort_func= straight_join ? join_tab_cmp_straight : join_tab_cmp;
}
+
+ /*
+ psergey-todo: if we're not optimizing an SJM nest,
+ - sort that outer tables are first, and each sjm nest follows
+ - then, put each [sjm_table1, ... sjm_tableN] sub-array right where
+ WHERE clause pushdown would have put it.
+ */
my_qsort2(join->best_ref + join->const_tables,
join->table_count - join->const_tables, sizeof(JOIN_TAB*),
jtab_sort_func, (void*)join->emb_sjm_nest);
+
+ if (!join->emb_sjm_nest)
+ {
+ choose_initial_table_order(join);
+ }
join->cur_sj_inner_tables= 0;
if (straight_join)
@@ -5855,6 +5983,64 @@ choose_plan(JOIN *join, table_map join_tables)
}
+/*
+ Compare two join tabs based on the subqueries they are from.
+ - top-level join tabs go first
+ - then subqueries are ordered by their select_id (we're using this
+ criteria because we need a cross-platform, deterministic ordering)
+
+ @return
+ 0 - equal
+ -1 - jt1 < jt2
+ 1 - jt1 > jt2
+*/
+
+static int compare_embedding_subqueries(JOIN_TAB *jt1, JOIN_TAB *jt2)
+{
+ /* Determine if the first table is originally from a subquery */
+ TABLE_LIST *tbl1= jt1->table->pos_in_table_list;
+ uint tbl1_select_no;
+ if (tbl1->jtbm_subselect)
+ {
+ tbl1_select_no=
+ tbl1->jtbm_subselect->unit->first_select()->select_number;
+ }
+ else if (tbl1->embedding && tbl1->embedding->sj_subq_pred)
+ {
+ tbl1_select_no=
+ tbl1->embedding->sj_subq_pred->unit->first_select()->select_number;
+ }
+ else
+ tbl1_select_no= 1; /* Top-level */
+
+ /* Same for the second table */
+ TABLE_LIST *tbl2= jt2->table->pos_in_table_list;
+ uint tbl2_select_no;
+ if (tbl2->jtbm_subselect)
+ {
+ tbl2_select_no=
+ tbl2->jtbm_subselect->unit->first_select()->select_number;
+ }
+ else if (tbl2->embedding && tbl2->embedding->sj_subq_pred)
+ {
+ tbl2_select_no=
+ tbl2->embedding->sj_subq_pred->unit->first_select()->select_number;
+ }
+ else
+ tbl2_select_no= 1; /* Top-level */
+
+ /*
+ Put top-level tables in front. Tables from within subqueries must follow,
+ grouped by their owner subquery. We don't care about the order that
+ subquery groups are in, because choose_initial_table_order() will re-order
+ the groups.
+ */
+ if (tbl1_select_no != tbl2_select_no)
+ return tbl1_select_no > tbl2_select_no ? 1 : -1;
+ return 0;
+}
+
+
/**
Compare two JOIN_TAB objects based on the number of accessed records.
@@ -5871,6 +6057,9 @@ choose_plan(JOIN *join, table_map join_tables)
a: dependent = 0x0 table->map = 0x1 found_records = 3 ptr = 0x907e6b0
b: dependent = 0x0 table->map = 0x2 found_records = 3 ptr = 0x907e838
c: dependent = 0x6 table->map = 0x10 found_records = 2 ptr = 0x907ecd0
+
+ As for subuqueries, this function must produce order that can be fed to
+ choose_initial_table_order().
@retval
1 if first is bigger
@@ -5885,7 +6074,15 @@ join_tab_cmp(const void *dummy, const void* ptr1, const void* ptr2)
{
JOIN_TAB *jt1= *(JOIN_TAB**) ptr1;
JOIN_TAB *jt2= *(JOIN_TAB**) ptr2;
+ int cmp;
+ if ((cmp= compare_embedding_subqueries(jt1, jt2)) != 0)
+ return cmp;
+ /*
+ After that,
+ take care about ordering imposed by LEFT JOIN constraints,
+ possible [eq]ref accesses, and numbers of matching records in the table.
+ */
if (jt1->dependent & jt2->table->map)
return 1;
if (jt2->dependent & jt1->table->map)
@@ -5916,6 +6113,10 @@ join_tab_cmp_straight(const void *dummy, const void* ptr1, const void* ptr2)
DBUG_ASSERT(!jt1->emb_sj_nest);
DBUG_ASSERT(!jt2->emb_sj_nest);
+ int cmp;
+ if ((cmp= compare_embedding_subqueries(jt1, jt2)) != 0)
+ return cmp;
+
if (jt1->dependent & jt2->table->map)
return 1;
if (jt2->dependent & jt1->table->map)
@@ -7636,7 +7837,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j,
if (keyuse->null_rejecting)
j->ref.null_rejecting |= 1 << i;
keyuse_uses_no_tables= keyuse_uses_no_tables && !keyuse->used_tables;
- if (!keyuse->used_tables && !thd->lex->describe)
+ if (!keyuse->val->used_tables() && !thd->lex->describe)
{ // Compare against constant
store_key_item tmp(thd,
keyinfo->key_part[i].field,
@@ -10852,6 +11053,9 @@ finish:
acceptable, as this happens rarely. The implementation without
copying would be much more complicated.
+ For description of how equality propagation works with SJM nests, grep
+ for EqualityPropagationAndSjmNests.
+
@param left_item left term of the quality to be checked
@param right_item right term of the equality to be checked
@param item equality item if the equality originates from a condition
@@ -10925,12 +11129,14 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
{
/* left_item_equal of an upper level contains left_item */
left_item_equal= new Item_equal(left_item_equal);
+ left_item_equal->set_context_field(((Item_field*) left_item));
cond_equal->current_level.push_back(left_item_equal);
}
if (right_copyfl)
{
/* right_item_equal of an upper level contains right_item */
right_item_equal= new Item_equal(right_item_equal);
+ right_item_equal->set_context_field(((Item_field*) right_item));
cond_equal->current_level.push_back(right_item_equal);
}
@@ -10960,6 +11166,7 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
Item_equal *item_equal= new Item_equal(orig_left_item,
orig_right_item,
FALSE);
+ item_equal->set_context_field((Item_field*)left_item);
cond_equal->current_level.push_back(item_equal);
}
}
@@ -11016,6 +11223,7 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
{
item_equal= new Item_equal(item_equal);
cond_equal->current_level.push_back(item_equal);
+ item_equal->set_context_field(field_item);
}
if (item_equal)
{
@@ -11029,6 +11237,7 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
else
{
item_equal= new Item_equal(const_item, orig_field_item, TRUE);
+ item_equal->set_context_field(field_item);
cond_equal->current_level.push_back(item_equal);
}
return TRUE;
@@ -11665,6 +11874,8 @@ static TABLE_LIST* embedding_sjm(Item *item)
Item_equal::get_first() also takes similar measures for dealing with
equality substitution in presense of SJM nests.
+ Grep for EqualityPropagationAndSjmNests for a more verbose description.
+
@return
- The condition with generated simple equalities or
a pointer to the simple generated equality, if success.
@@ -11728,9 +11939,13 @@ Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
on upper AND-levels.
*/
if (upper)
- {
+ {
+ TABLE_LIST *native_sjm= embedding_sjm(item_equal->context_field);
if (item_const && upper->get_const())
+ {
+ /* Upper item also has "field_item=const". Don't produce equality here */
item= 0;
+ }
else
{
Item_equal_fields_iterator li(*item_equal);
@@ -11741,6 +11956,8 @@ Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
break;
}
}
+ if (embedding_sjm(field_item) != native_sjm)
+ item= NULL; /* Don't produce equality */
}
bool produce_equality= test(item == field_item);
@@ -12436,11 +12653,9 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top,
Flatten nested joins that can be flattened.
no ON expression and not a semi-join => can be flattened.
*/
- TABLE_LIST *right_neighbor= NULL;
li.rewind();
while ((table= li++))
{
- bool fix_name_res= FALSE;
nested_join= table->nested_join;
if (table->sj_on_expr && !in_sj)
{
@@ -12477,15 +12692,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top,
tbl->dep_tables|= table->dep_tables;
}
li.replace(repl_list);
- /* Need to update the name resolution table chain when flattening joins */
- fix_name_res= TRUE;
- table= *li.ref();
}
- if (fix_name_res)
- table->next_name_resolution_table= right_neighbor ?
- right_neighbor->first_leaf_for_name_resolution() :
- NULL;
- right_neighbor= table;
}
DBUG_RETURN(conds);
}
@@ -15221,6 +15428,7 @@ free_tmp_table(THD *thd, TABLE *entry)
else
entry->file->ha_delete_table(entry->s->table_name.str);
delete entry->file;
+ entry->file= 0;
}
/* free blobs */
@@ -15834,7 +16042,8 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
DBUG_RETURN(NESTED_LOOP_KILLED); /* purecov: inspected */
}
- update_virtual_fields(join->thd, join_tab->table);
+ if (join_tab->table->vfield)
+ update_virtual_fields(join->thd, join_tab->table);
if (select_cond)
{
@@ -16262,7 +16471,8 @@ join_read_system(JOIN_TAB *tab)
empty_record(table); // Make empty record
return -1;
}
- update_virtual_fields(tab->join->thd, table);
+ if (table->vfield)
+ update_virtual_fields(tab->join->thd, table);
store_record(table,record[1]);
}
else if (!table->status) // Only happens with left join
@@ -16311,7 +16521,8 @@ join_read_const(JOIN_TAB *tab)
return report_error(table, error);
return -1;
}
- update_virtual_fields(tab->join->thd, table);
+ if (table->vfield)
+ update_virtual_fields(tab->join->thd, table);
store_record(table,record[1]);
}
else if (!(table->status & ~STATUS_NULL_ROW)) // Only happens with left join
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 2f7d31de404..53f2356853e 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -742,7 +742,7 @@ public:
Information about a position of table within a join order. Used in join
optimization.
*/
-typedef struct st_position
+typedef struct st_position :public Sql_alloc
{
/* The table that's put into join order */
JOIN_TAB *table;
@@ -844,23 +844,36 @@ protected:
*/
class Join_plan_state {
public:
- DYNAMIC_ARRAY keyuse; /* Copy of the JOIN::keyuse array. */
- POSITION best_positions[MAX_TABLES+1]; /* Copy of JOIN::best_positions */
+ DYNAMIC_ARRAY keyuse; /* Copy of the JOIN::keyuse array. */
+ POSITION *best_positions; /* Copy of JOIN::best_positions */
/* Copies of the JOIN_TAB::keyuse pointers for each JOIN_TAB. */
- KEYUSE *join_tab_keyuse[MAX_TABLES];
+ KEYUSE **join_tab_keyuse;
/* Copies of JOIN_TAB::checked_keys for each JOIN_TAB. */
- key_map join_tab_checked_keys[MAX_TABLES];
- SJ_MATERIALIZATION_INFO *sj_mat_info[MAX_TABLES];
+ key_map *join_tab_checked_keys;
+ SJ_MATERIALIZATION_INFO **sj_mat_info;
+ my_bool error;
public:
- Join_plan_state()
+ Join_plan_state(uint tables) : error(0)
{
keyuse.elements= 0;
keyuse.buffer= NULL;
+ best_positions= 0; /* To detect errors */
+ error= my_multi_malloc(MYF(MY_WME),
+ &best_positions,
+ sizeof(*best_positions) * (tables + 1),
+ &join_tab_keyuse,
+ sizeof(*join_tab_keyuse) * tables,
+ &join_tab_checked_keys,
+ sizeof(*join_tab_checked_keys) * tables,
+ &sj_mat_info,
+ sizeof(sj_mat_info) * tables,
+ NullS) == 0;
}
Join_plan_state(JOIN *join);
~Join_plan_state()
{
delete_dynamic(&keyuse);
+ my_free(best_positions);
}
};
@@ -958,7 +971,7 @@ public:
*/
ha_rows fetch_limit;
/* Finally picked QEP. This is result of join optimization */
- POSITION best_positions[MAX_TABLES+1];
+ POSITION *best_positions;
/******* Join optimization state members start *******/
/*
@@ -968,7 +981,7 @@ public:
TABLE_LIST *emb_sjm_nest;
/* Current join optimization state */
- POSITION positions[MAX_TABLES+1];
+ POSITION *positions;
/*
Bitmap of nested joins embedding the position at the end of the current
@@ -1238,6 +1251,7 @@ public:
exec_const_cond= 0;
group_optimized_away= 0;
no_rows_in_result_called= 0;
+ positions= best_positions= 0;
all_fields= fields_arg;
if (&fields_list != &fields_arg) /* Avoid valgrind-warning */
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index d64c7a6df52..b5ed327c193 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2000, 2011, Oracle and/or its affiliates.
- 2009-2011 Monty Program Ab
+/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2011, 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
@@ -1233,7 +1233,9 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
handler *file= table->file;
TABLE_SHARE *share= table->s;
HA_CREATE_INFO create_info;
- bool show_table_options __attribute__ ((unused))= FALSE;
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ bool show_table_options= FALSE;
+#endif /* WITH_PARTITION_STORAGE_ENGINE */
bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL |
MODE_ORACLE |
MODE_MSSQL |
@@ -1467,7 +1469,9 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
packet->append(STRING_WITH_LEN("\n)"));
if (!(thd->variables.sql_mode & MODE_NO_TABLE_OPTIONS) && !foreign_db_mode)
{
+#ifdef WITH_PARTITION_STORAGE_ENGINE
show_table_options= TRUE;
+#endif /* WITH_PARTITION_STORAGE_ENGINE */
/*
IF check_create_info
@@ -3628,16 +3632,17 @@ end:
@retval 1 error
*/
-static int fill_schema_table_names(THD *thd, TABLE *table,
+static int fill_schema_table_names(THD *thd, TABLE_LIST *tables,
LEX_STRING *db_name, LEX_STRING *table_name,
bool with_i_schema)
{
+ TABLE *table= tables->table;
if (with_i_schema)
{
table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"),
system_charset_info);
}
- else
+ else if (tables->table_open_method != SKIP_OPEN_TABLE)
{
enum legacy_db_type not_used;
char path[FN_REFLEN + 1];
@@ -4199,7 +4204,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
/* SHOW TABLE NAMES command */
if (schema_table_idx == SCH_TABLE_NAMES)
{
- if (fill_schema_table_names(thd, tables->table, db_name,
+ if (fill_schema_table_names(thd, tables, db_name,
table_name, with_i_schema))
continue;
}
@@ -5249,7 +5254,8 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
(sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0)
{
restore_record(table, s->default_values);
- if (!wild || !wild[0] || !wild_compare(sp_name.c_ptr_safe(), wild, 0))
+ if (!wild || !wild[0] || !wild_case_compare(system_charset_info,
+ sp_name.c_ptr_safe(), wild))
{
int enum_idx= (int) proc_table->field[MYSQL_PROC_FIELD_ACCESS]->val_int();
table->field[3]->store(sp_name.ptr(), sp_name.length(), cs);
@@ -6409,7 +6415,7 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
DBUG_RETURN(1);
}
- if (!(!wild || !wild[0] || !wild_compare(et.name.str, wild, 0)))
+ if (!(!wild || !wild[0] || !wild_case_compare(scs, et.name.str, wild)))
DBUG_RETURN(0);
/*
@@ -7498,6 +7504,8 @@ bool get_schema_tables_result(JOIN *join,
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;
@@ -8385,7 +8393,7 @@ ST_SCHEMA_TABLE schema_tables[]=
get_all_tables, 0, get_schema_constraints_record, 3, 4, 0,
OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
{"TABLE_NAMES", table_names_fields_info, create_schema_table,
- get_all_tables, make_table_names_old_format, 0, 1, 2, 1, 0},
+ get_all_tables, make_table_names_old_format, 0, 1, 2, 1, OPTIMIZE_I_S_TABLE},
{"TABLE_PRIVILEGES", table_privileges_fields_info, create_schema_table,
fill_schema_table_privileges, 0, 0, -1, -1, 0, 0},
{"TABLE_STATISTICS", table_stats_fields_info, create_schema_table,
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 01832036701..75f430b451e 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -1,6 +1,6 @@
/*
- Copyright (c) 2000, 2011, Oracle and/or its affiliates.
- Copyright (c) 2010, 2011 Monty Program Ab
+ Copyright (c) 2000, 2012, Oracle and/or its affiliates.
+ Copyright (c) 2010, 2011, 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
@@ -3144,6 +3144,15 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
DBUG_RETURN(TRUE);
}
+ /*
+ CREATE TABLE[with auto_increment column] SELECT is unsafe as the rows
+ inserted in the created table depends on the order of the rows fetched
+ from the select tables. This order may differ on master and slave. We
+ therefore mark it as unsafe.
+ */
+ if (select_field_count > 0 && auto_increment)
+ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_CREATE_SELECT_AUTOINC);
+
/* Create keys */
List_iterator<Key> key_iterator(alter_info->key_list);
@@ -7274,7 +7283,8 @@ copy_data_between_tables(THD *thd, TABLE *from,TABLE *to,
error= 1;
break;
}
- update_virtual_fields(thd, from);
+ if (from->vfield)
+ update_virtual_fields(thd, from);
if (++thd->progress.counter >= time_to_report_progress)
{
time_to_report_progress+= MY_HOW_OFTEN_TO_WRITE/10;
@@ -7301,7 +7311,8 @@ copy_data_between_tables(THD *thd, TABLE *from,TABLE *to,
copy_ptr->do_copy(copy_ptr);
}
prev_insert_id= to->file->next_insert_id;
- update_virtual_fields(thd, to, TRUE);
+ if (to->vfield)
+ update_virtual_fields(thd, to, TRUE);
if (thd->is_error())
{
error= 1;
diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc
index 50c57b62067..169e0d9e418 100644
--- a/sql/sql_udf.cc
+++ b/sql/sql_udf.cc
@@ -1,5 +1,4 @@
-/*
- Copyright (c) 2000, 2010, Oracle and/or its affiliates.
+/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
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_update.cc b/sql/sql_update.cc
index 5fa30c91417..f9502589beb 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -559,7 +559,8 @@ int mysql_update(THD *thd,
while (!(error=info.read_record(&info)) && !thd->killed)
{
- update_virtual_fields(thd, table);
+ if (table->vfield)
+ update_virtual_fields(thd, table);
thd->examined_row_count++;
if (!select || (error= select->skip_record(thd)) > 0)
{
@@ -674,7 +675,8 @@ int mysql_update(THD *thd,
while (!(error=info.read_record(&info)) && !thd->killed)
{
- update_virtual_fields(thd, table);
+ if (table->vfield)
+ update_virtual_fields(thd, table);
thd->examined_row_count++;
if (!select || select->skip_record(thd) > 0)
{
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 0db69af094f..b6a7cf010ed 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -445,6 +445,13 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
view= lex->unlink_first_table(&link_to_local);
+ if (check_db_dir_existence(view->db))
+ {
+ my_error(ER_BAD_DB_ERROR, MYF(0), view->db);
+ res= TRUE;
+ goto err;
+ }
+
if (mode == VIEW_ALTER && fill_defined_view_parts(thd, view))
{
res= TRUE;
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 5f9066afd39..34e015e1f9b 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -2772,9 +2772,15 @@ sp_decl:
sp_instr_hpush_jump *i=
new sp_instr_hpush_jump(sp->instructions(), ctx, $2,
ctx->current_var_count());
- if (i == NULL ||
- sp->add_instr(i) ||
- sp->push_backpatch(i, ctx->push_label((char *)"", 0)))
+ if (i == NULL || sp->add_instr(i))
+ MYSQL_YYABORT;
+
+ /* For continue handlers, mark end of handler scope. */
+ if ($2 == SP_HANDLER_CONTINUE &&
+ sp->push_backpatch(i, ctx->last_label()))
+ MYSQL_YYABORT;
+
+ if (sp->push_backpatch(i, ctx->push_label(empty_c_string, 0)))
MYSQL_YYABORT;
}
sp_hcond_list sp_proc_stmt
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 05c2ba9c063..040d7abfcba 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2002, 2012, Oracle and/or its affiliates.
Copyright (c) 2012, Monty Program Ab
This program is free software; you can redistribute it and/or modify
@@ -2954,7 +2954,7 @@ static Sys_var_uint Sys_repl_report_port(
"port or if you have a special tunnel from the master or other clients "
"to the slave. If not sure, leave this option unset",
READ_ONLY GLOBAL_VAR(report_port), CMD_LINE(REQUIRED_ARG),
- VALID_RANGE(0, UINT_MAX), DEFAULT(MYSQL_PORT), BLOCK_SIZE(1));
+ VALID_RANGE(0, UINT_MAX), DEFAULT(0), BLOCK_SIZE(1));
#endif
static Sys_var_mybool Sys_keep_files_on_create(
@@ -3255,6 +3255,150 @@ static Sys_var_mybool Sys_relay_log_recovery(
"processed",
GLOBAL_VAR(relay_log_recovery), CMD_LINE(OPT_ARG), DEFAULT(FALSE));
+bool Sys_var_rpl_filter::do_check(THD *thd, set_var *var)
+{
+ bool status;
+
+ mysql_mutex_lock(&LOCK_active_mi);
+ mysql_mutex_lock(&active_mi->rli.run_lock);
+
+ status= active_mi->rli.slave_running;
+
+ mysql_mutex_unlock(&active_mi->rli.run_lock);
+ mysql_mutex_unlock(&LOCK_active_mi);
+
+ if (status)
+ my_error(ER_SLAVE_MUST_STOP, MYF(0));
+ else
+ status= Sys_var_charptr::do_string_check(thd, var, charset(thd));
+
+ return status;
+}
+
+bool Sys_var_rpl_filter::global_update(THD *thd, set_var *var)
+{
+ bool slave_running, status= false;
+
+ mysql_mutex_lock(&LOCK_active_mi);
+ mysql_mutex_lock(&active_mi->rli.run_lock);
+
+ if (! (slave_running= active_mi->rli.slave_running))
+ status= set_filter_value(var->save_result.string_value.str);
+
+ mysql_mutex_unlock(&active_mi->rli.run_lock);
+ mysql_mutex_unlock(&LOCK_active_mi);
+
+ if (slave_running)
+ my_error(ER_SLAVE_MUST_STOP, MYF(0));
+
+ return slave_running || status;
+}
+
+bool Sys_var_rpl_filter::set_filter_value(const char *value)
+{
+ bool status= true;
+
+ switch (opt_id) {
+ case OPT_REPLICATE_DO_DB:
+ status= rpl_filter->set_do_db(value);
+ break;
+ case OPT_REPLICATE_DO_TABLE:
+ status= rpl_filter->set_do_table(value);
+ break;
+ case OPT_REPLICATE_IGNORE_DB:
+ status= rpl_filter->set_ignore_db(value);
+ break;
+ case OPT_REPLICATE_IGNORE_TABLE:
+ status= rpl_filter->set_ignore_table(value);
+ break;
+ case OPT_REPLICATE_WILD_DO_TABLE:
+ status= rpl_filter->set_wild_do_table(value);
+ break;
+ case OPT_REPLICATE_WILD_IGNORE_TABLE:
+ status= rpl_filter->set_wild_ignore_table(value);
+ break;
+ }
+
+ return status;
+}
+
+uchar *Sys_var_rpl_filter::global_value_ptr(THD *thd, LEX_STRING *base)
+{
+ char buf[256];
+ String tmp(buf, sizeof(buf), &my_charset_bin);
+
+ tmp.length(0);
+
+ mysql_mutex_lock(&LOCK_active_mi);
+ mysql_mutex_lock(&active_mi->rli.run_lock);
+
+ switch (opt_id) {
+ case OPT_REPLICATE_DO_DB:
+ rpl_filter->get_do_db(&tmp);
+ break;
+ case OPT_REPLICATE_DO_TABLE:
+ rpl_filter->get_do_table(&tmp);
+ break;
+ case OPT_REPLICATE_IGNORE_DB:
+ rpl_filter->get_ignore_db(&tmp);
+ break;
+ case OPT_REPLICATE_IGNORE_TABLE:
+ rpl_filter->get_ignore_table(&tmp);
+ break;
+ case OPT_REPLICATE_WILD_DO_TABLE:
+ rpl_filter->get_wild_do_table(&tmp);
+ break;
+ case OPT_REPLICATE_WILD_IGNORE_TABLE:
+ rpl_filter->get_wild_ignore_table(&tmp);
+ break;
+ }
+
+ mysql_mutex_unlock(&active_mi->rli.run_lock);
+ mysql_mutex_unlock(&LOCK_active_mi);
+
+ return (uchar *) thd->strmake(tmp.ptr(), tmp.length());
+}
+
+static Sys_var_rpl_filter Sys_replicate_do_db(
+ "replicate_do_db", OPT_REPLICATE_DO_DB,
+ "Tell the slave to restrict replication to updates of tables "
+ "whose names appear in the comma-separated list. For "
+ "statement-based replication, only the default database (that "
+ "is, the one selected by USE) is considered, not any explicitly "
+ "mentioned tables in the query. For row-based replication, the "
+ "actual names of table(s) being updated are checked.");
+
+static Sys_var_rpl_filter Sys_replicate_do_table(
+ "replicate_do_table", OPT_REPLICATE_DO_TABLE,
+ "Tells the slave to restrict replication to tables in the "
+ "comma-separated list.");
+
+static Sys_var_rpl_filter Sys_replicate_ignore_db(
+ "replicate_ignore_db", OPT_REPLICATE_IGNORE_DB,
+ "Tell the slave to restrict replication to updates of tables "
+ "whose names do not appear in the comma-separated list. For "
+ "statement-based replication, only the default database (that "
+ "is, the one selected by USE) is considered, not any explicitly "
+ "mentioned tables in the query. For row-based replication, the "
+ "actual names of table(s) being updated are checked.");
+
+static Sys_var_rpl_filter Sys_replicate_ignore_table(
+ "replicate_ignore_table", OPT_REPLICATE_IGNORE_TABLE,
+ "Tells the slave thread not to replicate any statement that "
+ "updates the specified table, even if any other tables might be "
+ "updated by the same statement.");
+
+static Sys_var_rpl_filter Sys_replicate_wild_do_table(
+ "replicate_wild_do_table", OPT_REPLICATE_WILD_DO_TABLE,
+ "Tells the slave thread to restrict replication to statements "
+ "where any of the updated tables match the specified database "
+ "and table name patterns.");
+
+static Sys_var_rpl_filter Sys_replicate_wild_ignore_table(
+ "replicate_wild_ignore_table", OPT_REPLICATE_WILD_IGNORE_TABLE,
+ "Tells the slave thread to not replicate to the tables that "
+ "match the given wildcard pattern.");
+
static Sys_var_charptr Sys_slave_load_tmpdir(
"slave_load_tmpdir", "The location where the slave should put "
"its temporary files when replicating a LOAD DATA INFILE command",
diff --git a/sql/sys_vars.h b/sql/sys_vars.h
index f2a2966e6a2..4ea6b1f036e 100644
--- a/sql/sys_vars.h
+++ b/sql/sys_vars.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
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
@@ -430,11 +430,11 @@ public:
my_free(global_var(char*));
flags&= ~ALLOCATED;
}
- bool do_check(THD *thd, set_var *var)
+ static bool do_string_check(THD *thd, set_var *var, CHARSET_INFO *charset)
{
char buff[STRING_BUFFER_USUAL_SIZE], buff2[STRING_BUFFER_USUAL_SIZE];
- String str(buff, sizeof(buff), charset(thd));
- String str2(buff2, sizeof(buff2), charset(thd)), *res;
+ String str(buff, sizeof(buff), charset);
+ String str2(buff2, sizeof(buff2), charset), *res;
if (!(res=var->value->val_str(&str)))
var->save_result.string_value.str= 0;
@@ -442,10 +442,10 @@ public:
{
uint32 unused;
if (String::needs_conversion(res->length(), res->charset(),
- charset(thd), &unused))
+ charset, &unused))
{
uint errors;
- str2.copy(res->ptr(), res->length(), res->charset(), charset(thd),
+ str2.copy(res->ptr(), res->length(), res->charset(), charset,
&errors);
res=&str2;
@@ -456,6 +456,8 @@ public:
return false;
}
+ bool do_check(THD *thd, set_var *var)
+ { return do_string_check(thd, var, charset(thd)); }
bool session_update(THD *thd, set_var *var)
{
DBUG_ASSERT(FALSE);
@@ -550,6 +552,44 @@ protected:
}
};
+class Sys_var_rpl_filter: public sys_var
+{
+private:
+ int opt_id;
+
+public:
+ Sys_var_rpl_filter(const char *name, int getopt_id, const char *comment)
+ : sys_var(&all_sys_vars, name, comment, sys_var::GLOBAL, 0, -1,
+ NO_ARG, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG,
+ NULL, NULL, 0, NULL), opt_id(getopt_id)
+ {
+ option.var_type= GET_STR;
+ }
+
+ bool check_update_type(Item_result type)
+ { return type != STRING_RESULT; }
+
+ bool do_check(THD *thd, set_var *var);
+
+ void session_save_default(THD *thd, set_var *var)
+ { DBUG_ASSERT(FALSE); }
+
+ void global_save_default(THD *thd, set_var *var)
+ { DBUG_ASSERT(FALSE); }
+
+ bool session_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(FALSE);
+ return true;
+ }
+
+ bool global_update(THD *thd, set_var *var);
+
+protected:
+ uchar *global_value_ptr(THD *thd, LEX_STRING *base);
+ bool set_filter_value(const char *value);
+};
+
/**
The class for string variables. Useful for strings that aren't necessarily
\0-terminated. Otherwise the same as Sys_var_charptr.
diff --git a/sql/table.cc b/sql/table.cc
index 6c20f95c28b..78449d0498d 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -2490,30 +2490,35 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
/*
Process virtual columns, if any.
*/
- if (!(vfield_ptr = (Field **) alloc_root(&outparam->mem_root,
- (uint) ((share->vfields+1)*
- sizeof(Field*)))))
- goto err;
-
- outparam->vfield= vfield_ptr;
-
- for (field_ptr= outparam->field; *field_ptr; field_ptr++)
+ if (!share->vfields)
+ outparam->vfield= NULL;
+ else
{
- if ((*field_ptr)->vcol_info)
+ if (!(vfield_ptr = (Field **) alloc_root(&outparam->mem_root,
+ (uint) ((share->vfields+1)*
+ sizeof(Field*)))))
+ goto err;
+
+ outparam->vfield= vfield_ptr;
+
+ for (field_ptr= outparam->field; *field_ptr; field_ptr++)
{
- if (unpack_vcol_info_from_frm(thd,
- outparam,
- *field_ptr,
- &(*field_ptr)->vcol_info->expr_str,
- &error_reported))
+ if ((*field_ptr)->vcol_info)
{
- error= 4; // in case no error is reported
- goto err;
+ if (unpack_vcol_info_from_frm(thd,
+ outparam,
+ *field_ptr,
+ &(*field_ptr)->vcol_info->expr_str,
+ &error_reported))
+ {
+ error= 4; // in case no error is reported
+ goto err;
+ }
+ *(vfield_ptr++)= *field_ptr;
}
- *(vfield_ptr++)= *field_ptr;
}
+ *vfield_ptr= 0; // End marker
}
- *vfield_ptr= 0; // End marker
#ifdef WITH_PARTITION_STORAGE_ENGINE
if (share->partition_info_str_len && outparam->file)
@@ -2626,8 +2631,7 @@ partititon_err:
HA_OPEN_IGNORE_IF_LOCKED) | ha_open_flags))))
{
/* Set a flag if the table is crashed and it can be auto. repaired */
- share->crashed= ((ha_err == HA_ERR_CRASHED_ON_USAGE) &&
- outparam->file->auto_repair() &&
+ share->crashed= (outparam->file->auto_repair(ha_err) &&
!(ha_open_flags & HA_OPEN_FOR_REPAIR));
switch (ha_err)
@@ -4063,7 +4067,21 @@ bool TABLE_LIST::create_field_translation(THD *thd)
Query_arena *arena= thd->stmt_arena, backup;
bool res= FALSE;
- used_items.empty();
+ if (thd->stmt_arena->is_conventional() ||
+ thd->stmt_arena->is_stmt_prepare_or_first_sp_execute())
+ {
+ /* initialize lists */
+ used_items.empty();
+ persistent_used_items.empty();
+ }
+ else
+ {
+ /*
+ Copy the list created by natural join procedure because the procedure
+ will not be repeated.
+ */
+ used_items= persistent_used_items;
+ }
if (field_translation)
{
@@ -5127,7 +5145,7 @@ Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref,
if (view->table && view->table->maybe_null)
item->maybe_null= TRUE;
/* Save item in case we will need to fall back to materialization. */
- view->used_items.push_back(item);
+ view->used_items.push_front(item);
DBUG_RETURN(item);
}
@@ -6387,8 +6405,7 @@ int update_virtual_fields(THD *thd, TABLE *table, bool for_write)
DBUG_ENTER("update_virtual_fields");
Field **vfield_ptr, *vfield;
int error __attribute__ ((unused))= 0;
- if (!table || !table->vfield)
- DBUG_RETURN(0);
+ DBUG_ASSERT(table && table->vfield);
thd->reset_arena_for_cached_items(table->expr_arena);
/* Iterate over virtual fields in the table */
@@ -6701,7 +6718,11 @@ bool TABLE_LIST::change_refs_to_fields()
if (!materialized_items[idx])
return TRUE;
}
- ref->ref= materialized_items + idx;
+ /*
+ We need to restore the pointers after the execution of the
+ prepared statement.
+ */
+ thd->change_item_tree((Item **)&ref->ref, (Item*)materialized_items + idx);
}
return FALSE;
diff --git a/sql/table.h b/sql/table.h
index 0deb793aa57..bad0894a786 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -303,6 +303,7 @@ typedef struct st_filesort_info
{
IO_CACHE *io_cache; /* If sorted through filesort */
uchar **sort_keys; /* Buffer for sorting keys */
+ uint keys; /* Number of key pointers in buffer */
uchar *buffpek; /* Buffer for buffpek structures */
uint buffpek_len; /* Max number of buffpeks in the buffer */
uchar *addon_buf; /* Pointer to a buffer if sorted with fields */
@@ -1596,6 +1597,8 @@ struct TABLE_LIST
/* If this is a non-jtbm semi-join nest: corresponding subselect predicate */
Item_in_subselect *sj_subq_pred;
+ table_map original_subq_pred_used_tables;
+
/* If this is a jtbm semi-join object: corresponding subselect predicate */
Item_in_subselect *jtbm_subselect;
/* TODO: check if this can be joined with tablenr_exec */
@@ -1875,7 +1878,13 @@ struct TABLE_LIST
/* TRUE <=> don't prepare this derived table/view as it should be merged.*/
bool skip_prepare_derived;
+ /*
+ Items created by create_view_field and collected to change them in case
+ of materialization of the view/derived table
+ */
List<Item> used_items;
+ /* Sublist (tail) of persistent used_items */
+ List<Item> persistent_used_items;
Item **materialized_items;
/* View creation context. */
diff --git a/sql/threadpool_unix.cc b/sql/threadpool_unix.cc
index 407905fd5f6..f5ea771883d 100644
--- a/sql/threadpool_unix.cc
+++ b/sql/threadpool_unix.cc
@@ -295,7 +295,7 @@ int io_poll_create()
int io_poll_start_read(int pollfd, int fd, void *data)
{
struct kevent ke;
- EV_SET(&ke, fd, EVFILT_READ, EV_ADD|EV_ENABLE|EV_CLEAR,
+ EV_SET(&ke, fd, EVFILT_READ, EV_ADD|EV_ONESHOT,
0, 0, data);
return kevent(pollfd, &ke, 1, 0, 0, 0);
}
@@ -303,6 +303,9 @@ int io_poll_start_read(int pollfd, int fd, void *data)
int io_poll_associate_fd(int pollfd, int fd, void *data)
{
+ struct kevent ke;
+ EV_SET(&ke, fd, EVFILT_READ, EV_ADD|EV_ONESHOT,
+ 0, 0, data);
return io_poll_start_read(pollfd,fd, data);
}
@@ -330,17 +333,6 @@ int io_poll_wait(int pollfd, struct kevent *events, int maxevents, int timeout_m
(timeout_ms >= 0)?&ts:NULL);
}
while (ret == -1 && errno == EINTR);
- if (ret > 0)
- {
- /* Disable monitoring for the events we that we dequeued */
- for (int i=0; i < ret; i++)
- {
- struct kevent *ke = &events[i];
- EV_SET(ke, ke->ident, EVFILT_READ, EV_ADD|EV_DISABLE,
- 0, 0, ke->udata);
- }
- kevent(pollfd, events, ret, 0, 0, 0);
- }
return ret;
}
diff --git a/sql/threadpool_win.cc b/sql/threadpool_win.cc
index bf1d4740a13..c8cc38e612a 100644
--- a/sql/threadpool_win.cc
+++ b/sql/threadpool_win.cc
@@ -144,6 +144,9 @@ WEAK_SYMBOL(VOID, SubmitThreadpoolWork,PTP_WORK pwk);
WEAK_SYMBOL(VOID, CloseThreadpoolWork, PTP_WORK pwk);
#define CloseThreadpoolWork my_CloseThreadpoolWork
+WEAK_SYMBOL(BOOL, CallbackMayRunLong, PTP_CALLBACK_INSTANCE pci);
+#define CallbackMayRunLong my_CallbackMayRunLong
+
#if _MSC_VER >= 1600
/* Stack size manipulation available only on Win7+ /declarations in VS10 */
WEAK_SYMBOL(BOOL, SetThreadpoolStackInformation, PTP_POOL,
@@ -419,8 +422,10 @@ void set_wait_timeout(connection_t *connection, ulonglong old_timeout)
/* Connection destructor */
-void destroy_connection(connection_t *connection)
+void destroy_connection(connection_t *connection, PTP_CALLBACK_INSTANCE instance)
{
+ if (instance)
+ DisassociateCurrentThreadFromCallback(instance);
if (connection->io)
{
WaitForThreadpoolIoCallbacks(connection->io, TRUE);
@@ -583,10 +588,8 @@ static VOID CALLBACK io_completion_callback(PTP_CALLBACK_INSTANCE instance,
error:
/* Some error has occured. */
- if (instance)
- DisassociateCurrentThreadFromCallback(instance);
- destroy_connection(connection);
+ destroy_connection(connection, instance);
free(connection);
}
@@ -603,7 +606,7 @@ static void CALLBACK login_callback(PTP_CALLBACK_INSTANCE instance,
connection_t *connection =(connection_t *)context;
if (login(connection, instance) != 0)
{
- destroy_connection(connection);
+ destroy_connection(connection, instance);
free(connection);
}
}
diff --git a/sql/transaction.cc b/sql/transaction.cc
index 94a32200274..3359decbcd5 100644
--- a/sql/transaction.cc
+++ b/sql/transaction.cc
@@ -390,7 +390,7 @@ bool trans_savepoint(THD *thd, LEX_STRING name)
DBUG_RETURN(FALSE);
enum xa_states xa_state= thd->transaction.xid_state.xa_state;
- if (xa_state != XA_NOTR)
+ if (xa_state != XA_NOTR && xa_state != XA_ACTIVE)
{
my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
DBUG_RETURN(TRUE);
diff --git a/sql/unireg.h b/sql/unireg.h
index 50aaa103b34..f8317a89c8c 100644
--- a/sql/unireg.h
+++ b/sql/unireg.h
@@ -2,7 +2,7 @@
#define UNIREG_INCLUDED
/*
- Copyright (c) 2000, 2010, Oracle and/or its affiliates.
+ Copyright (c) 2000, 2011, Oracle and/or its affiliates.
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