summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/item.cc1
-rw-r--r--sql/key.cc24
-rw-r--r--sql/mysql_priv.h3
-rw-r--r--sql/opt_range.cc16
-rw-r--r--sql/opt_range.h9
-rw-r--r--sql/sp.cc39
-rw-r--r--sql/sql_acl.cc1
-rw-r--r--sql/sql_select.cc43
-rw-r--r--sql/sql_table.cc5
-rw-r--r--sql/sql_trigger.cc32
-rw-r--r--sql/sql_trigger.h7
-rw-r--r--sql/sql_update.cc16
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