summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/CMakeLists.txt8
-rw-r--r--sql/handler.cc8
-rw-r--r--sql/item.h5
-rw-r--r--sql/item_cmpfunc.h5
-rw-r--r--sql/item_func.cc8
-rw-r--r--sql/item_geofunc.cc8
-rw-r--r--sql/log.cc63
-rw-r--r--sql/log_event.cc14
-rw-r--r--sql/opt_subselect.cc7
-rw-r--r--sql/rpl_parallel.cc31
-rw-r--r--sql/slave.cc18
-rw-r--r--sql/sql_acl.cc26
-rw-r--r--sql/sql_base.cc3
-rw-r--r--sql/sql_db.cc6
-rw-r--r--sql/sql_delete.cc5
-rw-r--r--sql/sql_derived.cc3
-rw-r--r--sql/sql_parse.cc12
-rw-r--r--sql/sql_select.cc56
-rw-r--r--sql/sql_select.h4
-rw-r--r--sql/sql_test.cc2
-rw-r--r--sql/sql_yacc.yy7
-rw-r--r--sql/structs.h1
-rw-r--r--sql/table.cc46
-rw-r--r--sql/table.h20
-rw-r--r--sql/udf_example.c5
25 files changed, 253 insertions, 118 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index c78fa73bb51..9a2ab3c72c8 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -1,4 +1,5 @@
-# Copyright (c) 2006, 2013, Oracle and/or its affiliates.
+# Copyright (c) 2006, 2014, Oracle and/or its affiliates.
+# Copyright (c) 2010, 2015, MariaDB
#
# 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
@@ -287,14 +288,15 @@ IF(WIN32 OR HAVE_DLOPEN AND NOT DISABLE_SHARED)
ENDIF()
FOREACH(tool glibtoolize libtoolize aclocal autoconf autoheader automake gtar
- tar bzr git)
+ tar git)
STRING(TOUPPER ${tool} TOOL)
FIND_PROGRAM(${TOOL}_EXECUTABLE ${tool} DOC "path to the executable")
MARK_AS_ADVANCED(${TOOL}_EXECUTABLE)
ENDFOREACH()
CONFIGURE_FILE(
- ${CMAKE_SOURCE_DIR}/cmake/make_dist.cmake.in ${CMAKE_BINARY_DIR}/make_dist.cmake @ONLY)
+ ${CMAKE_SOURCE_DIR}/cmake/make_dist.cmake.in
+ ${CMAKE_BINARY_DIR}/make_dist.cmake @ONLY)
ADD_CUSTOM_TARGET(dist
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_BINARY_DIR}/make_dist.cmake
diff --git a/sql/handler.cc b/sql/handler.cc
index 7c70babfea8..12d7ffb2f5e 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -1476,7 +1476,13 @@ done:
/* Come here if error and we need to rollback. */
err:
error= 1; /* Transaction was rolled back */
- ha_rollback_trans(thd, all);
+ /*
+ In parallel replication, rollback is delayed, as there is extra replication
+ book-keeping to be done before rolling back and allowing a conflicting
+ transaction to continue (MDEV-7458).
+ */
+ if (!(thd->rgi_slave && thd->rgi_slave->is_parallel_exec))
+ ha_rollback_trans(thd, all);
end:
if (rw_trans && mdl_request.ticket)
diff --git a/sql/item.h b/sql/item.h
index baa6bf51728..4a57be8e9ce 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -2869,8 +2869,9 @@ public:
{
set_cs_specified(true);
}
- Item_string_with_introducer(const String *str, CHARSET_INFO *tocs)
- :Item_string(str->ptr(), str->length(), tocs)
+ Item_string_with_introducer(const char *name,
+ const char *str, uint length, CHARSET_INFO *tocs)
+ :Item_string(name, str, length, tocs)
{
set_cs_specified(true);
}
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 9d0f2e62e5c..65b2c6148d4 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -734,6 +734,11 @@ public:
void fix_length_and_dec();
const char *func_name() const { return "interval"; }
uint decimal_precision() const { return 2; }
+ void print(String *str, enum_query_type query_type)
+ {
+ str->append(func_name());
+ print_args(str, 0, query_type);
+ }
};
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 92b20fbb15f..85a5f7c7ced 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2014, Oracle and/or its affiliates.
- Copyright (c) 2009, 2014, SkySQL Ab.
+ Copyright (c) 2009, 2015, MariaDB
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
@@ -3672,8 +3672,12 @@ bool udf_handler::get_arguments()
{
f_args.args[i]= (char*) res->ptr();
f_args.lengths[i]= res->length();
- break;
}
+ else
+ {
+ f_args.lengths[i]= 0;
+ }
+ break;
}
case INT_RESULT:
*((longlong*) to) = args[i]->val_int();
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index 3e5856f6cb0..e67ab9115e9 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -1793,6 +1793,13 @@ String *Item_func_buffer::val_str(String *str_value)
if (dist > 0.0)
mbr.buffer(dist);
+ else
+ {
+ /* This happens when dist is too far negative. */
+ if (mbr.xmax + dist < mbr.xmin || mbr.ymax + dist < mbr.ymin)
+ goto return_empty_result;
+ }
+
collector.set_extent(mbr.xmin, mbr.xmax, mbr.ymin, mbr.ymax);
/*
If the distance given is 0, the Buffer function is in fact NOOP,
@@ -1820,6 +1827,7 @@ String *Item_func_buffer::val_str(String *str_value)
goto mem_error;
+return_empty_result:
str_value->set_charset(&my_charset_bin);
if (str_value->reserve(SRID_SIZE, 512))
goto mem_error;
diff --git a/sql/log.cc b/sql/log.cc
index adb15f31198..94536e49145 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -5728,6 +5728,14 @@ end:
}
+/*
+ Initialize the binlog state from the master-bin.state file, at server startup.
+
+ Returns:
+ 0 for success.
+ 2 for when .state file did not exist.
+ 1 for other error.
+*/
int
MYSQL_BIN_LOG::read_state_from_file()
{
@@ -5755,7 +5763,7 @@ MYSQL_BIN_LOG::read_state_from_file()
with GTID enabled. So initialize to empty state.
*/
rpl_global_gtid_binlog_state.reset();
- err= 0;
+ err= 2;
goto end;
}
}
@@ -7490,6 +7498,8 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader)
my_error(ER_ERROR_ON_WRITE, MYF(ME_NOREFRESH), name, errno);
check_purge= false;
}
+ /* In case of binlog rotate, update the correct current binlog offset. */
+ commit_offset= my_b_write_tell(&log_file);
}
DEBUG_SYNC(leader->thd, "commit_before_get_LOCK_after_binlog_sync");
@@ -9649,7 +9659,17 @@ MYSQL_BIN_LOG::do_binlog_recovery(const char *opt_name, bool do_xa_recovery)
if (error != LOG_INFO_EOF)
sql_print_error("find_log_pos() failed (error: %d)", error);
else
+ {
error= read_state_from_file();
+ if (error == 2)
+ {
+ /*
+ No binlog files and no binlog state is not an error (eg. just initial
+ server start after fresh installation).
+ */
+ error= 0;
+ }
+ }
return error;
}
@@ -9675,15 +9695,42 @@ MYSQL_BIN_LOG::do_binlog_recovery(const char *opt_name, bool do_xa_recovery)
if ((ev= Log_event::read_log_event(&log, 0, &fdle,
opt_master_verify_checksum)) &&
- ev->get_type_code() == FORMAT_DESCRIPTION_EVENT &&
- ev->flags & LOG_EVENT_BINLOG_IN_USE_F)
+ ev->get_type_code() == FORMAT_DESCRIPTION_EVENT)
{
- sql_print_information("Recovering after a crash using %s", opt_name);
- error= recover(&log_info, log_name, &log,
- (Format_description_log_event *)ev, do_xa_recovery);
+ if (ev->flags & LOG_EVENT_BINLOG_IN_USE_F)
+ {
+ sql_print_information("Recovering after a crash using %s", opt_name);
+ error= recover(&log_info, log_name, &log,
+ (Format_description_log_event *)ev, do_xa_recovery);
+ }
+ else
+ {
+ error= read_state_from_file();
+ if (error == 2)
+ {
+ /*
+ The binlog exists, but the .state file is missing. This is normal if
+ this is the first master start after a major upgrade to 10.0 (with
+ GTID support).
+
+ However, it could also be that the .state file was lost somehow, and
+ in this case it could be a serious issue, as we would set the wrong
+ binlog state in the next binlog file to be created, and GTID
+ processing would be corrupted. A common way would be copying files
+ from an old server to a new one and forgetting the .state file.
+
+ So in this case, we want to try to recover the binlog state by
+ scanning the last binlog file (but we do not need any XA recovery).
+
+ ToDo: We could avoid one scan at first start after major upgrade, by
+ detecting that there is no GTID_LIST event at the start of the
+ binlog file, and stopping the scan in that case.
+ */
+ error= recover(&log_info, log_name, &log,
+ (Format_description_log_event *)ev, false);
+ }
+ }
}
- else
- error= read_state_from_file();
delete ev;
end_io_cache(&log);
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 4a7b1e221c9..e66096aa39c 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -52,6 +52,8 @@
#define my_b_write_string(A, B) my_b_write((A), (B), (uint) (sizeof(B) - 1))
+using std::max;
+
/**
BINLOG_CHECKSUM variable.
*/
@@ -1315,9 +1317,10 @@ int Log_event::read_log_event(IO_CACHE* file, String* packet,
}
data_len= uint4korr(buf + EVENT_LEN_OFFSET);
if (data_len < LOG_EVENT_MINIMAL_HEADER_LEN ||
- data_len > current_thd->variables.max_allowed_packet)
+ data_len > max(current_thd->variables.max_allowed_packet,
+ opt_binlog_rows_event_max_size + MAX_LOG_EVENT_HEADER))
{
- DBUG_PRINT("error",("data_len: %ld", data_len));
+ DBUG_PRINT("error",("data_len: %lu", data_len));
result= ((data_len < LOG_EVENT_MINIMAL_HEADER_LEN) ? LOG_READ_BOGUS :
LOG_READ_TOO_LARGE);
goto end;
@@ -1438,7 +1441,7 @@ failed my_b_read"));
*/
DBUG_RETURN(0);
}
- uint data_len = uint4korr(head + EVENT_LEN_OFFSET);
+ ulong data_len = uint4korr(head + EVENT_LEN_OFFSET);
char *buf= 0;
const char *error= 0;
Log_event *res= 0;
@@ -1447,7 +1450,8 @@ failed my_b_read"));
uint max_allowed_packet= thd ? slave_max_allowed_packet:~(uint)0;
#endif
- if (data_len > max_allowed_packet)
+ if (data_len > max<ulong>(max_allowed_packet,
+ opt_binlog_rows_event_max_size + MAX_LOG_EVENT_HEADER))
{
error = "Event too big";
goto err;
@@ -1481,7 +1485,7 @@ err:
{
DBUG_ASSERT(error != 0);
sql_print_error("Error in Log_event::read_log_event(): "
- "'%s', data_len: %d, event_type: %d",
+ "'%s', data_len: %lu, event_type: %d",
error,data_len,(uchar)(head[EVENT_TYPE_OFFSET]));
my_free(buf);
/*
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index 6503d110032..e26937441d1 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -513,8 +513,6 @@ bool is_materialization_applicable(THD *thd, Item_in_subselect *in_subs,
Subquery !contains {GROUP BY, ORDER BY [LIMIT],
aggregate functions}) && subquery predicate is not under "NOT IN"))
- (*) The subquery must be part of a SELECT or CREATE TABLE ... SELECT statement.
- The current condition also excludes multi-table update statements.
A note about prepared statements: we want the if-branch to be taken on
PREPARE and each EXECUTE. The rewrites are only done once, but we need
select_lex->sj_subselects list to be populated for every EXECUTE.
@@ -523,9 +521,7 @@ bool is_materialization_applicable(THD *thd, Item_in_subselect *in_subs,
if (optimizer_flag(thd, OPTIMIZER_SWITCH_MATERIALIZATION) && // 0
!child_select->is_part_of_union() && // 1
parent_unit->first_select()->leaf_tables.elements && // 2
- (thd->lex->sql_command == SQLCOM_SELECT || // *
- thd->lex->sql_command == SQLCOM_CREATE_TABLE) && // *
- child_select->outer_select()->leaf_tables.elements && // 2A
+ child_select->outer_select()->leaf_tables.elements && // 2A
subquery_types_allow_materialization(in_subs) &&
(in_subs->is_top_level_item() || //3
optimizer_flag(thd,
@@ -3894,7 +3890,6 @@ SJ_TMP_TABLE::create_sj_weedout_tmp_table(THD *thd)
/*
STEP 1: Get temporary table name
*/
- thd->inc_status_created_tmp_tables();
if (use_temp_pool && !(test_flags & TEST_KEEP_TMP_TABLES))
temp_pool_slot = bitmap_lock_set_next(&temp_pool);
diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc
index 756dafdf534..5a81db45551 100644
--- a/sql/rpl_parallel.cc
+++ b/sql/rpl_parallel.cc
@@ -688,7 +688,7 @@ handle_rpl_parallel_thread(void *arg)
}
DBUG_ASSERT(qev->typ==rpl_parallel_thread::queued_event::QUEUED_EVENT);
- thd->rgi_slave= group_rgi= rgi;
+ thd->rgi_slave= rgi;
gco= rgi->gco;
/* Handle a new event group, which will be initiated by a GTID event. */
if ((event_type= qev->ev->get_type_code()) == GTID_EVENT)
@@ -705,6 +705,21 @@ handle_rpl_parallel_thread(void *arg)
}
});
+ if(unlikely(thd->wait_for_commit_ptr) && group_rgi != NULL)
+ {
+ /*
+ This indicates that we get a new GTID event in the middle of
+ a not completed event group. This is corrupt binlog (the master
+ will never write such binlog), so it does not happen unless
+ someone tries to inject wrong crafted binlog, but let us still
+ try to handle it somewhat nicely.
+ */
+ group_rgi->cleanup_context(thd, true);
+ finish_event_group(rpt, group_rgi->gtid_sub_id,
+ group_rgi->parallel_entry, group_rgi);
+ rpt->loc_free_rgi(group_rgi);
+ }
+
thd->tx_isolation= (enum_tx_isolation)thd->variables.tx_isolation;
in_event_group= true;
/*
@@ -791,19 +806,6 @@ handle_rpl_parallel_thread(void *arg)
unlock_or_exit_cond(thd, &entry->LOCK_parallel_entry,
&did_enter_cond, &old_stage);
- if(thd->wait_for_commit_ptr)
- {
- /*
- This indicates that we get a new GTID event in the middle of
- a not completed event group. This is corrupt binlog (the master
- will never write such binlog), so it does not happen unless
- someone tries to inject wrong crafted binlog, but let us still
- try to handle it somewhat nicely.
- */
- rgi->cleanup_context(thd, true);
- thd->wait_for_commit_ptr->unregister_wait_for_prior_commit();
- thd->wait_for_commit_ptr->wakeup_subsequent_commits(rgi->worker_error);
- }
thd->wait_for_commit_ptr= &rgi->commit_orderer;
if (opt_gtid_ignore_duplicates)
@@ -841,6 +843,7 @@ handle_rpl_parallel_thread(void *arg)
}
}
+ group_rgi= rgi;
group_ending= is_group_ending(qev->ev, event_type);
if (group_ending && likely(!rgi->worker_error))
{
diff --git a/sql/slave.cc b/sql/slave.cc
index af441815169..2a852745470 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -372,6 +372,9 @@ int init_slave()
if (run_slave_init_thread())
return 1;
+ if (global_rpl_thread_pool.init(opt_slave_parallel_threads))
+ return 1;
+
/*
This is called when mysqld starts. Before client connections are
accepted. However bootstrap may conflict with us if it does START SLAVE.
@@ -405,9 +408,6 @@ int init_slave()
goto err;
}
- if (global_rpl_thread_pool.init(opt_slave_parallel_threads))
- return 1;
-
/*
If --slave-skip-errors=... was not used, the string value for the
system variable has not been set up yet. Do it now.
@@ -5722,6 +5722,18 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
}
break;
+#ifndef DBUG_OFF
+ case XID_EVENT:
+ DBUG_EXECUTE_IF("slave_discard_xid_for_gtid_0_x_1000",
+ {
+ /* Inject an event group that is missing its XID commit event. */
+ if (mi->last_queued_gtid.domain_id == 0 &&
+ mi->last_queued_gtid.seq_no == 1000)
+ goto skip_relay_logging;
+ });
+ /* Fall through to default case ... */
+#endif
+
default:
default_action:
DBUG_EXECUTE_IF("kill_slave_io_after_2_events",
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 1ee443cfb83..aaa12763cec 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -10079,7 +10079,6 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
List<LEX_USER> user_list;
bool result;
ACL_USER *au;
- char passwd_buff[SCRAMBLED_PASSWORD_CHAR_LENGTH+1];
Dummy_error_handler error_handler;
DBUG_ENTER("sp_grant_privileges");
@@ -10120,33 +10119,10 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
if(au)
{
- if (au->salt_len)
- {
- if (au->salt_len == SCRAMBLE_LENGTH)
- {
- make_password_from_salt(passwd_buff, au->salt);
- combo->auth.length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
- }
- else if (au->salt_len == SCRAMBLE_LENGTH_323)
- {
- make_password_from_salt_323(passwd_buff, (ulong *) au->salt);
- combo->auth.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
- }
- else
- {
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_PASSWD_LENGTH,
- ER(ER_PASSWD_LENGTH), SCRAMBLED_PASSWORD_CHAR_LENGTH);
- return TRUE;
- }
- combo->auth.str= passwd_buff;
- }
-
if (au->plugin.str != native_password_plugin_name.str &&
au->plugin.str != old_password_plugin_name.str)
- {
combo->plugin= au->plugin;
- combo->auth= au->auth_string;
- }
+ combo->auth= au->auth_string;
}
if (user_list.push_back(combo))
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index a5d7881707c..4d22f7f88d3 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1478,6 +1478,9 @@ unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
bool check_alias)
{
TABLE_LIST *dup;
+
+ table= table->find_table_for_update();
+
if (table->table && table->table->file->ht->db_type == DB_TYPE_MRG_MYISAM)
{
TABLE_LIST *child;
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 24814497600..475afa882f8 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -1,6 +1,6 @@
/*
- Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2009, 2013, Monty Program Ab.
+ Copyright (c) 2000, 2014, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2015, MariaDB
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
@@ -977,7 +977,7 @@ update_binlog:
if (!(query= (char*) thd->alloc(MAX_DROP_TABLE_Q_LEN)))
goto exit; /* not much else we can do */
- query_pos= query_data_start= strmov(query,"DROP TABLE ");
+ query_pos= query_data_start= strmov(query,"DROP TABLE IF EXISTS ");
query_end= query + MAX_DROP_TABLE_Q_LEN;
db_len= strlen(db);
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index e16aade6bcb..8fd9b0b2ada 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -922,9 +922,10 @@ multi_delete::initialize_tables(JOIN *join)
delete_while_scanning= 1;
for (walk= delete_tables; walk; walk= walk->next_local)
{
- tables_to_delete_from|= walk->table->map;
+ TABLE_LIST *tbl= walk->correspondent_table->find_table_for_update();
+ tables_to_delete_from|= tbl->table->map;
if (delete_while_scanning &&
- unique_table(thd, walk, join->tables_list, false))
+ unique_table(thd, tbl, join->tables_list, false))
{
/*
If the table we are going to delete from appears
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 5d896748d87..5bc83aefb98 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -516,6 +516,9 @@ bool mysql_derived_merge_for_insert(THD *thd, LEX *lex, TABLE_LIST *derived)
DBUG_RETURN(FALSE);
if (derived->is_materialized_derived())
DBUG_RETURN(mysql_derived_prepare(thd, lex, derived));
+ if ((thd->lex->sql_command == SQLCOM_UPDATE_MULTI ||
+ thd->lex->sql_command == SQLCOM_DELETE_MULTI))
+ DBUG_RETURN(FALSE);
if (!derived->is_multitable())
{
if (!derived->single_table_updatable())
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index be57be9b223..9c084555475 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2491,11 +2491,15 @@ mysql_execute_command(THD *thd)
according to slave filtering rules.
Returning success without producing any errors in this case.
*/
- DBUG_RETURN(0);
+ if (!thd->lex->create_info.if_exists())
+ DBUG_RETURN(0);
+ /*
+ DROP TRIGGER IF NOT EXISTS will return without an error later
+ after possibly writing the query to a binlog
+ */
}
-
- // force searching in slave.cc:tables_ok()
- all_tables->updating= 1;
+ else // force searching in slave.cc:tables_ok()
+ all_tables->updating= 1;
}
/*
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index de713d6aca0..610687ce8f1 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2000, 2013 Oracle and/or its affiliates.
- Copyright (c) 2009, 2013 Monty Program Ab.
+/* Copyright (c) 2000, 2014 Oracle and/or its affiliates.
+ Copyright (c) 2009, 2015 MariaDB
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
@@ -4983,7 +4983,18 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array, KEY_FIELD *key_field)
}
-#define FT_KEYPART (MAX_REF_PARTS+10)
+/*
+ A key part number that means we're using a fulltext scan.
+
+ In order not to confuse it with regular equalities, we need to pick
+ a number that's greater than MAX_REF_PARTS.
+
+ Hash Join code stores field->field_index in KEYUSE::keypart, so the
+ number needs to be bigger than MAX_FIELDS, also.
+
+ CAUTION: sql_test.cc has its own definition of FT_KEYPART.
+*/
+#define FT_KEYPART (MAX_FIELDS+10)
static bool
add_ft_keys(DYNAMIC_ARRAY *keyuse_array,
@@ -7477,8 +7488,12 @@ double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s,
else
fldno= table->key_info[key].key_part[keyparts-1].fieldnr - 1;
if (keyuse->val->const_item())
- {
- sel /= table->field[fldno]->cond_selectivity;
+ {
+ if (table->field[fldno]->cond_selectivity > 0)
+ {
+ sel /= table->field[fldno]->cond_selectivity;
+ set_if_smaller(sel, 1.0);
+ }
/*
TODO: we could do better here:
1. cond_selectivity might be =1 (the default) because quick
@@ -7532,7 +7547,10 @@ double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s,
if (!(next_field->table->map & rem_tables) && next_field->table != table)
{
if (field->cond_selectivity > 0)
+ {
sel/= field->cond_selectivity;
+ set_if_smaller(sel, 1.0);
+ }
break;
}
}
@@ -8721,7 +8739,8 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab,
{
Field *field= table->field[keyuse->keypart];
uint fieldnr= keyuse->keypart+1;
- table->create_key_part_by_field(keyinfo, key_part_info, field, fieldnr);
+ table->create_key_part_by_field(key_part_info, field, fieldnr);
+ keyinfo->key_length += key_part_info->store_length;
key_part_info++;
}
}
@@ -15878,7 +15897,6 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
(int) distinct, (int) save_sum_fields,
(ulong) rows_limit, MY_TEST(group)));
- thd->inc_status_created_tmp_tables();
thd->query_plan_flags|= QPLAN_TMP_TABLE;
if (use_temp_pool && !(test_flags & TEST_KEEP_TMP_TABLES))
@@ -16833,14 +16851,19 @@ bool open_tmp_table(TABLE *table)
HA_OPEN_TMP_TABLE |
HA_OPEN_INTERNAL_TABLE)))
{
- table->file->print_error(error,MYF(0)); /* purecov: inspected */
- table->db_stat=0;
- return(1);
+ table->file->print_error(error, MYF(0)); /* purecov: inspected */
+ table->db_stat= 0;
+ return 1;
}
table->db_stat= HA_OPEN_KEYFILE+HA_OPEN_RNDFILE;
- (void) table->file->extra(HA_EXTRA_QUICK); /* Faster */
- table->created= TRUE;
- return(0);
+ (void) table->file->extra(HA_EXTRA_QUICK); /* Faster */
+ if (!table->created)
+ {
+ table->created= TRUE;
+ table->in_use->inc_status_created_tmp_tables();
+ }
+
+ return 0;
}
@@ -16898,7 +16921,7 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo,
goto err;
bzero(seg, sizeof(*seg) * keyinfo->user_defined_key_parts);
- if (keyinfo->key_length >= table->file->max_key_length() ||
+ if (keyinfo->key_length > table->file->max_key_length() ||
keyinfo->user_defined_key_parts > table->file->max_key_parts() ||
share->uniques)
{
@@ -17040,8 +17063,10 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo,
}
table->in_use->inc_status_created_tmp_disk_tables();
+ table->in_use->inc_status_created_tmp_tables();
table->in_use->query_plan_flags|= QPLAN_TMP_DISK;
share->db_record_offset= 1;
+ table->created= TRUE;
DBUG_RETURN(0);
err:
DBUG_RETURN(1);
@@ -17101,7 +17126,7 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo,
goto err;
bzero(seg, sizeof(*seg) * keyinfo->user_defined_key_parts);
- if (keyinfo->key_length >= table->file->max_key_length() ||
+ if (keyinfo->key_length > table->file->max_key_length() ||
keyinfo->user_defined_key_parts > table->file->max_key_parts() ||
share->uniques)
{
@@ -17186,6 +17211,7 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo,
goto err;
}
table->in_use->inc_status_created_tmp_disk_tables();
+ table->in_use->inc_status_created_tmp_tables();
table->in_use->query_plan_flags|= QPLAN_TMP_DISK;
share->db_record_offset= 1;
table->created= TRUE;
diff --git a/sql/sql_select.h b/sql/sql_select.h
index a50ed130df8..fb42b6ba08e 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -1809,10 +1809,6 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
bool table_cant_handle_bit_fields,
bool make_copy_field,
uint convert_blob_length);
-bool create_internal_tmp_table(TABLE *table, KEY *keyinfo,
- TMP_ENGINE_COLUMNDEF *start_recinfo,
- TMP_ENGINE_COLUMNDEF **recinfo,
- ulonglong options, my_bool big_tables);
/*
General routine to change field->ptr of a NULL-terminated array of Field
diff --git a/sql/sql_test.cc b/sql/sql_test.cc
index cad2bf4ba56..ec65bd037b9 100644
--- a/sql/sql_test.cc
+++ b/sql/sql_test.cc
@@ -222,7 +222,7 @@ TEST_join(JOIN *join)
}
-#define FT_KEYPART (MAX_REF_PARTS+10)
+#define FT_KEYPART (MAX_FIELDS+10)
void print_keyuse(KEYUSE *keyuse)
{
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index ae6ba56c1e7..dbfe501be81 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -13544,7 +13544,12 @@ literal:
| UNDERSCORE_CHARSET hex_or_bin_String
{
Item_string_with_introducer *item_str;
- item_str= new (thd->mem_root) Item_string_with_introducer($2, $1);
+ /*
+ Pass NULL as name. Name will be set in the "select_item" rule and
+ will include the introducer and the original hex/bin notation.
+ */
+ item_str= new (thd->mem_root)
+ Item_string_with_introducer(NULL, $2->ptr(), $2->length(), $1);
if (!item_str || !item_str->check_well_formed_result(true))
MYSQL_YYABORT;
diff --git a/sql/structs.h b/sql/structs.h
index 9e9d7f9045e..de062f4a2ad 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -77,6 +77,7 @@ typedef struct st_key_part_info { /* Info about a key part */
*/
uint16 store_length;
uint16 key_type;
+ /* Fieldnr begins counting from 1 */
uint16 fieldnr; /* Fieldnum in UNIREG */
uint16 key_part_flag; /* 0 or HA_REVERSE_SORT */
uint8 type;
diff --git a/sql/table.cc b/sql/table.cc
index 9b6b64b93df..33695e730b0 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
- Copyright (c) 2008, 2014, SkySQL Ab.
+/* Copyright (c) 2000, 2014, Oracle and/or its affiliates.
+ Copyright (c) 2008, 2015, MariaDB
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
@@ -2946,7 +2946,9 @@ partititon_err:
outparam->no_replicate= FALSE;
}
- thd->status_var.opened_tables++;
+ /* Increment the opened_tables counter, only when open flags set. */
+ if (db_stat)
+ thd->status_var.opened_tables++;
thd->lex->context_analysis_only= save_context_analysis_only;
DBUG_RETURN (OPEN_FRM_OK);
@@ -6096,16 +6098,19 @@ bool TABLE::alloc_keys(uint key_count)
}
-/*
- Given a field, fill key_part_info
- @param keyinfo Key to where key part is added (we will
- only adjust key_length there)
- @param field IN Table field for which key part is needed
- @param key_part_info OUT key part structure to be filled.
- @param fieldnr Field's number.
+/**
+ @brief
+ Populate a KEY_PART_INFO structure with the data related to a field entry.
+
+ @param key_part_info The structure to fill.
+ @param field The field entry that represents the key part.
+ @param fleldnr The number of the field, count starting from 1.
+
+ TODO: This method does not make use of any table specific fields. It
+ could be refactored to act as a constructor for KEY_PART_INFO instead.
*/
-void TABLE::create_key_part_by_field(KEY *keyinfo,
- KEY_PART_INFO *key_part_info,
+
+void TABLE::create_key_part_by_field(KEY_PART_INFO *key_part_info,
Field *field, uint fieldnr)
{
DBUG_ASSERT(field->field_index + 1 == (int)fieldnr);
@@ -6115,8 +6120,11 @@ void TABLE::create_key_part_by_field(KEY *keyinfo,
key_part_info->field= field;
key_part_info->fieldnr= fieldnr;
key_part_info->offset= field->offset(record[0]);
- key_part_info->length= (uint16) field->pack_length();
- keyinfo->key_length+= key_part_info->length;
+ /*
+ field->key_length() accounts for the raw length of the field, excluding
+ any metadata such as length of field or the NULL flag.
+ */
+ key_part_info->length= (uint16) field->key_length();
key_part_info->key_part_flag= 0;
/* TODO:
The below method of computing the key format length of the
@@ -6128,17 +6136,20 @@ void TABLE::create_key_part_by_field(KEY *keyinfo,
*/
key_part_info->store_length= key_part_info->length;
+ /*
+ The total store length of the key part is the raw length of the field +
+ any metadata information, such as its length for strings and/or the null
+ flag.
+ */
if (field->real_maybe_null())
{
key_part_info->store_length+= HA_KEY_NULL_LENGTH;
- keyinfo->key_length+= HA_KEY_NULL_LENGTH;
}
if (field->type() == MYSQL_TYPE_BLOB ||
field->type() == MYSQL_TYPE_GEOMETRY ||
field->real_type() == MYSQL_TYPE_VARCHAR)
{
key_part_info->store_length+= HA_KEY_BLOB_LENGTH;
- keyinfo->key_length+= HA_KEY_BLOB_LENGTH; // ???
key_part_info->key_part_flag|=
field->type() == MYSQL_TYPE_BLOB ? HA_BLOB_PART: HA_VAR_LENGTH_PART;
}
@@ -6264,7 +6275,8 @@ bool TABLE::add_tmp_key(uint key, uint key_parts,
if (key_start)
(*reg_field)->key_start.set_bit(key);
(*reg_field)->part_of_key.set_bit(key);
- create_key_part_by_field(keyinfo, key_part_info, *reg_field, fld_idx+1);
+ create_key_part_by_field(key_part_info, *reg_field, fld_idx+1);
+ keyinfo->key_length += key_part_info->store_length;
(*reg_field)->flags|= PART_KEY_FLAG;
key_start= FALSE;
key_part_info++;
diff --git a/sql/table.h b/sql/table.h
index b020223854b..ba829167ab9 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -1323,7 +1323,7 @@ public:
bool add_tmp_key(uint key, uint key_parts,
uint (*next_field_no) (uchar *), uchar *arg,
bool unique);
- void create_key_part_by_field(KEY *keyinfo, KEY_PART_INFO *key_part_info,
+ void create_key_part_by_field(KEY_PART_INFO *key_part_info,
Field *field, uint fieldnr);
void use_index(int key_to_save);
void set_table_map(table_map map_arg, uint tablenr_arg)
@@ -2074,6 +2074,24 @@ struct TABLE_LIST
TABLE_LIST *find_underlying_table(TABLE *table);
TABLE_LIST *first_leaf_for_name_resolution();
TABLE_LIST *last_leaf_for_name_resolution();
+ /**
+ @brief
+ Find the bottom in the chain of embedded table VIEWs.
+
+ @detail
+ This is used for single-table UPDATE/DELETE when they are modifying a
+ single-table VIEW.
+ */
+ TABLE_LIST *find_table_for_update()
+ {
+ TABLE_LIST *tbl= this;
+ while(!tbl->is_multitable() && tbl->single_table_updatable() &&
+ tbl->merge_underlying_list)
+ {
+ tbl= tbl->merge_underlying_list;
+ }
+ return tbl;
+ }
TABLE *get_real_join_table();
bool is_leaf_for_name_resolution();
inline TABLE_LIST *top_table()
diff --git a/sql/udf_example.c b/sql/udf_example.c
index 36a5eafb704..a48801d1c4a 100644
--- a/sql/udf_example.c
+++ b/sql/udf_example.c
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2000, 2010, Oracle and/or its affiliates.
+ Copyright (c) 2000, 2014, 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
@@ -296,9 +296,12 @@ char *metaphon(UDF_INIT *initid __attribute__((unused)),
if (!word) /* Null argument */
{
+ /* The length is expected to be zero when the argument is NULL. */
+ assert(args->lengths[0] == 0);
*is_null=1;
return 0;
}
+
w_end=word+args->lengths[0];
org_result=result;