diff options
author | Sergei Golubchik <sergii@pisem.net> | 2013-09-06 22:31:30 +0200 |
---|---|---|
committer | Sergei Golubchik <sergii@pisem.net> | 2013-09-06 22:31:30 +0200 |
commit | b838d081ad346e52787753b1799c627922c4a6c7 (patch) | |
tree | dc8f1e21e6b40d5b72668571c570c9a3214fbf32 /sql | |
parent | 824db55ce53963a64fcf648b54500df22c57e9b2 (diff) | |
parent | 72c36f4415815d55ddb82b23682f3c549906c00e (diff) | |
download | mariadb-git-b838d081ad346e52787753b1799c627922c4a6c7.tar.gz |
mysql-5.5.33 merge
Diffstat (limited to 'sql')
-rw-r--r-- | sql/debug_sync.cc | 4 | ||||
-rw-r--r-- | sql/field.cc | 8 | ||||
-rw-r--r-- | sql/ha_partition.cc | 124 | ||||
-rw-r--r-- | sql/ha_partition.h | 2 | ||||
-rw-r--r-- | sql/item_func.h | 17 | ||||
-rw-r--r-- | sql/item_subselect.cc | 11 | ||||
-rw-r--r-- | sql/log_event.h | 1 | ||||
-rw-r--r-- | sql/partition_info.cc | 2 | ||||
-rw-r--r-- | sql/signal_handler.cc | 2 | ||||
-rw-r--r-- | sql/sql_bitmap.h | 1 | ||||
-rw-r--r-- | sql/sql_load.cc | 3 | ||||
-rw-r--r-- | sql/sql_partition.cc | 349 | ||||
-rw-r--r-- | sql/sql_plugin.cc | 61 | ||||
-rw-r--r-- | sql/sql_rename.cc | 5 | ||||
-rw-r--r-- | sql/sql_select.cc | 77 | ||||
-rw-r--r-- | sql/sql_table.cc | 22 | ||||
-rw-r--r-- | sql/sql_table.h | 4 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 4 | ||||
-rw-r--r-- | sql/sys_vars.h | 13 | ||||
-rw-r--r-- | sql/table.h | 4 |
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 */ |