summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2013-09-06 22:31:30 +0200
committerSergei Golubchik <sergii@pisem.net>2013-09-06 22:31:30 +0200
commitb838d081ad346e52787753b1799c627922c4a6c7 (patch)
treedc8f1e21e6b40d5b72668571c570c9a3214fbf32 /sql
parent824db55ce53963a64fcf648b54500df22c57e9b2 (diff)
parent72c36f4415815d55ddb82b23682f3c549906c00e (diff)
downloadmariadb-git-b838d081ad346e52787753b1799c627922c4a6c7.tar.gz
mysql-5.5.33 merge
Diffstat (limited to 'sql')
-rw-r--r--sql/debug_sync.cc4
-rw-r--r--sql/field.cc8
-rw-r--r--sql/ha_partition.cc124
-rw-r--r--sql/ha_partition.h2
-rw-r--r--sql/item_func.h17
-rw-r--r--sql/item_subselect.cc11
-rw-r--r--sql/log_event.h1
-rw-r--r--sql/partition_info.cc2
-rw-r--r--sql/signal_handler.cc2
-rw-r--r--sql/sql_bitmap.h1
-rw-r--r--sql/sql_load.cc3
-rw-r--r--sql/sql_partition.cc349
-rw-r--r--sql/sql_plugin.cc61
-rw-r--r--sql/sql_rename.cc5
-rw-r--r--sql/sql_select.cc77
-rw-r--r--sql/sql_table.cc22
-rw-r--r--sql/sql_table.h4
-rw-r--r--sql/sql_yacc.yy4
-rw-r--r--sql/sys_vars.h13
-rw-r--r--sql/table.h4
20 files changed, 462 insertions, 252 deletions
diff --git a/sql/debug_sync.cc b/sql/debug_sync.cc
index 4097d7fe6e1..4cff1c09ba7 100644
--- a/sql/debug_sync.cc
+++ b/sql/debug_sync.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2010, Oracle and/or its affiliates.
+/* Copyright (c) 2009, 2013, 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
@@ -1397,7 +1397,7 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
if (action->wait_for.length())
{
mysql_mutex_t *old_mutex;
- mysql_cond_t *UNINIT_VAR(old_cond);
+ mysql_cond_t *old_cond= NULL;
int error= 0;
struct timespec abstime;
diff --git a/sql/field.cc b/sql/field.cc
index 0aeb311d65a..8c530c24279 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1,6 +1,6 @@
/*
- Copyright (c) 2000, 2012, Oracle and/or its affiliates.
- Copyright (c) 2008, 2011, Monty Program Ab
+ Copyright (c) 2000, 2013, Oracle and/or its affiliates.
+ Copyright (c) 2008, 2013, 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
@@ -7077,7 +7077,7 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
if (!String::needs_conversion(length, cs, field_charset, &dummy_offset))
{
Field_blob::store_length(length);
- bmove(ptr+packlength,(char*) &from,sizeof(char*));
+ bmove(ptr+packlength, &from, sizeof(char*));
return 0;
}
if (tmpstr.copy(from, length, cs))
@@ -7595,7 +7595,7 @@ int Field_geom::store(const char *from, uint length, CHARSET_INFO *cs)
value.copy(from, length, cs);
from= value.ptr();
}
- bmove(ptr + packlength, (char*) &from, sizeof(char*));
+ bmove(ptr + packlength, &from, sizeof(char*));
}
return 0;
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index 838c1c374d8..1148a561743 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -69,7 +69,7 @@
#include "debug_sync.h"
static const char *ha_par_ext= ".par";
-
+#define MI_MAX_MSG_BUF MYSQL_ERRMSG_SIZE
/****************************************************************************
MODULE create/delete handler object
****************************************************************************/
@@ -1095,34 +1095,42 @@ int ha_partition::handle_opt_part(THD *thd, HA_CHECK_OPT *check_opt,
/*
- print a message row formatted for ANALYZE/CHECK/OPTIMIZE/REPAIR TABLE
+ print a message row formatted for ANALYZE/CHECK/OPTIMIZE/REPAIR TABLE
(modelled after mi_check_print_msg)
TODO: move this into the handler, or rewrite mysql_admin_table.
*/
-static bool print_admin_msg(THD* thd, const char* msg_type,
+static bool print_admin_msg(THD* thd, uint len,
+ const char* msg_type,
const char* db_name, String &table_name,
const char* op_name, const char *fmt, ...)
- ATTRIBUTE_FORMAT(printf, 6, 7);
-static bool print_admin_msg(THD* thd, const char* msg_type,
+ ATTRIBUTE_FORMAT(printf, 7, 8);
+static bool print_admin_msg(THD* thd, uint len,
+ const char* msg_type,
const char* db_name, String &table_name,
const char* op_name, const char *fmt, ...)
{
va_list args;
Protocol *protocol= thd->protocol;
- uint length, msg_length;
- char msgbuf[MYSQL_ERRMSG_SIZE];
+ uint length;
+ uint msg_length;
char name[SAFE_NAME_LEN*2+2];
+ char *msgbuf;
+ bool error= true;
+ if (!(msgbuf= (char*) my_malloc(len, MYF(0))))
+ return true;
va_start(args, fmt);
- msg_length= my_vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
+ msg_length= my_vsnprintf(msgbuf, len, fmt, args);
va_end(args);
- msgbuf[sizeof(msgbuf) - 1] = 0; // healthy paranoia
+ if (msg_length >= (len - 1))
+ goto err;
+ msgbuf[len - 1] = 0; // healthy paranoia
if (!thd->vio_ok())
{
- sql_print_error(fmt, args);
- return TRUE;
+ sql_print_error("%s", msgbuf);
+ goto err;
}
length=(uint) (strxmov(name, db_name, ".", table_name.c_ptr_safe(), NullS) - name);
@@ -1145,9 +1153,12 @@ static bool print_admin_msg(THD* thd, const char* msg_type,
{
sql_print_error("Failed on my_net_write, writing to stderr instead: %s\n",
msgbuf);
- return TRUE;
+ goto err;
}
- return FALSE;
+ error= false;
+err:
+ my_free(msgbuf);
+ return error;
}
@@ -1204,7 +1215,8 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt,
error != HA_ADMIN_ALREADY_DONE &&
error != HA_ADMIN_TRY_ALTER)
{
- print_admin_msg(thd, "error", table_share->db.str, table->alias,
+ print_admin_msg(thd, MI_MAX_MSG_BUF, "error",
+ table_share->db.str, table->alias,
opt_op_name[flag],
"Subpartition %s returned error",
sub_elem->partition_name);
@@ -1230,8 +1242,9 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt,
error != HA_ADMIN_ALREADY_DONE &&
error != HA_ADMIN_TRY_ALTER)
{
- print_admin_msg(thd, "error", table_share->db.str, table->alias,
- opt_op_name[flag], "Partition %s returned error",
+ print_admin_msg(thd, MI_MAX_MSG_BUF, "error",
+ table_share->db.str, table->alias,
+ opt_op_name[flag], "Partition %s returned error",
part_elem->partition_name);
}
/* reset part_state for the remaining partitions */
@@ -1940,15 +1953,15 @@ char *ha_partition::update_table_comment(const char *comment)
names of the partitions and the underlying storage engines.
*/
-uint ha_partition::del_ren_cre_table(const char *from,
+int ha_partition::del_ren_cre_table(const char *from,
const char *to,
TABLE *table_arg,
HA_CREATE_INFO *create_info)
{
int save_error= 0;
- int error;
+ int error= HA_ERR_INTERNAL_ERROR;
char from_buff[FN_REFLEN], to_buff[FN_REFLEN], from_lc_buff[FN_REFLEN],
- to_lc_buff[FN_REFLEN];
+ to_lc_buff[FN_REFLEN], buff[FN_REFLEN];
char *name_buffer_ptr;
const char *from_path;
const char *to_path= NULL;
@@ -1960,24 +1973,28 @@ uint ha_partition::del_ren_cre_table(const char *from,
if (create_info && create_info->options & HA_LEX_CREATE_TMP_TABLE)
{
my_error(ER_PARTITION_NO_TEMPORARY, MYF(0));
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(error);
+ }
+
+ fn_format(buff,from, "", ha_par_ext, MY_APPEND_EXT);
+ /* Check if the par file exists */
+ if (my_access(buff,F_OK))
+ {
+ /*
+ If the .par file does not exist, return HA_ERR_NO_SUCH_TABLE,
+ This will signal to the caller that it can remove the .frm
+ file.
+ */
+ error= HA_ERR_NO_SUCH_TABLE;
+ DBUG_RETURN(error);
}
if (get_from_handler_file(from, ha_thd()->mem_root, false))
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(error);
DBUG_ASSERT(m_file_buffer);
DBUG_PRINT("enter", ("from: (%s) to: (%s)", from, to ? to : "(nil)"));
name_buffer_ptr= m_name_buffer_ptr;
file= m_file;
- if (to == NULL && table_arg == NULL)
- {
- /*
- Delete table, start by delete the .par file. If error, break, otherwise
- delete as much as possible.
- */
- if ((error= handler::delete_table(from)))
- DBUG_RETURN(error);
- }
/*
Since ha_partition has HA_FILE_BASED, it must alter underlying table names
if they do not have HA_FILE_BASED and lower_case_table_names == 2.
@@ -2018,6 +2035,18 @@ uint ha_partition::del_ren_cre_table(const char *from,
save_error= error;
i++;
} while (*(++file));
+
+ if (to == NULL && table_arg == NULL)
+ {
+ DBUG_EXECUTE_IF("crash_before_deleting_par_file", DBUG_SUICIDE(););
+
+ /* Delete the .par file. If error, break.*/
+ if ((error= handler::delete_table(from)))
+ DBUG_RETURN(error);
+
+ DBUG_EXECUTE_IF("crash_after_deleting_par_file", DBUG_SUICIDE(););
+ }
+
if (to != NULL)
{
if ((error= handler::rename_table(from, to)))
@@ -7936,7 +7965,8 @@ int ha_partition::check_misplaced_rows(uint read_part_id, bool repair)
if (num_misplaced_rows > 0)
{
- print_admin_msg(ha_thd(), "warning", table_share->db.str, table->alias,
+ print_admin_msg(ha_thd(), MI_MAX_MSG_BUF, "warning",
+ table_share->db.str, table->alias,
opt_op_name[REPAIR_PARTS],
"Moved %lld misplaced rows",
num_misplaced_rows);
@@ -7957,7 +7987,8 @@ int ha_partition::check_misplaced_rows(uint read_part_id, bool repair)
if (!repair)
{
/* Check. */
- print_admin_msg(ha_thd(), "error", table_share->db.str, table->alias,
+ print_admin_msg(ha_thd(), MI_MAX_MSG_BUF, "error",
+ table_share->db.str, table->alias,
opt_op_name[CHECK_PARTS],
"Found a misplaced row");
/* Break on first misplaced row! */
@@ -8004,7 +8035,8 @@ int ha_partition::check_misplaced_rows(uint read_part_id, bool repair)
correct_part_id,
str.c_ptr_safe());
}
- print_admin_msg(ha_thd(), "error", table_share->db.str, table->alias,
+ print_admin_msg(ha_thd(), MI_MAX_MSG_BUF, "error",
+ table_share->db.str, table->alias,
opt_op_name[REPAIR_PARTS],
"Failed to move/insert a row"
" from part %d into part %d:\n%s",
@@ -8135,12 +8167,18 @@ int ha_partition::check_for_upgrade(HA_CHECK_OPT *check_opt)
NULL,
NULL,
NULL)) ||
- /* Also check that the length is smaller than the output field! */
- (part_buf_len + db_name.length() + table_name.length()) >=
- (SQL_ADMIN_MSG_TEXT_SIZE -
- (strlen(KEY_PARTITIONING_CHANGED_STR) - 3)))
- {
- print_admin_msg(thd, "error", table_share->db.str, table->alias,
+ print_admin_msg(thd, SQL_ADMIN_MSG_TEXT_SIZE + 1, "error",
+ table_share->db.str,
+ table->alias,
+ opt_op_name[CHECK_PARTS],
+ KEY_PARTITIONING_CHANGED_STR,
+ db_name.c_ptr_safe(),
+ table_name.c_ptr_safe(),
+ part_buf))
+ {
+ /* Error creating admin message (too long string?). */
+ print_admin_msg(thd, MI_MAX_MSG_BUF, "error",
+ table_share->db.str, table->alias,
opt_op_name[CHECK_PARTS],
KEY_PARTITIONING_CHANGED_STR,
db_name.c_ptr_safe(), table_name.c_ptr_safe(),
@@ -8148,14 +8186,6 @@ int ha_partition::check_for_upgrade(HA_CHECK_OPT *check_opt)
" between 'KEY' and '(' to change the metadata"
" without the need of a full table rebuild.");
}
- else
- {
- print_admin_msg(thd, "error", table_share->db.str, table->alias,
- opt_op_name[CHECK_PARTS],
- KEY_PARTITIONING_CHANGED_STR,
- db_name.c_ptr_safe(), table_name.c_ptr_safe(),
- part_buf);
- }
m_part_info->key_algorithm= old_algorithm;
DBUG_RETURN(error);
}
diff --git a/sql/ha_partition.h b/sql/ha_partition.h
index ebf9dcdb842..7941c1ce581 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -274,7 +274,7 @@ private:
delete_table, rename_table and create uses very similar logic which
is packed into this routine.
*/
- uint del_ren_cre_table(const char *from, const char *to,
+ int del_ren_cre_table(const char *from, const char *to,
TABLE *table_arg, HA_CREATE_INFO *create_info);
/*
One method to create the table_name.par file containing the names of the
diff --git a/sql/item_func.h b/sql/item_func.h
index 499d1796d5d..d177562c2a5 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -1599,15 +1599,14 @@ public:
:Item_func(b), cached_result_type(INT_RESULT),
entry(NULL), entry_thread_id(0), name(a)
{}
- Item_func_set_user_var(Item_func_set_user_var *item)
- :Item_func(item), cached_result_type(item->cached_result_type),
- entry(item->entry), entry_thread_id(item->entry_thread_id),
- value(item->value), decimal_buff(item->decimal_buff),
- null_item(item->null_item), save_result(item->save_result),
- name(item->name)
- {
- //fixed= 1;
- }
+ Item_func_set_user_var(THD *thd, Item_func_set_user_var *item)
+ :Item_func(thd, item), cached_result_type(item->cached_result_type),
+ entry(item->entry), entry_thread_id(item->entry_thread_id),
+ value(item->value), decimal_buff(item->decimal_buff),
+ null_item(item->null_item), save_result(item->save_result),
+ name(item->name)
+ {}
+
enum Functype functype() const { return SUSERVAR_FUNC; }
double val_real();
longlong val_int();
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 43855286d4f..090cd827311 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -1737,7 +1737,16 @@ Item_in_subselect::single_value_transformer(JOIN *join)
*/
where_item->walk(&Item::remove_dependence_processor, 0,
(uchar *) select_lex->outer_select());
- substitution= func->create(left_expr, where_item);
+ /*
+ fix_field of substitution item will be done in time of
+ substituting.
+ Note that real_item() should be used instead of
+ original left expression because left_expr can be
+ runtime created Ref item which is deleted at the end
+ of the statement. Thus one of 'substitution' arguments
+ can be broken in case of PS.
+ */
+ substitution= func->create(left_expr->real_item(), where_item);
have_to_be_excluded= 1;
if (thd->lex->describe)
{
diff --git a/sql/log_event.h b/sql/log_event.h
index 11fff7a8af6..8429f7f0b01 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -40,7 +40,6 @@
#include "rpl_utility.h"
#include "hash.h"
#include "rpl_tblmap.h"
-#include "rpl_tblmap.cc"
#endif
#ifdef MYSQL_SERVER
diff --git a/sql/partition_info.cc b/sql/partition_info.cc
index d877491e770..a6c4fdaa6d2 100644
--- a/sql/partition_info.cc
+++ b/sql/partition_info.cc
@@ -2459,7 +2459,7 @@ bool partition_info::has_same_partitioning(partition_info *new_part_info)
partition_element *new_sub_part_elem= new_sub_part_it++;
/* new_part_elem may not have engine_type set! */
if (new_sub_part_elem->engine_type &&
- sub_part_elem->engine_type != new_part_elem->engine_type)
+ sub_part_elem->engine_type != new_sub_part_elem->engine_type)
DBUG_RETURN(false);
if (strcmp(sub_part_elem->partition_name,
diff --git a/sql/signal_handler.cc b/sql/signal_handler.cc
index edc33c4d63b..33b0fd13267 100644
--- a/sql/signal_handler.cc
+++ b/sql/signal_handler.cc
@@ -12,7 +12,7 @@
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., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA */
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#include "my_global.h"
#include <signal.h>
diff --git a/sql/sql_bitmap.h b/sql/sql_bitmap.h
index db4c7110ac7..6a26ad5bb2b 100644
--- a/sql/sql_bitmap.h
+++ b/sql/sql_bitmap.h
@@ -71,6 +71,7 @@ public:
bool is_subset(const Bitmap& map2) const { return bitmap_is_subset(&map, &map2.map); }
bool is_overlapping(const Bitmap& map2) const { return bitmap_is_overlapping(&map, &map2.map); }
bool operator==(const Bitmap& map2) const { return bitmap_cmp(&map, &map2.map); }
+ bool operator!=(const Bitmap& map2) const { return !(*this == map2); }
char *print(char *buf) const
{
char *s=buf;
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index b060d116214..493a38ce0f5 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -1,5 +1,6 @@
/*
- Copyright (c) 2000, 2011, Oracle and/or its affiliates.
+ Copyright (c) 2000, 2013, Oracle and/or its affiliates.
+ Copyright (c) 2010, 2013, Monty Progrm 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_partition.cc b/sql/sql_partition.cc
index a3054ecfb15..eb48e2be48b 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -173,7 +173,8 @@ int get_part_iter_for_interval_via_walking(partition_info *part_info,
static int cmp_rec_and_tuple(part_column_list_val *val, uint32 nvals_in_rec);
static int cmp_rec_and_tuple_prune(part_column_list_val *val,
uint32 n_vals_in_rec,
- bool tail_is_min);
+ bool is_left_endpoint,
+ bool include_endpoint);
/*
Convert constants in VALUES definition to the character set the
@@ -3222,44 +3223,6 @@ notfound:
}
-/*
- Find the sub-array part_info->list_array that corresponds to given interval
-
- SYNOPSIS
- get_list_array_idx_for_endpoint()
- part_info Partitioning info (partitioning type must be LIST)
- left_endpoint TRUE - the interval is [a; +inf) or (a; +inf)
- FALSE - the interval is (-inf; a] or (-inf; a)
- include_endpoint TRUE iff the interval includes the endpoint
-
- DESCRIPTION
- This function finds the sub-array of part_info->list_array where values of
- list_array[idx].list_value are contained within the specifed interval.
- list_array is ordered by list_value, so
- 1. For [a; +inf) or (a; +inf)-type intervals (left_endpoint==TRUE), the
- sought sub-array starts at some index idx and continues till array end.
- The function returns first number idx, such that
- list_array[idx].list_value is contained within the passed interval.
-
- 2. For (-inf; a] or (-inf; a)-type intervals (left_endpoint==FALSE), the
- sought sub-array starts at array start and continues till some last
- index idx.
- The function returns first number idx, such that
- list_array[idx].list_value is NOT contained within the passed interval.
- If all array elements are contained, part_info->num_list_values is
- returned.
-
- NOTE
- The caller will call this function and then will run along the sub-array of
- list_array to collect partition ids. If the number of list values is
- significantly higher then number of partitions, this could be slow and
- we could invent some other approach. The "run over list array" part is
- already wrapped in a get_next()-like function.
-
- RETURN
- The edge of corresponding sub-array of part_info->list_array
-*/
-
uint32 get_partition_id_cols_list_for_endpoint(partition_info *part_info,
bool left_endpoint,
bool include_endpoint,
@@ -3267,37 +3230,81 @@ uint32 get_partition_id_cols_list_for_endpoint(partition_info *part_info,
{
part_column_list_val *list_col_array= part_info->list_col_array;
uint num_columns= part_info->part_field_list.elements;
- int list_index, cmp;
+ uint list_index;
uint min_list_index= 0;
- uint max_list_index= part_info->num_list_values - 1;
- bool tailf= !(left_endpoint ^ include_endpoint);
+ uint max_list_index= part_info->num_list_values;
DBUG_ENTER("get_partition_id_cols_list_for_endpoint");
+ /* Find the matching partition (including taking endpoint into account). */
do
{
+ /* Midpoint, adjusted down, so it can never be > last index. */
list_index= (max_list_index + min_list_index) >> 1;
- cmp= cmp_rec_and_tuple_prune(list_col_array + list_index*num_columns,
- nparts, tailf);
- if (cmp > 0)
+ if (cmp_rec_and_tuple_prune(list_col_array + list_index*num_columns,
+ nparts, left_endpoint, include_endpoint) > 0)
min_list_index= list_index + 1;
- else if (cmp < 0)
- {
- if (!list_index)
- goto notfound;
- max_list_index= list_index - 1;
- }
- else
- {
- DBUG_RETURN(list_index + test(!tailf));
- }
- } while (max_list_index >= min_list_index);
- if (cmp > 0)
- list_index++;
-notfound:
+ else
+ max_list_index= list_index;
+ } while (max_list_index > min_list_index);
+ list_index= max_list_index;
+
+ /* Given value must be LESS THAN or EQUAL to the found partition. */
+ DBUG_ASSERT(list_index == part_info->num_list_values ||
+ (0 >= cmp_rec_and_tuple_prune(list_col_array +
+ list_index*num_columns,
+ nparts, left_endpoint,
+ include_endpoint)));
+ /* Given value must be GREATER THAN the previous partition. */
+ DBUG_ASSERT(list_index == 0 ||
+ (0 < cmp_rec_and_tuple_prune(list_col_array +
+ (list_index - 1)*num_columns,
+ nparts, left_endpoint,
+ include_endpoint)));
+
+ if (!left_endpoint)
+ {
+ /* Set the end after this list tuple if not already after the last. */
+ if (list_index < part_info->num_parts)
+ list_index++;
+ }
+
DBUG_RETURN(list_index);
}
+/**
+ Find the sub-array part_info->list_array that corresponds to given interval.
+
+ @param part_info Partitioning info (partitioning type must be LIST)
+ @param left_endpoint TRUE - the interval is [a; +inf) or (a; +inf)
+ FALSE - the interval is (-inf; a] or (-inf; a)
+ @param include_endpoint TRUE iff the interval includes the endpoint
+
+ This function finds the sub-array of part_info->list_array where values of
+ list_array[idx].list_value are contained within the specifed interval.
+ list_array is ordered by list_value, so
+ 1. For [a; +inf) or (a; +inf)-type intervals (left_endpoint==TRUE), the
+ sought sub-array starts at some index idx and continues till array end.
+ The function returns first number idx, such that
+ list_array[idx].list_value is contained within the passed interval.
+
+ 2. For (-inf; a] or (-inf; a)-type intervals (left_endpoint==FALSE), the
+ sought sub-array starts at array start and continues till some last
+ index idx.
+ The function returns first number idx, such that
+ list_array[idx].list_value is NOT contained within the passed interval.
+ If all array elements are contained, part_info->num_list_values is
+ returned.
+
+ @note The caller will call this function and then will run along the
+ sub-array of list_array to collect partition ids. If the number of list
+ values is significantly higher then number of partitions, this could be slow
+ and we could invent some other approach. The "run over list array" part is
+ already wrapped in a get_next()-like function.
+
+ @return The index of corresponding sub-array of part_info->list_array.
+*/
+
uint32 get_list_array_idx_for_endpoint_charset(partition_info *part_info,
bool left_endpoint,
bool include_endpoint)
@@ -7345,15 +7352,17 @@ uint32 store_tuple_to_record(Field **pfield,
return nparts;
}
-/*
- RANGE(columns) partitioning: compare value bound and probe tuple.
+/**
+ RANGE(columns) partitioning: compare partition value bound and probe tuple.
+
+ @param val Partition column values.
+ @param nvals_in_rec Number of (prefix) fields to compare.
- The value bound always is a full tuple (but may include the MAXVALUE
- special value).
+ @return Less than/Equal to/Greater than 0 if the record is L/E/G than val.
- The probe tuple may be a prefix of partitioning tuple. The tail_is_min
- parameter specifies whether the suffix components should be assumed to
- hold MAXVALUE
+ @note The partition value bound is always a full tuple (but may include the
+ MAXVALUE special value). The probe tuple may be a prefix of partitioning
+ tuple.
*/
static int cmp_rec_and_tuple(part_column_list_val *val, uint32 nvals_in_rec)
@@ -7383,25 +7392,73 @@ static int cmp_rec_and_tuple(part_column_list_val *val, uint32 nvals_in_rec)
}
+/**
+ Compare record and columns partition tuple including endpoint handling.
+
+ @param val Columns partition tuple
+ @param n_vals_in_rec Number of columns to compare
+ @param is_left_endpoint True if left endpoint (part_tuple < rec or
+ part_tuple <= rec)
+ @param include_endpoint If endpoint is included (part_tuple <= rec or
+ rec <= part_tuple)
+
+ @return Less than/Equal to/Greater than 0 if the record is L/E/G than
+ the partition tuple.
+
+ @see get_list_array_idx_for_endpoint() and
+ get_partition_id_range_for_endpoint().
+*/
+
static int cmp_rec_and_tuple_prune(part_column_list_val *val,
uint32 n_vals_in_rec,
- bool tail_is_min)
+ bool is_left_endpoint,
+ bool include_endpoint)
{
int cmp;
Field **field;
- partition_info *part_info;
if ((cmp= cmp_rec_and_tuple(val, n_vals_in_rec)))
return cmp;
- part_info= val->part_info;
- field= part_info->part_field_array + n_vals_in_rec;
- for (; *field; field++, val++)
+ field= val->part_info->part_field_array + n_vals_in_rec;
+ if (!(*field))
{
- if (tail_is_min)
- return -1;
- if (!tail_is_min && !val->max_value)
- return +1;
+ /*
+ Full match, if right endpoint and not including the endpoint,
+ (rec < part) return lesser.
+ */
+ if (!is_left_endpoint && !include_endpoint)
+ return -4;
+
+ /* Otherwise they are equal! */
+ return 0;
}
- return 0;
+ /*
+ The prefix is equal and there are more partition columns to compare.
+
+ If including left endpoint or not including right endpoint
+ then the record is considered lesser compared to the partition.
+
+ i.e:
+ part(10, x) <= rec(10, unknown) and rec(10, unknown) < part(10, x)
+ part <= rec -> lesser (i.e. this or previous partitions)
+ rec < part -> lesser (i.e. this or previous partitions)
+ */
+ if (is_left_endpoint == include_endpoint)
+ return -2;
+
+ /*
+ If right endpoint and the first additional partition value
+ is MAXVALUE, then the record is lesser.
+ */
+ if (!is_left_endpoint && (val + n_vals_in_rec)->max_value)
+ return -3;
+
+ /*
+ Otherwise the record is considered greater.
+
+ rec <= part -> greater (i.e. does not match this partition, seek higher).
+ part < rec -> greater (i.e. does not match this partition, seek higher).
+ */
+ return 2;
}
@@ -7412,91 +7469,65 @@ typedef uint32 (*get_col_endpoint_func)(partition_info*, bool left_endpoint,
bool include_endpoint,
uint32 num_parts);
-/*
- Partitioning Interval Analysis: Initialize the iterator for "mapping" case
+/**
+ Get partition for RANGE COLUMNS endpoint.
- SYNOPSIS
- get_part_iter_for_interval_via_mapping()
- part_info Partition info
- is_subpart TRUE - act for subpartitioning
- FALSE - act for partitioning
- min_value minimum field value, in opt_range key format.
- max_value minimum field value, in opt_range key format.
- flags Some combination of NEAR_MIN, NEAR_MAX, NO_MIN_RANGE,
- NO_MAX_RANGE.
- part_iter Iterator structure to be initialized
+ @param part_info Partitioning metadata.
+ @param is_left_endpoint True if left endpoint (const <=/< cols)
+ @param include_endpoint True if range includes the endpoint (<=/>=)
+ @param nparts Total number of partitions
- DESCRIPTION
- Initialize partition set iterator to walk over the interval in
- ordered-array-of-partitions (for RANGE partitioning) or
- ordered-array-of-list-constants (for LIST partitioning) space.
+ @return Partition id of matching partition.
- IMPLEMENTATION
- This function is used when partitioning is done by
- <RANGE|LIST>(ascending_func(t.field)), and we can map an interval in
- t.field space into a sub-array of partition_info::range_int_array or
- partition_info::list_array (see get_partition_id_range_for_endpoint,
- get_list_array_idx_for_endpoint for details).
-
- The function performs this interval mapping, and sets the iterator to
- traverse the sub-array and return appropriate partitions.
-
- RETURN
- 0 - No matching partitions (iterator not initialized)
- 1 - Ok, iterator intialized for traversal of matching partitions.
- -1 - All partitions would match (iterator not initialized)
+ @see get_partition_id_cols_list_for_endpoint and
+ get_partition_id_range_for_endpoint.
*/
uint32 get_partition_id_cols_range_for_endpoint(partition_info *part_info,
- bool left_endpoint,
+ bool is_left_endpoint,
bool include_endpoint,
uint32 nparts)
{
- uint max_partition= part_info->num_parts - 1;
- uint min_part_id= 0, max_part_id= max_partition, loc_part_id;
+ uint min_part_id= 0, max_part_id= part_info->num_parts, loc_part_id;
part_column_list_val *range_col_array= part_info->range_col_array;
uint num_columns= part_info->part_field_list.elements;
- bool tailf= !(left_endpoint ^ include_endpoint);
DBUG_ENTER("get_partition_id_cols_range_for_endpoint");
- /* Get the partitioning function value for the endpoint */
- while (max_part_id > min_part_id)
+ /* Find the matching partition (including taking endpoint into account). */
+ do
{
- loc_part_id= (max_part_id + min_part_id + 1) >> 1;
- if (cmp_rec_and_tuple_prune(range_col_array + loc_part_id*num_columns,
- nparts, tailf) >= 0)
+ /* Midpoint, adjusted down, so it can never be > last partition. */
+ loc_part_id= (max_part_id + min_part_id) >> 1;
+ if (0 <= cmp_rec_and_tuple_prune(range_col_array +
+ loc_part_id * num_columns,
+ nparts,
+ is_left_endpoint,
+ include_endpoint))
min_part_id= loc_part_id + 1;
else
- max_part_id= loc_part_id - 1;
- }
+ max_part_id= loc_part_id;
+ } while (max_part_id > min_part_id);
loc_part_id= max_part_id;
- if (loc_part_id < max_partition &&
- cmp_rec_and_tuple_prune(range_col_array + (loc_part_id+1)*num_columns,
- nparts, tailf) >= 0
- )
- {
- loc_part_id++;
- }
- if (left_endpoint)
- {
- if (cmp_rec_and_tuple_prune(range_col_array + loc_part_id*num_columns,
- nparts, tailf) >= 0)
+
+ /* Given value must be LESS THAN the found partition. */
+ DBUG_ASSERT(loc_part_id == part_info->num_parts ||
+ (0 > cmp_rec_and_tuple_prune(range_col_array +
+ loc_part_id * num_columns,
+ nparts, is_left_endpoint,
+ include_endpoint)));
+ /* Given value must be GREATER THAN or EQUAL to the previous partition. */
+ DBUG_ASSERT(loc_part_id == 0 ||
+ (0 <= cmp_rec_and_tuple_prune(range_col_array +
+ (loc_part_id - 1) * num_columns,
+ nparts, is_left_endpoint,
+ include_endpoint)));
+
+ if (!is_left_endpoint)
+ {
+ /* Set the end after this partition if not already after the last. */
+ if (loc_part_id < part_info->num_parts)
loc_part_id++;
}
- else
- {
- if (loc_part_id < max_partition)
- {
- int res= cmp_rec_and_tuple_prune(range_col_array +
- loc_part_id * num_columns,
- nparts, tailf);
- if (!res)
- loc_part_id += test(include_endpoint);
- else if (res > 0)
- loc_part_id++;
- }
- loc_part_id++;
- }
DBUG_RETURN(loc_part_id);
}
@@ -7568,6 +7599,40 @@ int get_part_iter_for_interval_cols_via_map(partition_info *part_info,
}
+/**
+ Partitioning Interval Analysis: Initialize the iterator for "mapping" case
+
+ @param part_info Partition info
+ @param is_subpart TRUE - act for subpartitioning
+ FALSE - act for partitioning
+ @param store_length_array Ignored.
+ @param min_value minimum field value, in opt_range key format.
+ @param max_value minimum field value, in opt_range key format.
+ @param min_len Ignored.
+ @param max_len Ignored.
+ @param flags Some combination of NEAR_MIN, NEAR_MAX, NO_MIN_RANGE,
+ NO_MAX_RANGE.
+ @param part_iter Iterator structure to be initialized
+
+ @details Initialize partition set iterator to walk over the interval in
+ ordered-array-of-partitions (for RANGE partitioning) or
+ ordered-array-of-list-constants (for LIST partitioning) space.
+
+ This function is used when partitioning is done by
+ <RANGE|LIST>(ascending_func(t.field)), and we can map an interval in
+ t.field space into a sub-array of partition_info::range_int_array or
+ partition_info::list_array (see get_partition_id_range_for_endpoint,
+ get_list_array_idx_for_endpoint for details).
+
+ The function performs this interval mapping, and sets the iterator to
+ traverse the sub-array and return appropriate partitions.
+
+ @return Status of iterator
+ @retval 0 No matching partitions (iterator not initialized)
+ @retval 1 Ok, iterator intialized for traversal of matching partitions.
+ @retval -1 All partitions would match (iterator not initialized)
+*/
+
int get_part_iter_for_interval_via_mapping(partition_info *part_info,
bool is_subpart,
uint32 *store_length_array, /* ignored */
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
index 40ccd275947..ee0b1ac0c4b 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -2391,6 +2391,7 @@ typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_longlong_t, longlong);
typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_uint_t, uint);
typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_ulong_t, ulong);
typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_ulonglong_t, ulonglong);
+typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_double_t, double);
typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_int_t, int);
typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_long_t, long);
@@ -2398,6 +2399,7 @@ typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_longlong_t, longlong);
typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_uint_t, uint);
typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_ulong_t, ulong);
typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_ulonglong_t, ulonglong);
+typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_double_t, double);
/****************************************************************************
@@ -2613,6 +2615,20 @@ err:
return 1;
}
+static int check_func_double(THD *thd, struct st_mysql_sys_var *var,
+ void *save, st_mysql_value *value)
+{
+ double v;
+ my_bool fixed;
+ struct my_option option;
+
+ value->val_real(value, &v);
+ plugin_opt_set_limits(&option, var);
+ *(double *) save= getopt_double_limit_value(v, &option, &fixed);
+
+ return throw_bounds_warning(thd, var->name, fixed, v);
+}
+
static void update_func_bool(THD *thd, struct st_mysql_sys_var *var,
void *tgt, const void *save)
@@ -2654,6 +2670,11 @@ static void update_func_str(THD *thd, struct st_mysql_sys_var *var,
}
}
+static void update_func_double(THD *thd, struct st_mysql_sys_var *var,
+ void *tgt, const void *save)
+{
+ *(double *) tgt= *(double *) save;
+}
/****************************************************************************
System Variables support
@@ -2768,6 +2789,9 @@ static st_bookmark *register_var(const char *plugin, const char *name,
case PLUGIN_VAR_STR:
size= sizeof(char*);
break;
+ case PLUGIN_VAR_DOUBLE:
+ size= sizeof(double);
+ break;
default:
DBUG_ASSERT(0);
return NULL;
@@ -2980,6 +3004,11 @@ static char **mysql_sys_var_str(THD* thd, int offset)
return (char **) intern_sys_var_ptr(thd, offset, true);
}
+static double *mysql_sys_var_double(THD* thd, int offset)
+{
+ return (double *) intern_sys_var_ptr(thd, offset, true);
+}
+
void plugin_thdvar_init(THD *thd)
{
plugin_ref old_table_plugin= thd->variables.table_plugin;
@@ -3132,6 +3161,8 @@ static SHOW_TYPE pluginvar_show_type(st_mysql_sys_var *plugin_var)
case PLUGIN_VAR_ENUM:
case PLUGIN_VAR_SET:
return SHOW_CHAR;
+ case PLUGIN_VAR_DOUBLE:
+ return SHOW_DOUBLE;
default:
DBUG_ASSERT(0);
return SHOW_UNDEF;
@@ -3152,6 +3183,8 @@ bool sys_var_pluginvar::check_update_type(Item_result type)
case PLUGIN_VAR_BOOL:
case PLUGIN_VAR_SET:
return type != STRING_RESULT && type != INT_RESULT;
+ case PLUGIN_VAR_DOUBLE:
+ return type != INT_RESULT && type != REAL_RESULT && type != DECIMAL_RESULT;
default:
return true;
}
@@ -3270,6 +3303,9 @@ bool sys_var_pluginvar::global_update(THD *thd, set_var *var)
case PLUGIN_VAR_STR:
src= &((sysvar_str_t*) plugin_var)->def_val;
break;
+ case PLUGIN_VAR_DOUBLE:
+ src= &((sysvar_double_t*) plugin_var)->def_val;
+ break;
case PLUGIN_VAR_INT | PLUGIN_VAR_THDLOCAL:
src= &((thdvar_uint_t*) plugin_var)->def_val;
break;
@@ -3291,6 +3327,9 @@ bool sys_var_pluginvar::global_update(THD *thd, set_var *var)
case PLUGIN_VAR_STR | PLUGIN_VAR_THDLOCAL:
src= &((thdvar_str_t*) plugin_var)->def_val;
break;
+ case PLUGIN_VAR_DOUBLE | PLUGIN_VAR_THDLOCAL:
+ src= &((thdvar_double_t*) plugin_var)->def_val;
+ break;
default:
DBUG_ASSERT(0);
}
@@ -3308,6 +3347,13 @@ bool sys_var_pluginvar::global_update(THD *thd, set_var *var)
options->max_value= (opt)->max_val; \
options->block_size= (long) (opt)->blk_sz
+#define OPTION_SET_LIMITS_DOUBLE(options, opt) \
+ options->var_type= GET_DOUBLE; \
+ options->def_value= (longlong) getopt_double2ulonglong((opt)->def_val); \
+ options->min_value= (longlong) getopt_double2ulonglong((opt)->min_val); \
+ options->max_value= getopt_double2ulonglong((opt)->max_val); \
+ options->block_size= (long) (opt)->blk_sz;
+
static void plugin_opt_set_limits(struct my_option *options,
const struct st_mysql_sys_var *opt)
@@ -3358,6 +3404,9 @@ static void plugin_opt_set_limits(struct my_option *options,
GET_STR_ALLOC : GET_STR);
options->def_value= (intptr) ((sysvar_str_t*) opt)->def_val;
break;
+ case PLUGIN_VAR_DOUBLE:
+ OPTION_SET_LIMITS_DOUBLE(options, (sysvar_double_t*) opt);
+ break;
/* threadlocal variables */
case PLUGIN_VAR_INT | PLUGIN_VAR_THDLOCAL:
OPTION_SET_LIMITS(GET_INT, options, (thdvar_int_t*) opt);
@@ -3377,6 +3426,9 @@ static void plugin_opt_set_limits(struct my_option *options,
case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_THDLOCAL:
OPTION_SET_LIMITS(GET_ULL, options, (thdvar_ulonglong_t*) opt);
break;
+ case PLUGIN_VAR_DOUBLE | PLUGIN_VAR_THDLOCAL:
+ OPTION_SET_LIMITS_DOUBLE(options, (thdvar_double_t*) opt);
+ break;
case PLUGIN_VAR_ENUM | PLUGIN_VAR_THDLOCAL:
options->var_type= GET_ENUM;
options->typelib= ((thdvar_enum_t*) opt)->typelib;
@@ -3539,6 +3591,9 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp,
case PLUGIN_VAR_SET:
((thdvar_set_t *) opt)->resolve= mysql_sys_var_ulonglong;
break;
+ case PLUGIN_VAR_DOUBLE:
+ ((thdvar_double_t *) opt)->resolve= mysql_sys_var_double;
+ break;
default:
sql_print_error("Unknown variable type code 0x%x in plugin '%s'.",
opt->flags, plugin_name);
@@ -3602,6 +3657,12 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp,
if (!opt->update)
opt->update= update_func_longlong;
break;
+ case PLUGIN_VAR_DOUBLE:
+ if (!opt->check)
+ opt->check= check_func_double;
+ if (!opt->update)
+ opt->update= update_func_double;
+ break;
default:
sql_print_error("Unknown variable type code 0x%x in plugin '%s'.",
opt->flags, plugin_name);
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index 6b0d1e980f9..ee7c0fd2f73 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -1,5 +1,6 @@
/*
- Copyright (c) 2000, 2010, Oracle and/or its affiliates.
+ Copyright (c) 2000, 2013, Oracle and/or its affiliates.
+ Copyright (c) 2011, 2013, 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
@@ -294,7 +295,7 @@ do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db, char *new_table_name,
(void) mysql_rename_table(ha_resolve_by_legacy_type(thd,
table_type),
new_db, new_alias,
- ren_table->db, old_alias, 0);
+ ren_table->db, old_alias, NO_FK_CHECKS);
}
}
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index c3b3fc5eaac..60c875f8f55 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -5038,8 +5038,23 @@ static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array)
Optionally (if out_args is supplied) will push the arguments of
AGGFN(DISTINCT) to the list
+ Check for every COUNT(DISTINCT), AVG(DISTINCT) or
+ SUM(DISTINCT). These can be resolved by Loose Index Scan as long
+ as all the aggregate distinct functions refer to the same
+ fields. Thus:
+
+ SELECT AGGFN(DISTINCT a, b), AGGFN(DISTINCT b, a)... => can use LIS
+ SELECT AGGFN(DISTINCT a), AGGFN(DISTINCT a) ... => can use LIS
+ SELECT AGGFN(DISTINCT a, b), AGGFN(DISTINCT a) ... => cannot use LIS
+ SELECT AGGFN(DISTINCT a), AGGFN(DISTINCT b) ... => cannot use LIS
+ etc.
+
@param join the join to check
- @param[out] out_args list of aggregate function arguments
+ @param[out] out_args Collect the arguments of the aggregate functions
+ to a list. We don't worry about duplicates as
+ these will be sorted out later in
+ get_best_group_min_max.
+
@return does the query qualify for indexed AGGFN(DISTINCT)
@retval true it does
@retval false AGGFN(DISTINCT) must apply distinct in it.
@@ -5050,6 +5065,7 @@ is_indexed_agg_distinct(JOIN *join, List<Item_field> *out_args)
{
Item_sum **sum_item_ptr;
bool result= false;
+ Field_map first_aggdistinct_fields;
if (join->table_count != 1 || /* reference more than 1 table */
join->select_distinct || /* or a DISTINCT */
@@ -5062,6 +5078,7 @@ is_indexed_agg_distinct(JOIN *join, List<Item_field> *out_args)
for (sum_item_ptr= join->sum_funcs; *sum_item_ptr; sum_item_ptr++)
{
Item_sum *sum_item= *sum_item_ptr;
+ Field_map cur_aggdistinct_fields;
Item *expr;
/* aggregate is not AGGFN(DISTINCT) or more than 1 argument to it */
switch (sum_item->sum_func())
@@ -5091,15 +5108,23 @@ is_indexed_agg_distinct(JOIN *join, List<Item_field> *out_args)
if (expr->real_item()->type() != Item::FIELD_ITEM)
return false;
- /*
- If we came to this point the AGGFN(DISTINCT) loose index scan
- optimization is applicable
- */
+ Item_field* item= static_cast<Item_field*>(expr->real_item());
if (out_args)
- out_args->push_back((Item_field *) expr->real_item());
+ out_args->push_back(item);
+
+ cur_aggdistinct_fields.set_bit(item->field->field_index);
result= true;
}
+ /*
+ If there are multiple aggregate functions, make sure that they all
+ refer to exactly the same set of columns.
+ */
+ if (first_aggdistinct_fields.is_clear_all())
+ first_aggdistinct_fields.merge(cur_aggdistinct_fields);
+ else if (first_aggdistinct_fields != cur_aggdistinct_fields)
+ return false;
}
+
return result;
}
@@ -21169,22 +21194,20 @@ change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array,
if (field != NULL)
{
/*
- Replace "@:=<expression>" with "@:=<tmp table column>". Otherwise,
- we would re-evaluate <expression>, and if expression were
- a subquery, this would access already-unlocked tables.
- */
+ Replace "@:=<expression>" with "@:=<tmp table column>". Otherwise, we
+ would re-evaluate <expression>, and if expression were a subquery, this
+ would access already-unlocked tables.
+ */
Item_func_set_user_var* suv=
- new Item_func_set_user_var((Item_func_set_user_var*) item);
+ new Item_func_set_user_var(thd, (Item_func_set_user_var*) item);
Item_field *new_field= new Item_field(field);
- if (!suv || !new_field || suv->fix_fields(thd, (Item**)&suv))
+ if (!suv || !new_field)
DBUG_RETURN(true); // Fatal error
- ((Item *)suv)->name= item->name;
/*
- We are replacing the argument of Item_func_set_user_var after its
- value has been read. The argument's null_value should be set by
- now, so we must set it explicitly for the replacement argument
- since the null_value may be read without any preceeding call to
- val_*().
+ We are replacing the argument of Item_func_set_user_var after its value
+ has been read. The argument's null_value should be set by now, so we
+ must set it explicitly for the replacement argument since the null_value
+ may be read without any preceeding call to val_*().
*/
new_field->update_null_value();
List<Item> list;
@@ -21215,15 +21238,15 @@ change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array,
ifield->db_name= iref->db_name;
}
#ifndef DBUG_OFF
- if (!item_field->name)
- {
- char buff[256];
- String str(buff,sizeof(buff),&my_charset_bin);
- str.length(0);
- str.extra_allocation(1024);
- item->print(&str, QT_ORDINARY);
- item_field->name= sql_strmake(str.ptr(),str.length());
- }
+ if (!item_field->name)
+ {
+ char buff[256];
+ String str(buff,sizeof(buff),&my_charset_bin);
+ str.length(0);
+ str.extra_allocation(1024);
+ item->print(&str, QT_ORDINARY);
+ item_field->name= sql_strmake(str.ptr(),str.length());
+ }
#endif
}
else
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 97a2ef03757..d7102c0e3f6 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -4655,6 +4655,8 @@ make_unique_key_name(const char *field_name,KEY *start,KEY *end)
FN_TO_IS_TMP new_name is temporary.
NO_FRM_RENAME Don't rename the FRM file
but only the table in the storage engine.
+ NO_FK_CHECKS Don't check FK constraints
+ during rename.
RETURN
FALSE OK
@@ -4673,9 +4675,14 @@ mysql_rename_table(handlerton *base, const char *old_db,
char tmp_name[SAFE_NAME_LEN+1];
handler *file;
int error=0;
+ ulonglong save_bits= thd->variables.option_bits;
DBUG_ENTER("mysql_rename_table");
DBUG_PRINT("enter", ("old: '%s'.'%s' new: '%s'.'%s'",
old_db, old_name, new_db, new_name));
+
+ // Temporarily disable foreign key checks
+ if (flags & NO_FK_CHECKS)
+ thd->variables.option_bits|= OPTION_NO_FOREIGN_KEY_CHECKS;
file= (base == NULL ? 0 :
get_new_handler((TABLE_SHARE*) 0, thd->mem_root, base));
@@ -4723,6 +4730,10 @@ mysql_rename_table(handlerton *base, const char *old_db,
my_error(ER_ERROR_ON_RENAME, MYF(0), from, to, error);
else if (!(flags & FN_IS_TMP))
mysql_audit_rename_table(thd, old_db, old_name, new_db, new_name);
+
+ // Restore options bits to the original value
+ thd->variables.option_bits= save_bits;
+
DBUG_RETURN(error != 0);
}
@@ -6327,7 +6338,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
new_db, new_alias))
{
(void) mysql_rename_table(old_db_type, new_db, new_alias, db,
- table_name, 0);
+ table_name, NO_FK_CHECKS);
error= -1;
}
}
@@ -7102,7 +7113,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
error= 1;
(void) quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP);
(void) mysql_rename_table(old_db_type, db, old_name, db, alias,
- FN_FROM_IS_TMP);
+ FN_FROM_IS_TMP | NO_FK_CHECKS);
}
else if (new_name != table_name || new_db != db)
{
@@ -7114,7 +7125,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
error= 1;
(void) quick_rm_table(new_db_type, new_db, new_alias, 0);
(void) mysql_rename_table(old_db_type, db, old_name, db, alias,
- FN_FROM_IS_TMP);
+ FN_FROM_IS_TMP | NO_FK_CHECKS);
}
else if (Table_triggers_list::change_table_name(thd, db, alias,
table_name, new_db,
@@ -7124,7 +7135,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
error= 1;
(void) quick_rm_table(new_db_type, new_db, new_alias, 0);
(void) mysql_rename_table(old_db_type, db, old_name, db,
- alias, FN_FROM_IS_TMP);
+ alias, FN_FROM_IS_TMP | NO_FK_CHECKS);
/*
If we were performing "fast"/in-place ALTER TABLE we also need
to restore old name of table in storage engine as a separate
@@ -7133,7 +7144,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (need_copy_table == ALTER_TABLE_METADATA_ONLY)
{
(void) mysql_rename_table(save_old_db_type, new_db, new_alias,
- db, table_name, NO_FRM_RENAME);
+ db, table_name,
+ NO_FRM_RENAME | NO_FK_CHECKS);
}
}
}
diff --git a/sql/sql_table.h b/sql/sql_table.h
index 00de6ed1b8d..c8ecb3ced4f 100644
--- a/sql/sql_table.h
+++ b/sql/sql_table.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2006, 2013, 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
@@ -118,6 +118,8 @@ enum enum_explain_filename_mode
#define FN_IS_TMP (FN_FROM_IS_TMP | FN_TO_IS_TMP)
#define NO_FRM_RENAME (1 << 2)
#define FRM_ONLY (1 << 3)
+/** Don't check foreign key constraints while renaming table */
+#define NO_FK_CHECKS (1 << 4)
uint filename_to_tablename(const char *from, char *to, uint to_length
#ifndef DBUG_OFF
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 885ec01e14d..1c1cd0958f1 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -4188,8 +4188,8 @@ ts_wait:
;
size_number:
- real_ulong_num { $$= $1;}
- | IDENT
+ real_ulonglong_num { $$= $1;}
+ | IDENT_sys
{
ulonglong number;
uint text_shift_number= 0;
diff --git a/sql/sys_vars.h b/sql/sys_vars.h
index b7be81afd73..3cbd24f1c89 100644
--- a/sql/sys_vars.h
+++ b/sql/sys_vars.h
@@ -1,4 +1,5 @@
-/* Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2002, 2011, Oracle and/or its affiliates.
+ Copyright (c) 2010, 2013, 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
@@ -138,6 +139,7 @@ public:
option.u_max_value= (uchar**)max_var_ptr();
if (max_var_ptr())
*max_var_ptr()= max_val;
+
global_var(T)= def_val;
SYSVAR_ASSERT(size == sizeof(T));
SYSVAR_ASSERT(min_val < max_val);
@@ -904,13 +906,14 @@ public:
on_update_function on_update_func=0,
const char *substitute=0)
: sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
- getopt.arg_type, SHOW_DOUBLE, (longlong) double2ulonglong(def_val),
+ getopt.arg_type, SHOW_DOUBLE,
+ (longlong) getopt_double2ulonglong(def_val),
lock, binlog_status_arg, on_check_func, on_update_func,
substitute)
{
option.var_type= GET_DOUBLE;
- option.min_value= (longlong) double2ulonglong(min_val);
- option.max_value= (longlong) double2ulonglong(max_val);
+ option.min_value= (longlong) getopt_double2ulonglong(min_val);
+ option.max_value= (longlong) getopt_double2ulonglong(max_val);
global_var(double)= (double)option.def_value;
SYSVAR_ASSERT(min_val < max_val);
SYSVAR_ASSERT(min_val <= def_val);
@@ -942,7 +945,7 @@ public:
void session_save_default(THD *thd, set_var *var)
{ var->save_result.double_value= global_var(double); }
void global_save_default(THD *thd, set_var *var)
- { var->save_result.double_value= (double)option.def_value; }
+ { var->save_result.double_value= getopt_ulonglong2double(option.def_value); }
};
/**
diff --git a/sql/table.h b/sql/table.h
index 0e41c10447a..c7a032e3811 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -953,9 +953,13 @@ enum index_hint_type
INDEX_HINT_FORCE
};
+
#define CHECK_ROW_FOR_NULLS_TO_REJECT (1 << 0)
#define REJECT_ROW_DUE_TO_NULL_FIELDS (1 << 1)
+/* Bitmap of table's fields */
+typedef Bitmap<MAX_FIELDS> Field_map;
+
struct TABLE
{
TABLE() {} /* Remove gcc warning */