diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/CMakeLists.txt | 8 | ||||
-rw-r--r-- | sql/handler.cc | 8 | ||||
-rw-r--r-- | sql/item.h | 5 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 5 | ||||
-rw-r--r-- | sql/item_func.cc | 8 | ||||
-rw-r--r-- | sql/item_geofunc.cc | 8 | ||||
-rw-r--r-- | sql/log.cc | 63 | ||||
-rw-r--r-- | sql/log_event.cc | 14 | ||||
-rw-r--r-- | sql/opt_subselect.cc | 7 | ||||
-rw-r--r-- | sql/rpl_parallel.cc | 31 | ||||
-rw-r--r-- | sql/slave.cc | 18 | ||||
-rw-r--r-- | sql/sql_acl.cc | 26 | ||||
-rw-r--r-- | sql/sql_base.cc | 3 | ||||
-rw-r--r-- | sql/sql_db.cc | 6 | ||||
-rw-r--r-- | sql/sql_delete.cc | 5 | ||||
-rw-r--r-- | sql/sql_derived.cc | 3 | ||||
-rw-r--r-- | sql/sql_parse.cc | 12 | ||||
-rw-r--r-- | sql/sql_select.cc | 56 | ||||
-rw-r--r-- | sql/sql_select.h | 4 | ||||
-rw-r--r-- | sql/sql_test.cc | 2 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 7 | ||||
-rw-r--r-- | sql/structs.h | 1 | ||||
-rw-r--r-- | sql/table.cc | 46 | ||||
-rw-r--r-- | sql/table.h | 20 | ||||
-rw-r--r-- | sql/udf_example.c | 5 |
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; |