diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item.cc | 1 | ||||
-rw-r--r-- | sql/key.cc | 24 | ||||
-rw-r--r-- | sql/mysql_priv.h | 3 | ||||
-rw-r--r-- | sql/opt_range.cc | 16 | ||||
-rw-r--r-- | sql/opt_range.h | 9 | ||||
-rw-r--r-- | sql/sp.cc | 39 | ||||
-rw-r--r-- | sql/sql_acl.cc | 1 | ||||
-rw-r--r-- | sql/sql_select.cc | 43 | ||||
-rw-r--r-- | sql/sql_table.cc | 5 | ||||
-rw-r--r-- | sql/sql_trigger.cc | 32 | ||||
-rw-r--r-- | sql/sql_trigger.h | 7 | ||||
-rw-r--r-- | sql/sql_update.cc | 16 |
12 files changed, 112 insertions, 84 deletions
diff --git a/sql/item.cc b/sql/item.cc index a0eef7a19e9..d56ca95093b 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3745,6 +3745,7 @@ void Item_field::cleanup() I.e. we can drop 'field'. */ field= result_field= 0; + null_value= FALSE; DBUG_VOID_RETURN; } diff --git a/sql/key.cc b/sql/key.cc index 75161e4f616..5e658312352 100644 --- a/sql/key.cc +++ b/sql/key.cc @@ -18,6 +18,7 @@ /* Functions to handle keys and fields in forms */ #include "mysql_priv.h" +#include "sql_trigger.h" /* ** Search after with key field is. If no key starts with field test @@ -342,12 +343,24 @@ void key_unpack(String *to,TABLE *table,uint idx) /* - Return 1 if any field in a list is part of key or the key uses a field - that is automaticly updated (like a timestamp) + Check if key uses field that is listed in passed field list or is + automatically updated (like a timestamp) or can be updated by before + update trigger defined on the table. + + SYNOPSIS + is_key_used() + table TABLE object with which keys and fields are associated. + idx Key to be checked. + fields List of fields to be checked. + + RETURN VALUE + TRUE Key uses field which meets one the above conditions + FALSE Otherwise */ -bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields) +bool is_key_used(TABLE *table, uint idx, List<Item> &fields) { + Table_triggers_list *triggers= table->triggers; List_iterator_fast<Item> f(fields); KEY_PART_INFO *key_part,*key_part_end; for (key_part=table->key_info[idx].key_part,key_part_end=key_part+ @@ -366,6 +379,9 @@ bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields) if (key_part->field->eq(field->field)) return 1; } + if (triggers && + triggers->is_updated_in_before_update_triggers(key_part->field)) + return 1; } /* @@ -374,7 +390,7 @@ bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields) */ if (idx != table->s->primary_key && table->s->primary_key < MAX_KEY && (table->file->table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX)) - return check_if_key_used(table, table->s->primary_key, fields); + return is_key_used(table, table->s->primary_key, fields); return 0; } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index ff04022b110..c6cc6519d78 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1114,7 +1114,7 @@ void key_restore(byte *to_record, byte *from_key, KEY *key_info, uint key_length); bool key_cmp_if_same(TABLE *form,const byte *key,uint index,uint key_length); void key_unpack(String *to,TABLE *form,uint index); -bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields); +bool is_key_used(TABLE *table, uint idx, List<Item> &fields); int key_cmp(KEY_PART_INFO *key_part, const byte *key, uint key_length); bool init_errmessage(void); @@ -1229,7 +1229,6 @@ extern my_bool opt_log_queries_not_using_indexes; extern bool opt_disable_networking, opt_skip_show_db; extern my_bool opt_character_set_client_handshake; extern bool volatile abort_loop, shutdown_in_progress, grant_option; -extern bool mysql_proc_table_exists; extern uint volatile thread_count, thread_running, global_read_lock; extern my_bool opt_sql_bin_update, opt_safe_user_create, opt_no_mix_types; extern my_bool opt_safe_show_db, opt_local_infile; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 79cfbc72fe7..959d7b7e381 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -6127,42 +6127,42 @@ static bool null_part_in_key(KEY_PART *key_part, const char *key, uint length) } -bool QUICK_SELECT_I::check_if_keys_used(List<Item> *fields) +bool QUICK_SELECT_I::is_keys_used(List<Item> *fields) { - return check_if_key_used(head, index, *fields); + return is_key_used(head, index, *fields); } -bool QUICK_INDEX_MERGE_SELECT::check_if_keys_used(List<Item> *fields) +bool QUICK_INDEX_MERGE_SELECT::is_keys_used(List<Item> *fields) { QUICK_RANGE_SELECT *quick; List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); while ((quick= it++)) { - if (check_if_key_used(head, quick->index, *fields)) + if (is_key_used(head, quick->index, *fields)) return 1; } return 0; } -bool QUICK_ROR_INTERSECT_SELECT::check_if_keys_used(List<Item> *fields) +bool QUICK_ROR_INTERSECT_SELECT::is_keys_used(List<Item> *fields) { QUICK_RANGE_SELECT *quick; List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects); while ((quick= it++)) { - if (check_if_key_used(head, quick->index, *fields)) + if (is_key_used(head, quick->index, *fields)) return 1; } return 0; } -bool QUICK_ROR_UNION_SELECT::check_if_keys_used(List<Item> *fields) +bool QUICK_ROR_UNION_SELECT::is_keys_used(List<Item> *fields) { QUICK_SELECT_I *quick; List_iterator_fast<QUICK_SELECT_I> it(quick_selects); while ((quick= it++)) { - if (quick->check_if_keys_used(fields)) + if (quick->is_keys_used(fields)) return 1; } return 0; diff --git a/sql/opt_range.h b/sql/opt_range.h index 9474f2d469f..40a95beb894 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -225,8 +225,9 @@ public: Return 1 if any index used by this quick select a) uses field that is listed in passed field list or b) is automatically updated (like a timestamp) + c) can be updated by one of before update triggers defined on table */ - virtual bool check_if_keys_used(List<Item> *fields); + virtual bool is_keys_used(List<Item> *fields); /* rowid of last row retrieved by this quick select. This is used only when @@ -423,7 +424,7 @@ public: int get_type() { return QS_TYPE_INDEX_MERGE; } void add_keys_and_lengths(String *key_names, String *used_lengths); void add_info_string(String *str); - bool check_if_keys_used(List<Item> *fields); + bool is_keys_used(List<Item> *fields); #ifndef DBUG_OFF void dbug_dump(int indent, bool verbose); #endif @@ -482,7 +483,7 @@ public: int get_type() { return QS_TYPE_ROR_INTERSECT; } void add_keys_and_lengths(String *key_names, String *used_lengths); void add_info_string(String *str); - bool check_if_keys_used(List<Item> *fields); + bool is_keys_used(List<Item> *fields); #ifndef DBUG_OFF void dbug_dump(int indent, bool verbose); #endif @@ -536,7 +537,7 @@ public: int get_type() { return QS_TYPE_ROR_UNION; } void add_keys_and_lengths(String *key_names, String *used_lengths); void add_info_string(String *str); - bool check_if_keys_used(List<Item> *fields); + bool is_keys_used(List<Item> *fields); #ifndef DBUG_OFF void dbug_dump(int indent, bool verbose); #endif diff --git a/sql/sp.cc b/sql/sp.cc index fc72822c15e..49dbed79fe5 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -66,8 +66,6 @@ enum MYSQL_PROC_FIELD_COUNT }; -bool mysql_proc_table_exists= 1; - /* Tells what SP_DEFAULT_ACCESS should be mapped to */ #define SP_DEFAULT_ACCESS_MAPPING SP_CONTAINS_SQL @@ -119,13 +117,6 @@ TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup) bool not_used; DBUG_ENTER("open_proc_table"); - /* - Speed up things if mysql.proc doesn't exists. mysql_proc_table_exists - is set when we create or read stored procedure or on flush privileges. - */ - if (!mysql_proc_table_exists) - DBUG_RETURN(0); - thd->reset_n_backup_open_tables_state(backup); bzero((char*) &tables, sizeof(tables)); @@ -135,7 +126,6 @@ TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup) MYSQL_LOCK_IGNORE_FLUSH))) { thd->restore_backup_open_tables_state(backup); - mysql_proc_table_exists= 0; DBUG_RETURN(0); } @@ -184,15 +174,6 @@ static TABLE *open_proc_table_for_update(THD *thd) table= open_ltable(thd, &tables, TL_WRITE); - /* - Under explicit LOCK TABLES or in prelocked mode we should not - say that mysql.proc table does not exist if we are unable to - open and lock it for writing since this condition may be - transient. - */ - if (!(thd->locked_tables || thd->prelocked_mode) || table) - mysql_proc_table_exists= test(table); - DBUG_RETURN(table); } @@ -1610,14 +1591,6 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex, case SP_KEY_NOT_FOUND: ret= SP_OK; break; - case SP_OPEN_TABLE_FAILED: - /* - Force it to attempt opening it again on subsequent calls; - otherwise we will get one error message the first time, and - then ER_SP_PROC_TABLE_CORRUPT (below) on subsequent tries. - */ - mysql_proc_table_exists= 1; - /* Fall through */ default: /* Any error when loading an existing routine is either some problem @@ -1633,7 +1606,17 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex, */ if (!thd->net.report_error) { - char n[NAME_LEN*2+2]; + /* + SP allows full NAME_LEN chars thus he have to allocate enough + size in bytes. Otherwise there is stack overrun could happen + if multibyte sequence is `name`. `db` is still safe because the + rest of the server checks agains NAME_LEN bytes and not chars. + Hence, the overrun happens only if the name is in length > 32 and + uses multibyte (cyrillic, greek, etc.) + + !! Change 3 with SYSTEM_CHARSET_MBMAXLEN when it's defined. + */ + char n[NAME_LEN*3*2+2]; /* m_qname.str is not always \0 terminated */ memcpy(n, name.m_qname.str, name.m_qname.length); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index e6170cae994..50cee6eeca4 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -202,7 +202,6 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) DBUG_ENTER("acl_load"); grant_version++; /* Privileges updated */ - mysql_proc_table_exists= 1; // Assume mysql.proc exists acl_cache->clear(1); // Clear locked hostname cache diff --git a/sql/sql_select.cc b/sql/sql_select.cc index e0deeb7d65e..6d17faf8509 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1134,17 +1134,28 @@ JOIN::optimize() tmp_table_param.hidden_field_count= (all_fields.elements - fields_list.elements); + ORDER *tmp_group= ((!simple_group && !procedure && + !(test_flags & TEST_NO_KEY_GROUP)) ? group_list : + (ORDER*) 0); + /* + Pushing LIMIT to the temporary table creation is not applicable + when there is ORDER BY or GROUP BY or there is no GROUP BY, but + there are aggregate functions, because in all these cases we need + all result rows. + */ + ha_rows tmp_rows_limit= ((order == 0 || skip_sort_order || + test(select_options & OPTION_BUFFER_RESULT)) && + !tmp_group && + !thd->lex->current_select->with_sum_func) ? + select_limit : HA_POS_ERROR; + if (!(exec_tmp_table1 = create_tmp_table(thd, &tmp_table_param, all_fields, - ((!simple_group && !procedure && - !(test_flags & TEST_NO_KEY_GROUP)) ? - group_list : (ORDER*) 0), + tmp_group, group_list ? 0 : select_distinct, group_list && simple_group, select_options, - (order == 0 || skip_sort_order || - test(select_options & OPTION_BUFFER_RESULT)) ? - select_limit : HA_POS_ERROR, + tmp_rows_limit, (char *) ""))) DBUG_RETURN(1); @@ -9104,6 +9115,13 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, thd->variables.max_heap_table_size) : thd->variables.tmp_table_size)/ table->s->reclength); set_if_bigger(table->s->max_rows,1); // For dummy start options + /* + Push the LIMIT clause to the temporary table creation, so that we + materialize only up to 'rows_limit' records instead of all result records. + */ + set_if_smaller(table->s->max_rows, rows_limit); + param->end_write_records= rows_limit; + keyinfo= param->keyinfo; if (group) @@ -9233,19 +9251,6 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, } } - /* - Push the LIMIT clause to the temporary table creation, so that we - materialize only up to 'rows_limit' records instead of all result records. - This optimization is not applicable when there is GROUP BY or there is - no GROUP BY, but there are aggregate functions, because both must be - computed for all result rows. - */ - if (!group && !thd->lex->current_select->with_sum_func) - { - set_if_smaller(table->s->max_rows, rows_limit); - param->end_write_records= rows_limit; - } - if (thd->is_fatal_error) // If end of memory goto err; /* purecov: inspected */ table->s->db_record_offset= 1; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index a340c5ffc98..1c5be098ae0 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -224,7 +224,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, DBUG_ENTER("mysql_rm_table_part2"); - if (lock_table_names(thd, tables)) + if (!drop_temporary && lock_table_names(thd, tables)) DBUG_RETURN(1); /* Don't give warnings for not found errors, as we already generate notes */ @@ -334,7 +334,8 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, } } - unlock_table_names(thd, tables, (TABLE_LIST*) 0); + if (!drop_temporary) + unlock_table_names(thd, tables, (TABLE_LIST*) 0); thd->no_warnings_for_error= 0; DBUG_RETURN(error); } diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 6bb50d602c3..c0c9c34cbeb 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -1548,6 +1548,38 @@ void Table_triggers_list::mark_fields_used(THD *thd, trg_event_type event) /* + Check if field of subject table can be changed in before update trigger. + + SYNOPSIS + is_updated_in_before_update_triggers() + field Field object for field to be checked + + NOTE + Field passed to this function should be bound to the same + TABLE object as Table_triggers_list. + + RETURN VALUE + TRUE Field is changed + FALSE Otherwise +*/ + +bool Table_triggers_list::is_updated_in_before_update_triggers(Field *fld) +{ + Item_trigger_field *trg_fld; + for (trg_fld= trigger_fields[TRG_EVENT_UPDATE][TRG_ACTION_BEFORE]; + trg_fld != 0; + trg_fld= trg_fld->next_trg_field) + { + if (trg_fld->get_settable_routine_parameter() && + trg_fld->field_idx != (uint)-1 && + table->field[trg_fld->field_idx]->eq(fld)) + return TRUE; + } + return FALSE; +} + + +/* Trigger BUG#14090 compatibility hook SYNOPSIS diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h index 521905a2c56..7e0fadfa677 100644 --- a/sql/sql_trigger.h +++ b/sql/sql_trigger.h @@ -116,15 +116,12 @@ public: bodies[TRG_EVENT_DELETE][TRG_ACTION_AFTER]); } - bool has_before_update_triggers() - { - return test(bodies[TRG_EVENT_UPDATE][TRG_ACTION_BEFORE]); - } - void set_table(TABLE *new_table); void mark_fields_used(THD *thd, trg_event_type event); + bool is_updated_in_before_update_triggers(Field *fld); + friend class Item_trigger_field; friend int sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex, TABLE_LIST *table); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 50914fd3408..a4e05a96f9b 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -274,7 +274,7 @@ int mysql_update(THD *thd, { used_index= select->quick->index; used_key_is_modified= (!select->quick->unique_key_range() && - select->quick->check_if_keys_used(&fields)); + select->quick->is_keys_used(&fields)); } else { @@ -282,7 +282,7 @@ int mysql_update(THD *thd, if (used_index == MAX_KEY) // no index for sort order used_index= table->file->key_used_on_scan; if (used_index != MAX_KEY) - used_key_is_modified= check_if_key_used(table, used_index, fields); + used_key_is_modified= is_key_used(table, used_index, fields); } if (used_key_is_modified || order) @@ -1189,21 +1189,15 @@ static bool safe_update_on_fly(JOIN_TAB *join_tab, List<Item> *fields) return TRUE; // At most one matching row case JT_REF: case JT_REF_OR_NULL: - return !check_if_key_used(table, join_tab->ref.key, *fields) && - !(table->triggers && - table->triggers->has_before_update_triggers()); + return !is_key_used(table, join_tab->ref.key, *fields); case JT_ALL: /* If range search on index */ if (join_tab->quick) - return !join_tab->quick->check_if_keys_used(fields) && - !(table->triggers && - table->triggers->has_before_update_triggers()); + return !join_tab->quick->is_keys_used(fields); /* If scanning in clustered key */ if ((table->file->table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) && table->s->primary_key < MAX_KEY) - return !check_if_key_used(table, table->s->primary_key, *fields) && - !(table->triggers && - table->triggers->has_before_update_triggers()); + return !is_key_used(table, table->s->primary_key, *fields); return TRUE; default: break; // Avoid compler warning |