diff options
Diffstat (limited to 'sql')
58 files changed, 480 insertions, 299 deletions
diff --git a/sql/filesort.cc b/sql/filesort.cc index 4183c28f05b..34cd11cbcf3 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. - Copyright (c) 2009, 2012, Monty Program Ab. +/* Copyright (c) 2000, 2014, Oracle and/or its affiliates. + Copyright (c) 2009, 2014, Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -903,8 +903,8 @@ static void make_sortkey(register SORTPARAM *param, if (maybe_null) *to++=1; - /* All item->str() to use some extra byte for end null.. */ - String tmp((char*) to,sort_field->length+4,cs); + char *tmp_buffer= param->tmp_buffer ? param->tmp_buffer : (char*)to; + String tmp(tmp_buffer, param->sort_length, cs); String *res= item->str_result(&tmp); if (!res) { @@ -929,17 +929,9 @@ static void make_sortkey(register SORTPARAM *param, length= res->length(); if (sort_field->need_strxnfrm) { - char *from=(char*) res->ptr(); uint tmp_length __attribute__((unused)); - if ((uchar*) from == to) - { - DBUG_ASSERT(sort_field->length >= length); - set_if_smaller(length,sort_field->length); - memcpy(param->tmp_buffer,from,length); - from=param->tmp_buffer; - } - tmp_length= my_strnxfrm(cs,to,sort_field->length, - (uchar*) from, length); + tmp_length= my_strnxfrm(cs, to ,sort_field->length, + (uchar*) res->ptr(), length); DBUG_ASSERT(tmp_length == sort_field->length); } else @@ -960,6 +952,7 @@ static void make_sortkey(register SORTPARAM *param, store_length(to + sort_field_length, length, sort_field->suffix_length); } + /* apply cs->sort_order for case-insensitive comparison if needed */ my_strnxfrm(cs,(uchar*)to,length,(const uchar*)res->ptr(),length); cs->cset->fill(cs, (char *)to+length,diff,fill_char); } diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 25bb6f44284..a4409c4da80 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -80,7 +80,8 @@ static handler *partition_create_handler(handlerton *hton, static uint partition_flags(); static uint alter_table_flags(uint flags); -extern "C" int cmp_key_then_part_id(void *key_p, uchar *ref1, uchar *ref2); +extern "C" int cmp_key_part_id(void *key_p, uchar *ref1, uchar *ref2); +extern "C" int cmp_key_rowid_part_id(void *ptr, uchar *ref1, uchar *ref2); static int partition_initialize(void *p) { @@ -4520,7 +4521,10 @@ bool ha_partition::init_record_priority_queue() uint alloc_len; uint used_parts= bitmap_bits_set(&m_part_info->used_partitions); /* Allocate record buffer for each used partition. */ - alloc_len= used_parts * (m_rec_length + PARTITION_BYTES_IN_POS); + m_priority_queue_rec_len= m_rec_length + PARTITION_BYTES_IN_POS; + if (!m_using_extended_keys) + m_priority_queue_rec_len += m_file[0]->ref_length; + alloc_len= used_parts * m_priority_queue_rec_len; /* Allocate a key for temporary use when setting up the scan. */ alloc_len+= table_share->max_key_length; @@ -4542,13 +4546,25 @@ bool ha_partition::init_record_priority_queue() { DBUG_PRINT("info", ("init rec-buf for part %u", i)); int2store(ptr, i); - ptr+= m_rec_length + PARTITION_BYTES_IN_POS; + ptr+= m_priority_queue_rec_len; } } while (++i < m_tot_parts); m_start_key.key= (const uchar*)ptr; + /* Initialize priority queue, initialized to reading forward. */ - if (init_queue(&m_queue, used_parts, 0, - 0, cmp_key_then_part_id, (void*)m_curr_key_info, 0, 0)) + int (*cmp_func)(void *, uchar *, uchar *); + void *cmp_arg; + if (!m_using_extended_keys) + { + cmp_func= cmp_key_rowid_part_id; + cmp_arg= (void*)this; + } + else + { + cmp_func= cmp_key_part_id; + cmp_arg= (void*)m_curr_key_info; + } + if (init_queue(&m_queue, used_parts, 0, 0, cmp_func, cmp_arg, 0, 0)) { my_free(m_ordered_rec_buffer); m_ordered_rec_buffer= NULL; @@ -4615,9 +4631,13 @@ int ha_partition::index_init(uint inx, bool sorted) DBUG_PRINT("info", ("Clustered pk, using pk as secondary cmp")); m_curr_key_info[1]= table->key_info+table->s->primary_key; m_curr_key_info[2]= NULL; + m_using_extended_keys= TRUE; } else + { m_curr_key_info[1]= NULL; + m_using_extended_keys= FALSE; + } if (init_record_priority_queue()) DBUG_RETURN(HA_ERR_OUT_OF_MEM); @@ -4744,36 +4764,12 @@ int ha_partition::index_read_map(uchar *buf, const uchar *key, } -/* - @brief - Provide ordering by (key_value, partition_id). - - @detail - Ordering by partition id is required so that key scans on key=const - return rows in rowid order (this is required for some variants of - index_merge to work). - - In ha_partition, rowid is a (partition_id, underlying_table_rowid). - handle_ordered_index_scan must return rows ordered by (key, rowid). - - If two rows have the same key value and come from different partitions, - it is sufficient to return them in the order of their partition_id. -*/ - -extern "C" int cmp_key_then_part_id(void *key_p, uchar *ref1, uchar *ref2) +/* Compare two part_no partition numbers */ +static int cmp_part_ids(uchar *ref1, uchar *ref2) { - my_ptrdiff_t diff1, diff2; - int res; - - if ((res= key_rec_cmp(key_p, ref1 + PARTITION_BYTES_IN_POS, - ref2 + PARTITION_BYTES_IN_POS))) - { - return res; - } - /* The following was taken from ha_partition::cmp_ref */ - diff1= ref2[1] - ref1[1]; - diff2= ref2[0] - ref1[0]; + my_ptrdiff_t diff1= ref2[1] - ref1[1]; + my_ptrdiff_t diff2= ref2[0] - ref1[0]; if (!diff1 && !diff2) return 0; @@ -4790,6 +4786,45 @@ extern "C" int cmp_key_then_part_id(void *key_p, uchar *ref1, uchar *ref2) } +/* + @brief + Provide ordering by (key_value, part_no). +*/ + +extern "C" int cmp_key_part_id(void *key_p, uchar *ref1, uchar *ref2) +{ + int res; + if ((res= key_rec_cmp(key_p, ref1 + PARTITION_BYTES_IN_POS, + ref2 + PARTITION_BYTES_IN_POS))) + { + return res; + } + return cmp_part_ids(ref1, ref2); +} + +/* + @brief + Provide ordering by (key_value, underying_table_rowid, part_no). +*/ +extern "C" int cmp_key_rowid_part_id(void *ptr, uchar *ref1, uchar *ref2) +{ + ha_partition *file= (ha_partition*)ptr; + int res; + + if ((res= key_rec_cmp(file->m_curr_key_info, ref1 + PARTITION_BYTES_IN_POS, + ref2 + PARTITION_BYTES_IN_POS))) + { + return res; + } + if ((res= file->m_file[0]->cmp_ref(ref1 + PARTITION_BYTES_IN_POS + file->m_rec_length, + ref2 + PARTITION_BYTES_IN_POS + file->m_rec_length))) + { + return res; + } + return cmp_part_ids(ref1, ref2); +} + + /** Common routine for a number of index_read variants @@ -5490,7 +5525,7 @@ int ha_partition::handle_ordered_index_scan(uchar *buf, bool reverse_order) for (; first_used_part < m_part_spec.start_part; first_used_part++) { if (bitmap_is_set(&(m_part_info->used_partitions), first_used_part)) - part_rec_buf_ptr+= m_rec_length + PARTITION_BYTES_IN_POS; + part_rec_buf_ptr+= m_priority_queue_rec_len; } DBUG_PRINT("info", ("m_part_spec.start_part %u first_used_part %u", m_part_spec.start_part, first_used_part)); @@ -5545,6 +5580,11 @@ int ha_partition::handle_ordered_index_scan(uchar *buf, bool reverse_order) if (!error) { found= TRUE; + if (!m_using_extended_keys) + { + file->position(rec_buf_ptr); + memcpy(rec_buf_ptr + m_rec_length, file->ref, file->ref_length); + } /* Initialize queue without order first, simply insert */ @@ -5561,7 +5601,7 @@ int ha_partition::handle_ordered_index_scan(uchar *buf, bool reverse_order) m_key_not_found= true; saved_error= error; } - part_rec_buf_ptr+= m_rec_length + PARTITION_BYTES_IN_POS; + part_rec_buf_ptr+= m_priority_queue_rec_len; } if (found) { @@ -5570,7 +5610,7 @@ int ha_partition::handle_ordered_index_scan(uchar *buf, bool reverse_order) after that read the first entry and copy it to the buffer to return in. */ queue_set_max_at_top(&m_queue, reverse_order); - queue_set_cmp_arg(&m_queue, (void*)m_curr_key_info); + queue_set_cmp_arg(&m_queue, m_using_extended_keys? m_curr_key_info : (void*)this); m_queue.elements= j - queue_first_element(&m_queue); queue_fix(&m_queue); return_top_record(buf); @@ -5646,7 +5686,7 @@ int ha_partition::handle_ordered_index_scan_key_not_found() else if (error != HA_ERR_END_OF_FILE && error != HA_ERR_KEY_NOT_FOUND) DBUG_RETURN(error); } - part_buf+= m_rec_length + PARTITION_BYTES_IN_POS; + part_buf += m_priority_queue_rec_len; } DBUG_ASSERT(curr_rec_buf); bitmap_clear_all(&m_key_not_found_partitions); @@ -5730,6 +5770,7 @@ int ha_partition::handle_ordered_next(uchar *buf, bool is_next_same) else error= file->ha_index_next_same(rec_buf, m_start_key.key, m_start_key.length); + if (error) { if (error == HA_ERR_END_OF_FILE) @@ -5747,6 +5788,13 @@ int ha_partition::handle_ordered_next(uchar *buf, bool is_next_same) } DBUG_RETURN(error); } + + if (!m_using_extended_keys) + { + file->position(rec_buf); + memcpy(rec_buf + m_rec_length, file->ref, file->ref_length); + } + queue_replace_top(&m_queue); return_top_record(buf); DBUG_PRINT("info", ("Record returned from partition %u", m_top_entry)); @@ -7717,19 +7765,29 @@ uint ha_partition::min_record_length(uint options) const int ha_partition::cmp_ref(const uchar *ref1, const uchar *ref2) { - uint part_id; + int cmp; my_ptrdiff_t diff1, diff2; - handler *file; DBUG_ENTER("ha_partition::cmp_ref"); + cmp = m_file[0]->cmp_ref((ref1 + PARTITION_BYTES_IN_POS), + (ref2 + PARTITION_BYTES_IN_POS)); + if (cmp) + DBUG_RETURN(cmp); + if ((ref1[0] == ref2[0]) && (ref1[1] == ref2[1])) { - part_id= uint2korr(ref1); - file= m_file[part_id]; - DBUG_ASSERT(part_id < m_tot_parts); - DBUG_RETURN(file->cmp_ref((ref1 + PARTITION_BYTES_IN_POS), - (ref2 + PARTITION_BYTES_IN_POS))); + /* This means that the references are same and are in same partition.*/ + DBUG_RETURN(0); } + + /* + In Innodb we compare with either primary key value or global DB_ROW_ID so + it is not possible that the two references are equal and are in different + partitions, but in myisam it is possible since we are comparing offsets. + Remove this assert if DB_ROW_ID is changed to be per partition. + */ + DBUG_ASSERT(!m_innodb); + diff1= ref2[1] - ref1[1]; diff2= ref2[0] - ref1[0]; if (diff1 > 0) diff --git a/sql/ha_partition.h b/sql/ha_partition.h index db8863a36b6..c044f9daa9c 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -49,6 +49,8 @@ enum partition_keywords /* offset to the engines array */ #define PAR_ENGINES_OFFSET 12 +extern "C" int cmp_key_rowid_part_id(void *ptr, uchar *ref1, uchar *ref2); + class ha_partition :public handler { private: @@ -88,6 +90,22 @@ private: uchar *m_rec0; // table->record[0] const uchar *m_err_rec; // record which gave error QUEUE m_queue; // Prio queue used by sorted read + + /* + Length of an element in m_ordered_rec_buffer. The elements are composed of + + [part_no] [table->record copy] [underlying_table_rowid] + + underlying_table_rowid is only stored when the table has no extended keys. + */ + uint m_priority_queue_rec_len; + + /* + If true, then sorting records by key value also sorts them by their + underlying_table_rowid. + */ + bool m_using_extended_keys; + /* Since the partition handler is a handler on top of other handlers, it is necessary to keep information about what the underlying handler @@ -1172,14 +1190,17 @@ public: DBUG_ASSERT(h == m_file[i]->ht); return h; } + #ifdef WITH_WSREP void wsrep_reset_files() { for (uint i=0; i < m_tot_parts; i++) - m_file[i]->ha_start_of_new_statement(); + m_file[i]->ft_handler= 0; } virtual int wsrep_db_type() const; #endif /* WITH_WSREP */ + + friend int cmp_key_rowid_part_id(void *ptr, uchar *ref1, uchar *ref2); }; #endif /* HA_PARTITION_INCLUDED */ diff --git a/sql/handler.cc b/sql/handler.cc index dc7e3cb3084..ad651e7de4a 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -3545,14 +3545,11 @@ int handler::ha_check(THD *thd, HA_CHECK_OPT *check_opt) if it is started. */ +inline void -handler::mark_trx_read_write_part2() +handler::mark_trx_read_write() { Ha_trx_info *ha_info= &ha_thd()->ha_data[ht->slot].ha_info[0]; - - /* Don't call this function again for this statement */ - mark_trx_done= TRUE; - /* When a storage engine method is called, the transaction must have been started, unless it's a DDL call, for which the diff --git a/sql/handler.h b/sql/handler.h index dd0b2a9a581..406d9f976e2 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1763,7 +1763,6 @@ public: enum {NONE=0, INDEX, RND} inited; bool locked; bool implicit_emptied; /* Can be !=0 only if HEAP */ - bool mark_trx_done; const COND *pushed_cond; /** next_insert_id is the next value which should be inserted into the @@ -1826,7 +1825,7 @@ public: in_range_check_pushed_down(FALSE), ref_length(sizeof(my_off_t)), ft_handler(0), inited(NONE), - locked(FALSE), implicit_emptied(0), mark_trx_done(FALSE), + locked(FALSE), implicit_emptied(0), pushed_cond(0), next_insert_id(0), insert_id_for_cur_row(0), pushed_idx_cond(NULL), pushed_idx_cond_keyno(MAX_KEY), @@ -1904,13 +1903,6 @@ public: } int ha_rnd_init_with_error(bool scan) __attribute__ ((warn_unused_result)); int ha_reset(); - /* Tell handler (not storage engine) this is start of a new statement */ - void ha_start_of_new_statement() - { - ft_handler= 0; - mark_trx_done= FALSE; - } - /* this is necessary in many places, e.g. in HANDLER command */ int ha_index_or_rnd_end() { @@ -2779,12 +2771,8 @@ protected: private: /* Private helpers */ - void mark_trx_read_write_part2(); - inline void mark_trx_read_write() - { - if (!mark_trx_done) - mark_trx_read_write_part2(); - } + inline void mark_trx_read_write(); +private: inline void increment_statistics(ulong SSV::*offset) const; inline void decrement_statistics(ulong SSV::*offset) const; diff --git a/sql/item.cc b/sql/item.cc index 5e4c4b03c16..a4ab81a9e5a 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -8360,6 +8360,8 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items) { tmp_field->init(field_arg->field->table); set_field(tmp_field); + // the index is important when read bits set + tmp_field->field_index= field_arg->field->field_index; } } return FALSE; diff --git a/sql/item.h b/sql/item.h index 0714ea835f8..3b3dfe5d327 100644 --- a/sql/item.h +++ b/sql/item.h @@ -3857,7 +3857,7 @@ public: bool walk(Item_processor processor, bool walk_subquery, uchar *args) { - return arg->walk(processor, walk_subquery, args) || + return (arg && arg->walk(processor, walk_subquery, args)) || (this->*processor)(args); } diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 1731fcf7e99..4579a6949c7 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -943,7 +943,7 @@ class Item_func_uncompressed_length : public Item_int_func public: Item_func_uncompressed_length(Item *a):Item_int_func(a){} const char *func_name() const{return "uncompressed_length";} - void fix_length_and_dec() { max_length=10; } + void fix_length_and_dec() { max_length=10; maybe_null= true; } longlong val_int(); }; diff --git a/sql/log_event.cc b/sql/log_event.cc index 5d402cdeb3a..291e1456ae8 100644 --- a/sql/log_event.cc +++ b/sql/log_event.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, 2014, Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -8306,8 +8306,31 @@ int Rows_log_event::do_add_row_data(uchar *row_data, size_t length) if (static_cast<size_t>(m_rows_end - m_rows_cur) <= length) { size_t const block_size= 1024; - my_ptrdiff_t const cur_size= m_rows_cur - m_rows_buf; - my_ptrdiff_t const new_alloc= + ulong cur_size= m_rows_cur - m_rows_buf; + DBUG_EXECUTE_IF("simulate_too_big_row_case1", + cur_size= UINT_MAX32 - (block_size * 10); + length= UINT_MAX32 - (block_size * 10);); + DBUG_EXECUTE_IF("simulate_too_big_row_case2", + cur_size= UINT_MAX32 - (block_size * 10); + length= block_size * 10;); + DBUG_EXECUTE_IF("simulate_too_big_row_case3", + cur_size= block_size * 10; + length= UINT_MAX32 - (block_size * 10);); + DBUG_EXECUTE_IF("simulate_too_big_row_case4", + cur_size= UINT_MAX32 - (block_size * 10); + length= (block_size * 10) - block_size + 1;); + ulong remaining_space= UINT_MAX32 - cur_size; + /* Check that the new data fits within remaining space and we can add + block_size without wrapping. + */ + if (length > remaining_space || + ((length + block_size) > remaining_space)) + { + sql_print_error("The row data is greater than 4GB, which is too big to " + "write to the binary log."); + DBUG_RETURN(ER_BINLOG_ROW_LOGGING_FAILED); + } + ulong const new_alloc= block_size * ((cur_size + length + block_size - 1) / block_size); uchar* const new_buf= (uchar*)my_realloc((uchar*)m_rows_buf, (uint) new_alloc, @@ -8589,10 +8612,14 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) /* Bug#56662 Assertion failed: next_insert_id == 0, file handler.cc Don't allow generation of auto_increment value when processing - rows event by setting 'MODE_NO_AUTO_VALUE_ON_ZERO'. + rows event by setting 'MODE_NO_AUTO_VALUE_ON_ZERO'. The exception + to this rule happens when the auto_inc column exists on some + extra columns on the slave. In that case, do not force + MODE_NO_AUTO_VALUE_ON_ZERO. */ ulonglong saved_sql_mode= thd->variables.sql_mode; - thd->variables.sql_mode= MODE_NO_AUTO_VALUE_ON_ZERO; + if (!is_auto_inc_in_extra_columns()) + thd->variables.sql_mode= MODE_NO_AUTO_VALUE_ON_ZERO; // row processing loop @@ -9896,9 +9923,28 @@ Write_rows_log_event::do_before_row_operations(const Slave_reporting_capability * table->auto_increment_field_not_null and SQL_MODE(if includes * MODE_NO_AUTO_VALUE_ON_ZERO) in update_auto_increment function. * SQL_MODE of slave sql thread is always consistency with master's. - * In RBR, auto_increment fields never are NULL. + * In RBR, auto_increment fields never are NULL, except if the auto_inc + * column exists only on the slave side (i.e., in an extra column + * on the slave's table). */ - m_table->auto_increment_field_not_null= TRUE; + if (!is_auto_inc_in_extra_columns()) + m_table->auto_increment_field_not_null= TRUE; + else + { + /* + Here we have checked that there is an extra field + on this server's table that has an auto_inc column. + + Mark that the auto_increment field is null and mark + the read and write set bits. + + (There can only be one AUTO_INC column, it is always + indexed and it cannot have a DEFAULT value). + */ + m_table->auto_increment_field_not_null= FALSE; + m_table->mark_auto_increment_column(); + } + return error; } @@ -9907,6 +9953,19 @@ Write_rows_log_event::do_after_row_operations(const Slave_reporting_capability * int error) { int local_error= 0; + + /** + Clear the write_set bit for auto_inc field that only + existed on the destination table as an extra column. + */ + if (is_auto_inc_in_extra_columns()) + { + bitmap_clear_bit(m_table->write_set, m_table->next_number_field->field_index); + bitmap_clear_bit( m_table->read_set, m_table->next_number_field->field_index); + + if (get_flags(STMT_END_F)) + m_table->file->ha_release_auto_increment(); + } m_table->next_number_field=0; m_table->auto_increment_field_not_null= FALSE; if ((slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT) || @@ -10030,7 +10089,13 @@ Rows_log_event::write_row(const Relay_log_info *const rli, ulong estimated_rows= (m_rows_end - m_curr_row) / (m_curr_row_end - m_curr_row); m_table->file->ha_start_bulk_insert(estimated_rows); } - + + /* + Explicitly set the auto_inc to null to make sure that + it gets an auto_generated value. + */ + if (is_auto_inc_in_extra_columns()) + m_table->next_number_field->set_null(); #ifndef DBUG_OFF DBUG_DUMP("record[0]", table->record[0], table->s->reclength); diff --git a/sql/log_event.h b/sql/log_event.h index 1d90111f1ca..c10380618a8 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2013, 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 @@ -3910,6 +3910,20 @@ protected: return ::unpack_row(rli, m_table, m_width, m_curr_row, &m_cols, &m_curr_row_end, &m_master_reclength, m_rows_end); } + + /** + Helper function to check whether there is an auto increment + column on the table where the event is to be applied. + + @return true if there is an autoincrement field on the extra + columns, false otherwise. + */ + inline bool is_auto_inc_in_extra_columns() + { + DBUG_ASSERT(m_table); + return (m_table->next_number_field && + m_table->next_number_field->field_index >= m_width); + } #endif private: diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 91fdb27ffe7..af1a5a2e81e 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. +/* Copyright (c) 2000, 2014, Oracle and/or its affiliates. Copyright (c) 2008, 2014, SkySQL Ab. This program is free software; you can redistribute it and/or modify @@ -2168,7 +2168,7 @@ static struct passwd *check_user(const char *user) } if (!user) { - if (!opt_bootstrap) + if (!opt_bootstrap && !opt_help) { sql_print_error("Fatal error: Please read \"Security\" section of the manual to find out how to run mysqld as root!\n"); unireg_abort(1); @@ -2629,9 +2629,7 @@ void unlink_thd(THD *thd) thd_cleanup(thd); dec_connection_count(thd); - mysql_mutex_lock(&LOCK_status); - add_to_status(&global_status_var, &thd->status_var); - mysql_mutex_unlock(&LOCK_status); + thd->add_status_to_global(); mysql_mutex_lock(&LOCK_thread_count); thread_count--; @@ -5771,12 +5769,6 @@ int mysqld_main(int argc, char **argv) unireg_abort(1); } - /* - We must have LOCK_open before LOCK_global_system_variables because - LOCK_open is hold while sql_plugin.c::intern_sys_var_ptr() is called. - */ - mysql_mutex_record_order(&LOCK_open, &LOCK_global_system_variables); - create_shutdown_thread(); start_handle_manager(); diff --git a/sql/mysqld.h b/sql/mysqld.h index 89e20539555..d3e7f3eb4b3 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -447,7 +447,7 @@ extern my_atomic_rwlock_t global_query_id_lock; void unireg_end(void) __attribute__((noreturn)); /* increment query_id and return it. */ -inline query_id_t next_query_id() +inline __attribute__((warn_unused_result)) query_id_t next_query_id() { query_id_t id; my_atomic_rwlock_wrlock(&global_query_id_lock); diff --git a/sql/protocol.cc b/sql/protocol.cc index 9b8dd2299f3..5afddb277e4 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -64,7 +64,7 @@ bool Protocol_binary::net_store_data(const uchar *from, size_t length) /* - net_store_data() - extended version with character set conversion. + net_store_data_cs() - extended version with character set conversion. It is optimized for short strings whose length after conversion is garanteed to be less than 251, which accupies @@ -76,8 +76,12 @@ bool Protocol_binary::net_store_data(const uchar *from, size_t length) */ #ifndef EMBEDDED_LIBRARY -bool Protocol::net_store_data(const uchar *from, size_t length, +bool Protocol::net_store_data_cs(const uchar *from, size_t length, CHARSET_INFO *from_cs, CHARSET_INFO *to_cs) +#else +bool Protocol_binary::net_store_data_cs(const uchar *from, size_t length, + CHARSET_INFO *from_cs, CHARSET_INFO *to_cs) +#endif { uint dummy_errors; /* Calculate maxumum possible result length */ @@ -117,7 +121,6 @@ bool Protocol::net_store_data(const uchar *from, size_t length, packet->length((uint) (to - packet->ptr())); return 0; } -#endif /** @@ -1015,7 +1018,7 @@ bool Protocol::store_string_aux(const char *from, size_t length, tocs != &my_charset_bin) { /* Store with conversion */ - return net_store_data((uchar*) from, length, fromcs, tocs); + return net_store_data_cs((uchar*) from, length, fromcs, tocs); } /* Store without conversion */ return net_store_data((uchar*) from, length); diff --git a/sql/protocol.h b/sql/protocol.h index d9bc48ce45d..871d6018458 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -43,14 +43,16 @@ protected: uint field_count; #ifndef EMBEDDED_LIBRARY bool net_store_data(const uchar *from, size_t length); + bool net_store_data_cs(const uchar *from, size_t length, + CHARSET_INFO *fromcs, CHARSET_INFO *tocs); #else virtual bool net_store_data(const uchar *from, size_t length); + virtual bool net_store_data_cs(const uchar *from, size_t length, + CHARSET_INFO *fromcs, CHARSET_INFO *tocs); char **next_field; MYSQL_FIELD *next_mysql_field; MEM_ROOT *alloc; #endif - bool net_store_data(const uchar *from, size_t length, - CHARSET_INFO *fromcs, CHARSET_INFO *tocs); bool store_string_aux(const char *from, size_t length, CHARSET_INFO *fromcs, CHARSET_INFO *tocs); @@ -179,6 +181,8 @@ public: #ifdef EMBEDDED_LIBRARY virtual bool write(); bool net_store_data(const uchar *from, size_t length); + bool net_store_data_cs(const uchar *from, size_t length, + CHARSET_INFO *fromcs, CHARSET_INFO *tocs); #endif virtual bool store_null(); virtual bool store_tiny(longlong from); diff --git a/sql/share/charsets/Index.xml b/sql/share/charsets/Index.xml index 3e402226a34..9764d629625 100644 --- a/sql/share/charsets/Index.xml +++ b/sql/share/charsets/Index.xml @@ -4,6 +4,7 @@ <copyright> Copyright (c) 2003-2005 MySQL AB + Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/share/charsets/ascii.xml b/sql/share/charsets/ascii.xml index 29336b3a665..c516a68516c 100644 --- a/sql/share/charsets/ascii.xml +++ b/sql/share/charsets/ascii.xml @@ -4,6 +4,7 @@ <copyright> Copyright (c) 2003, 2007 MySQL AB + Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/share/charsets/cp1250.xml b/sql/share/charsets/cp1250.xml index 1b4a71ef6d5..e6681a625a2 100644 --- a/sql/share/charsets/cp1250.xml +++ b/sql/share/charsets/cp1250.xml @@ -4,6 +4,7 @@ <copyright> Copyright (c) 2003, 2005 MySQL AB + Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/share/charsets/cp1256.xml b/sql/share/charsets/cp1256.xml index 806fef961f7..ab0ba855f3b 100644 --- a/sql/share/charsets/cp1256.xml +++ b/sql/share/charsets/cp1256.xml @@ -6,6 +6,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/share/charsets/cp1257.xml b/sql/share/charsets/cp1257.xml index 8ae73fdf25a..61d1d276b0a 100644 --- a/sql/share/charsets/cp1257.xml +++ b/sql/share/charsets/cp1257.xml @@ -4,6 +4,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/share/charsets/cp850.xml b/sql/share/charsets/cp850.xml index 198b336daef..06465540a75 100644 --- a/sql/share/charsets/cp850.xml +++ b/sql/share/charsets/cp850.xml @@ -4,6 +4,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/share/charsets/cp866.xml b/sql/share/charsets/cp866.xml index d35f3d68b05..9cd8c8c504b 100644 --- a/sql/share/charsets/cp866.xml +++ b/sql/share/charsets/cp866.xml @@ -4,6 +4,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/share/charsets/dec8.xml b/sql/share/charsets/dec8.xml index 66bb421b674..68949309ced 100644 --- a/sql/share/charsets/dec8.xml +++ b/sql/share/charsets/dec8.xml @@ -4,6 +4,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/share/charsets/geostd8.xml b/sql/share/charsets/geostd8.xml index a789d07e6d8..822cc083724 100644 --- a/sql/share/charsets/geostd8.xml +++ b/sql/share/charsets/geostd8.xml @@ -4,6 +4,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/share/charsets/greek.xml b/sql/share/charsets/greek.xml index 5b66a7ab442..cbbe22e675a 100644 --- a/sql/share/charsets/greek.xml +++ b/sql/share/charsets/greek.xml @@ -4,6 +4,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/share/charsets/hebrew.xml b/sql/share/charsets/hebrew.xml index 0544b27ef4f..562fa4f4748 100644 --- a/sql/share/charsets/hebrew.xml +++ b/sql/share/charsets/hebrew.xml @@ -4,6 +4,7 @@ <copyright> Copyright (c) 2003, 2006 MySQL AB + Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/share/charsets/hp8.xml b/sql/share/charsets/hp8.xml index 83a076237f7..b17f75ed73e 100644 --- a/sql/share/charsets/hp8.xml +++ b/sql/share/charsets/hp8.xml @@ -4,6 +4,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/share/charsets/keybcs2.xml b/sql/share/charsets/keybcs2.xml index a9f305deab8..7c2775ba5c3 100644 --- a/sql/share/charsets/keybcs2.xml +++ b/sql/share/charsets/keybcs2.xml @@ -4,6 +4,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/share/charsets/koi8r.xml b/sql/share/charsets/koi8r.xml index 21ebf78b79e..25264d4f9ce 100644 --- a/sql/share/charsets/koi8r.xml +++ b/sql/share/charsets/koi8r.xml @@ -4,6 +4,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/share/charsets/koi8u.xml b/sql/share/charsets/koi8u.xml index 65145c97593..a2f5de9feb2 100644 --- a/sql/share/charsets/koi8u.xml +++ b/sql/share/charsets/koi8u.xml @@ -4,6 +4,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/share/charsets/languages.html b/sql/share/charsets/languages.html index 2b1c44421bf..3263d6a2ae2 100644 --- a/sql/share/charsets/languages.html +++ b/sql/share/charsets/languages.html @@ -1,6 +1,7 @@ #!/bin/sh # Copyright (C) 2003 MySQL AB +# Use is subject to license terms # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/sql/share/charsets/latin1.xml b/sql/share/charsets/latin1.xml index 4054eea8d33..68307847d91 100644 --- a/sql/share/charsets/latin1.xml +++ b/sql/share/charsets/latin1.xml @@ -4,6 +4,7 @@ <copyright> Copyright (c) 2003, 2005 MySQL AB + Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/share/charsets/latin2.xml b/sql/share/charsets/latin2.xml index a44ec7e0ec6..29ff4cb974b 100644 --- a/sql/share/charsets/latin2.xml +++ b/sql/share/charsets/latin2.xml @@ -4,6 +4,7 @@ <copyright> Copyright (c) 2003, 2005 MySQL AB + Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/share/charsets/latin5.xml b/sql/share/charsets/latin5.xml index 6b60e58cdda..ca7dd106de5 100644 --- a/sql/share/charsets/latin5.xml +++ b/sql/share/charsets/latin5.xml @@ -4,6 +4,7 @@ <copyright> Copyright (c) 2003, 2005 MySQL AB + Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/share/charsets/latin7.xml b/sql/share/charsets/latin7.xml index fb384b3a5ff..81866c23bbd 100644 --- a/sql/share/charsets/latin7.xml +++ b/sql/share/charsets/latin7.xml @@ -4,6 +4,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/share/charsets/macce.xml b/sql/share/charsets/macce.xml index d7242f26297..4fa46301d2e 100644 --- a/sql/share/charsets/macce.xml +++ b/sql/share/charsets/macce.xml @@ -4,6 +4,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/share/charsets/macroman.xml b/sql/share/charsets/macroman.xml index a2485cf9379..4ee8dc1f952 100644 --- a/sql/share/charsets/macroman.xml +++ b/sql/share/charsets/macroman.xml @@ -4,6 +4,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/share/charsets/swe7.xml b/sql/share/charsets/swe7.xml index f12a2238718..d881f1e7d62 100644 --- a/sql/share/charsets/swe7.xml +++ b/sql/share/charsets/swe7.xml @@ -4,6 +4,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/slave.cc b/sql/slave.cc index 75765ca13e2..7469f28457d 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1220,6 +1220,7 @@ bool is_network_error(uint errorno) errorno == ER_CON_COUNT_ERROR || errorno == ER_CONNECTION_KILLED || errorno == ER_NEW_ABORTING_CONNECTION || + errorno == ER_NET_READ_INTERRUPTED || errorno == ER_SERVER_SHUTDOWN) return TRUE; @@ -3358,6 +3359,7 @@ err: } write_ignored_events_info_to_relay_log(thd, mi); thd_proc_info(thd, "Waiting for slave mutex on exit"); + thd->add_status_to_global(); mysql_mutex_lock(&mi->run_lock); err_during_init: @@ -3753,6 +3755,7 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \ thd->catalog= 0; thd->reset_query(); thd->reset_db(NULL, 0); + thd->add_status_to_global(); thd_proc_info(thd, "Waiting for slave mutex on exit"); mysql_mutex_lock(&rli->run_lock); err_during_init: diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 99f9b172b16..3272e29389b 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1223,6 +1223,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success) LEX *old_lex; Item_change_list old_change_list; String old_packet; + uint old_server_status; Reprepare_observer *save_reprepare_observer= thd->m_reprepare_observer; Object_creation_ctx *saved_creation_ctx; Warning_info *saved_warning_info; @@ -1357,6 +1358,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success) It is probably safe to use same thd->convert_buff everywhere. */ old_packet.swap(thd->packet); + old_server_status= thd->server_status; /* Switch to per-instruction arena here. We can do it since we cleanup @@ -1486,6 +1488,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success) thd->spcont->pop_all_cursors(); // To avoid memory leaks after an error /* Restore all saved */ + thd->server_status= old_server_status; old_packet.swap(thd->packet); DBUG_ASSERT(thd->change_list.is_empty()); old_change_list.move_elements_to(&thd->change_list); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 0e52247dcae..3d550b5314a 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -9184,7 +9184,12 @@ bool acl_authenticate(THD *thd, uint connect_errors, auth_plugin_name= &mpvio.acl_user->plugin; res= do_auth_once(thd, auth_plugin_name, &mpvio); } - + if (mpvio.make_it_fail) + { + mpvio.status= MPVIO_EXT::FAILURE; + res= CR_ERROR; + } + Security_context *sctx= thd->security_ctx; const ACL_USER *acl_user= mpvio.acl_user; diff --git a/sql/sql_audit.cc b/sql/sql_audit.cc index 1dab45800d9..108b74cac5f 100644 --- a/sql/sql_audit.cc +++ b/sql/sql_audit.cc @@ -84,7 +84,7 @@ static void general_class_handler(THD *thd, uint event_subtype, va_list ap) event.general_rows= (unsigned long long) va_arg(ap, ha_rows); event.database= va_arg(ap, const char *); event.database_length= va_arg(ap, unsigned int); - event.query_id= (unsigned long long) thd->query_id; + event.query_id= (unsigned long long) (thd ? thd->query_id : 0); event_class_dispatch(thd, MYSQL_AUDIT_GENERAL_CLASS, &event); } @@ -134,7 +134,7 @@ static void table_class_handler(THD *thd, uint event_subclass, va_list ap) event.new_database_length= va_arg(ap, unsigned int); event.new_table= va_arg(ap, const char *); event.new_table_length= va_arg(ap, unsigned int); - event.query_id= (unsigned long long) thd->query_id; + event.query_id= (unsigned long long) (thd ? thd->query_id : 0); event_class_dispatch(thd, MYSQL_AUDIT_TABLE_CLASS, &event); } diff --git a/sql/sql_audit.h b/sql/sql_audit.h index 9acd4abbdca..3f3f97a2730 100644 --- a/sql/sql_audit.h +++ b/sql/sql_audit.h @@ -90,11 +90,13 @@ void mysql_audit_general_log(THD *thd, time_t time, { CHARSET_INFO *clientcs= thd ? thd->variables.character_set_client : global_system_variables.character_set_client; + const char *db= thd ? thd->db : ""; + size_t db_length= thd ? thd->db_length : 0; mysql_audit_notify(thd, MYSQL_AUDIT_GENERAL_CLASS, MYSQL_AUDIT_GENERAL_LOG, 0, time, user, userlen, cmd, cmdlen, query, querylen, clientcs, (ha_rows) 0, - thd->db, thd->db_length); + db, db_length); } } @@ -123,6 +125,8 @@ void mysql_audit_general(THD *thd, uint event_subtype, char user_buff[MAX_USER_HOST_SIZE]; CSET_STRING query; ha_rows rows; + const char *db; + size_t db_length; if (thd) { @@ -130,18 +134,22 @@ void mysql_audit_general(THD *thd, uint event_subtype, user= user_buff; userlen= make_user_name(thd, user_buff); rows= thd->warning_info->current_row_for_warning(); + db= thd->db; + db_length= thd->db_length; } else { user= 0; userlen= 0; rows= 0; + db= ""; + db_length= 0; } mysql_audit_notify(thd, MYSQL_AUDIT_GENERAL_CLASS, event_subtype, error_code, time, user, userlen, msg, msglen, query.str(), query.length(), query.charset(), rows, - thd->db, thd->db_length); + db, db_length); } } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 9eb88e90b6b..e840b5c7072 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1942,6 +1942,17 @@ retry: DBUG_PRINT("info", ("real table: %s.%s", d_name, t_name)); for (TABLE_LIST *tl= table_list;;) { + if (tl && + tl->select_lex && tl->select_lex->master_unit() && + tl->select_lex->master_unit()->executed) + { + /* + There is no sense to check tables of already executed parts + of the query + */ + tl= tl->next_global; + continue; + } /* Table is unique if it is present only once in the global list of tables and once in the list of table locks. diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 2641ab9bc4f..511df6b998b 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1349,7 +1349,6 @@ MYSQL_ERROR* THD::raise_condition(uint sql_errno, got_warning= 1; break; case MYSQL_ERROR::WARN_LEVEL_ERROR: - mysql_audit_general(this, MYSQL_AUDIT_GENERAL_ERROR, sql_errno, msg); break; default: DBUG_ASSERT(FALSE); @@ -1360,6 +1359,8 @@ MYSQL_ERROR* THD::raise_condition(uint sql_errno, if (level == MYSQL_ERROR::WARN_LEVEL_ERROR) { + mysql_audit_general(this, MYSQL_AUDIT_GENERAL_ERROR, sql_errno, msg); + is_slave_error= 1; // needed to catch query errors during replication if (! stmt_da->is_error()) @@ -1581,9 +1582,7 @@ void THD::init_for_queries() void THD::change_user(void) { - mysql_mutex_lock(&LOCK_status); - add_to_status(&global_status_var, &status_var); - mysql_mutex_unlock(&LOCK_status); + add_status_to_global(); cleanup(); reset_killed(); @@ -1614,6 +1613,7 @@ void THD::cleanup(void) #endif mysql_ha_cleanup(this); + locked_tables_list.unlock_locked_tables(this); close_temporary_tables(this); @@ -1621,8 +1621,6 @@ void THD::cleanup(void) trans_rollback(this); xid_cache_delete(&transaction.xid_state); - locked_tables_list.unlock_locked_tables(this); - DBUG_ASSERT(open_tables == NULL); /* If the thread was in the middle of an ongoing transaction (rolled diff --git a/sql/sql_class.h b/sql/sql_class.h index 8d19069fbcf..bee35bfda7c 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -712,6 +712,11 @@ typedef struct system_status_var #define last_system_status_var questions +void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var); + +void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var, + STATUS_VAR *dec_var); + void mark_transaction_to_rollback(THD *thd, bool all); #ifdef MYSQL_SERVER @@ -2660,8 +2665,11 @@ public: Clear the current error, if any. We do not clear is_fatal_error or is_fatal_sub_stmt_error since we assume this is never called if the fatal error is set. + @todo: To silence an error, one should use Internal_error_handler - mechanism. In future this function will be removed. + mechanism. Issuing an error that can be possibly later "cleared" is not + compatible with other installed error handlers and audit plugins. + In future this function will be removed. */ inline void clear_error() { @@ -3160,6 +3168,14 @@ public: void wait_for_wakeup_ready(); /* Wake this thread up from wait_for_wakeup_ready(). */ void signal_wakeup_ready(); + + void add_status_to_global() + { + mysql_mutex_lock(&LOCK_status); + add_to_status(&global_status_var, &status_var); + mysql_mutex_unlock(&LOCK_status); + } + private: /** The current internal error handler for this thread, or NULL. */ @@ -4202,10 +4218,6 @@ public: */ #define CF_SKIP_QUESTIONS (1U << 1) -void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var); - -void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var, - STATUS_VAR *dec_var); void mark_transaction_to_rollback(THD *thd, bool all); /* Inline functions */ diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 90dd2483a44..4dbec21bf7e 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -68,8 +68,10 @@ mysql_handle_derived(LEX *lex, uint phases) { bool res= FALSE; THD *thd= lex->thd; + DBUG_ENTER("mysql_handle_derived"); + DBUG_PRINT("enter", ("phases: 0x%x", phases)); if (!lex->derived_tables) - return FALSE; + DBUG_RETURN(FALSE); lex->thd->derived_tables_processing= TRUE; @@ -127,7 +129,7 @@ mysql_handle_derived(LEX *lex, uint phases) } } lex->thd->derived_tables_processing= FALSE; - return res; + DBUG_RETURN(res); } /* @@ -166,8 +168,10 @@ mysql_handle_single_derived(LEX *lex, TABLE_LIST *derived, uint phases) THD *thd= lex->thd; uint8 allowed_phases= (derived->is_merged_derived() ? DT_PHASES_MERGE : DT_PHASES_MATERIALIZE); + DBUG_ENTER("mysql_handle_single_derived"); + DBUG_PRINT("enter", ("phases: 0x%x allowed: 0x%x", phases, allowed_phases)); if (!lex->derived_tables) - return FALSE; + DBUG_RETURN(FALSE); lex->thd->derived_tables_processing= TRUE; @@ -189,7 +193,7 @@ mysql_handle_single_derived(LEX *lex, TABLE_LIST *derived, uint phases) break; } lex->thd->derived_tables_processing= FALSE; - return res; + DBUG_RETURN(res); } @@ -354,16 +358,17 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived) uint tablenr; SELECT_LEX *parent_lex= derived->select_lex; Query_arena *arena, backup; + DBUG_ENTER("mysql_derived_merge"); if (derived->merged) - return FALSE; + DBUG_RETURN(FALSE); if (dt_select->uncacheable & UNCACHEABLE_RAND) { /* There is random function => fall back to materialization. */ derived->change_refs_to_fields(); derived->set_materialized_derived(); - return FALSE; + DBUG_RETURN(FALSE); } if (thd->lex->sql_command == SQLCOM_UPDATE_MULTI || @@ -467,7 +472,7 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived) exit_merge: if (arena) thd->restore_active_arena(arena, &backup); - return res; + DBUG_RETURN(res); } @@ -492,14 +497,15 @@ exit_merge: bool mysql_derived_merge_for_insert(THD *thd, LEX *lex, TABLE_LIST *derived) { + DBUG_ENTER("mysql_derived_merge_for_insert"); if (derived->merged_for_insert) - return FALSE; + DBUG_RETURN(FALSE); if (derived->is_materialized_derived()) - return mysql_derived_prepare(thd, lex, derived); + DBUG_RETURN(mysql_derived_prepare(thd, lex, derived)); if (!derived->is_multitable()) { if (!derived->single_table_updatable()) - return derived->create_field_translation(thd); + DBUG_RETURN(derived->create_field_translation(thd)); if (derived->merge_underlying_list) { derived->table= derived->merge_underlying_list->table; @@ -507,7 +513,7 @@ bool mysql_derived_merge_for_insert(THD *thd, LEX *lex, TABLE_LIST *derived) derived->merged_for_insert= TRUE; } } - return FALSE; + DBUG_RETURN(FALSE); } @@ -761,9 +767,10 @@ bool mysql_derived_optimize(THD *thd, LEX *lex, TABLE_LIST *derived) SELECT_LEX *save_current_select= lex->current_select; bool res= FALSE; + DBUG_ENTER("mysql_derived_optimize"); if (unit->optimized) - return FALSE; + DBUG_RETURN(FALSE); lex->current_select= first_select; if (unit->is_union()) @@ -803,7 +810,7 @@ bool mysql_derived_optimize(THD *thd, LEX *lex, TABLE_LIST *derived) } err: lex->current_select= save_current_select; - return res; + DBUG_RETURN(res); } @@ -825,11 +832,12 @@ err: bool mysql_derived_create(THD *thd, LEX *lex, TABLE_LIST *derived) { + DBUG_ENTER("mysql_derived_create"); TABLE *table= derived->table; SELECT_LEX_UNIT *unit= derived->get_unit(); if (table->created) - return FALSE; + DBUG_RETURN(FALSE); select_union *result= (select_union*)unit->result; if (table->s->db_type() == TMP_ENGINE_HTON) { @@ -839,13 +847,13 @@ bool mysql_derived_create(THD *thd, LEX *lex, TABLE_LIST *derived) &result->tmp_table_param.recinfo, (unit->first_select()->options | thd->variables.option_bits | TMP_TABLE_ALL_COLUMNS))) - return(TRUE); + DBUG_RETURN(TRUE); } if (open_tmp_table(table)) - return TRUE; + DBUG_RETURN(TRUE); table->file->extra(HA_EXTRA_WRITE_CACHE); table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); - return FALSE; + DBUG_RETURN(FALSE); } @@ -874,11 +882,12 @@ bool mysql_derived_create(THD *thd, LEX *lex, TABLE_LIST *derived) bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived) { + DBUG_ENTER("mysql_derived_fill"); SELECT_LEX_UNIT *unit= derived->get_unit(); bool res= FALSE; if (unit->executed && !unit->uncacheable && !unit->describe) - return FALSE; + DBUG_RETURN(FALSE); /*check that table creation passed without problems. */ DBUG_ASSERT(derived->table && derived->table->created); SELECT_LEX *first_select= unit->first_select(); @@ -920,7 +929,7 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived) unit->cleanup(); lex->current_select= save_current_select; - return res; + DBUG_RETURN(res); } @@ -943,6 +952,7 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived) bool mysql_derived_reinit(THD *thd, LEX *lex, TABLE_LIST *derived) { + DBUG_ENTER("mysql_derived_reinit"); st_select_lex_unit *unit= derived->get_unit(); if (derived->table) @@ -952,6 +962,6 @@ bool mysql_derived_reinit(THD *thd, LEX *lex, TABLE_LIST *derived) /* for derived tables & PS (which can't be reset by Item_subquery) */ unit->reinit_exec_mechanism(); unit->set_thd(thd); - return FALSE; + DBUG_RETURN(FALSE); } diff --git a/sql/sql_list.h b/sql/sql_list.h index aef2f8d5f25..7538f69766d 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -330,11 +330,12 @@ public: friend class error_list; friend class error_list_iterator; +#ifndef DBUG_OFF /* Debugging help: return N-th element in the list, or NULL if the list has less than N elements. */ - inline void *nth_element(int n) + void *elem(int n) { list_node *node= first; void *data= NULL; @@ -350,6 +351,8 @@ public: } return data; } +#endif + #ifdef LIST_EXTRA_DEBUG /* Check list invariants and print results into trace. Invariants are: @@ -528,7 +531,9 @@ public: } empty(); } - inline T *nth_element(int n) { return (T*)base_list::nth_element(n); } +#ifndef DBUG_OFF + T *elem(int n) { return (T*)base_list::elem(n); } +#endif }; diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 17c21118868..60e7b0b0d44 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -2900,6 +2900,7 @@ static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock) DBUG_ENTER("intern_sys_var_ptr"); DBUG_ASSERT(offset >= 0); DBUG_ASSERT((uint)offset <= global_system_variables.dynamic_variables_head); + mysql_mutex_assert_not_owner(&LOCK_open); if (!thd) DBUG_RETURN((uchar*) global_system_variables.dynamic_variables_ptr + offset); @@ -3170,15 +3171,21 @@ static void plugin_vars_free_values(sys_var *vars) static SHOW_TYPE pluginvar_show_type(st_mysql_sys_var *plugin_var) { - switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) { + switch (plugin_var->flags & (PLUGIN_VAR_TYPEMASK | PLUGIN_VAR_UNSIGNED)) { case PLUGIN_VAR_BOOL: return SHOW_MY_BOOL; case PLUGIN_VAR_INT: - return SHOW_INT; + return SHOW_SINT; + case PLUGIN_VAR_INT | PLUGIN_VAR_UNSIGNED: + return SHOW_UINT; case PLUGIN_VAR_LONG: - return SHOW_LONG; + return SHOW_SLONG; + case PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED: + return SHOW_ULONG; case PLUGIN_VAR_LONGLONG: - return SHOW_LONGLONG; + return SHOW_SLONGLONG; + case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED: + return SHOW_ULONGLONG; case PLUGIN_VAR_STR: return SHOW_CHAR_PTR; case PLUGIN_VAR_ENUM: diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 35267e6617c..fcadecdb85f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -496,6 +496,7 @@ fix_inner_refs(THD *thd, List<Item> &all_fields, SELECT_LEX *select, static void remove_redundant_subquery_clauses(st_select_lex *subq_select_lex) { + DBUG_ENTER("remove_redundant_subquery_clauses"); Item_subselect *subq_predicate= subq_select_lex->master_unit()->item; /* The removal should happen for IN, ALL, ANY and EXISTS subqueries, @@ -505,7 +506,7 @@ void remove_redundant_subquery_clauses(st_select_lex *subq_select_lex) b) SELECT a, (<single row subquery) FROM t1 */ if (subq_predicate->substype() == Item_subselect::SINGLEROW_SUBS) - return; + DBUG_VOID_RETURN; /* A subquery that is not single row should be one of IN/ALL/ANY/EXISTS. */ DBUG_ASSERT (subq_predicate->substype() == Item_subselect::EXISTS_SUBS || @@ -515,6 +516,7 @@ void remove_redundant_subquery_clauses(st_select_lex *subq_select_lex) { subq_select_lex->join->select_distinct= false; subq_select_lex->options&= ~SELECT_DISTINCT; + DBUG_PRINT("info", ("DISTINCT removed")); } /* @@ -524,8 +526,13 @@ void remove_redundant_subquery_clauses(st_select_lex *subq_select_lex) if (subq_select_lex->group_list.elements && !subq_select_lex->with_sum_func && !subq_select_lex->join->having) { + for (ORDER *ord= subq_select_lex->group_list.first; ord; ord= ord->next) + { + (*ord->item)->walk(&Item::eliminate_subselect_processor, FALSE, NULL); + } subq_select_lex->join->group_list= NULL; subq_select_lex->group_list.empty(); + DBUG_PRINT("info", ("GROUP BY removed")); } /* @@ -540,6 +547,7 @@ void remove_redundant_subquery_clauses(st_select_lex *subq_select_lex) subq_select_lex->group_list.empty(); } */ + DBUG_VOID_RETURN; } @@ -3605,6 +3613,9 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list, { conds->update_used_tables(); conds= remove_eq_conds(join->thd, conds, &join->cond_value); + if (conds && conds->type() == Item::COND_ITEM && + ((Item_cond*) conds)->functype() == Item_func::COND_AND_FUNC) + join->cond_equal= &((Item_cond_and*) conds)->cond_equal; join->select_lex->where= conds; if (join->cond_value == Item::COND_FALSE) { @@ -13594,7 +13605,10 @@ optimize_cond(JOIN *join, COND *conds, Remove all and-levels where CONST item != CONST item */ DBUG_EXECUTE("where",print_where(conds,"after const change", QT_ORDINARY);); - conds= remove_eq_conds(thd, conds, cond_value) ; + conds= remove_eq_conds(thd, conds, cond_value); + if (conds && conds->type() == Item::COND_ITEM && + ((Item_cond*) conds)->functype() == Item_func::COND_AND_FUNC) + join->cond_equal= &((Item_cond_and*) conds)->cond_equal; DBUG_EXECUTE("info",print_where(conds,"after remove", QT_ORDINARY);); } DBUG_RETURN(conds); @@ -15463,7 +15477,20 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields, keyinfo->key_length= 0; // Will compute the sum of the parts below. keyinfo->name= (char*) "distinct_key"; keyinfo->algorithm= HA_KEY_ALG_UNDEF; - keyinfo->rec_per_key=0; + /* + Needed by non-merged semi-joins: SJ-Materialized table must have a valid + rec_per_key array, because it participates in join optimization. Since + the table has no data, the only statistics we can provide is "unknown", + i.e. zero values. + + (For table record count, we calculate and set JOIN_TAB::found_records, + see get_delayed_table_estimates()). + */ + size_t rpk_size= keyinfo->key_parts* sizeof(keyinfo->rec_per_key[0]); + if (!(keyinfo->rec_per_key= (ulong*) alloc_root(&table->mem_root, + rpk_size))) + goto err; + bzero(keyinfo->rec_per_key, rpk_size); /* Create an extra field to hold NULL bits so that unique indexes on diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 4ad7c6b2478..51b48063525 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -940,9 +940,12 @@ public: is_handled= TRUE; break; + case ER_BAD_FIELD_ERROR: + case ER_SP_DOES_NOT_EXIST: case ER_NO_SUCH_TABLE: case ER_NO_SUCH_TABLE_IN_ENGINE: - /* Established behavior: warn if underlying tables are missing. */ + /* Established behavior: warn if underlying tables, columns, or functions + are missing. */ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_VIEW_INVALID, ER(ER_VIEW_INVALID), @@ -951,15 +954,6 @@ public: is_handled= TRUE; break; - case ER_SP_DOES_NOT_EXIST: - /* Established behavior: warn if underlying functions are missing. */ - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_VIEW_INVALID, - ER(ER_VIEW_INVALID), - m_top_view->get_db_name(), - m_top_view->get_table_name()); - is_handled= TRUE; - break; default: is_handled= FALSE; } @@ -2706,7 +2700,7 @@ static bool show_status_array(THD *thd, const char *wild, end= int10_to_str((long) *(uint*) value, buff, 10); break; case SHOW_SINT: - end= int10_to_str((long) *(uint*) value, buff, -10); + end= int10_to_str((long) *(int*) value, buff, -10); break; case SHOW_SLONG: end= int10_to_str(*(long*) value, buff, -10); @@ -4290,25 +4284,7 @@ end: } -/** - Trigger_error_handler is intended to intercept and silence SQL conditions - that might happen during trigger loading for SHOW statements. - The potential SQL conditions are: - - - ER_PARSE_ERROR -- this error is thrown if a trigger definition file - is damaged or contains invalid CREATE TRIGGER statement. That should - not happen in normal life. - - - ER_TRG_NO_DEFINER -- this warning is thrown when we're loading a - trigger created/imported in/from the version of MySQL, which does not - support trigger definers. - - - ER_TRG_NO_CREATION_CTX -- this warning is thrown when we're loading a - trigger created/imported in/from the version of MySQL, which does not - support trigger creation contexts. -*/ - -class Trigger_error_handler : public Internal_error_handler +class Warnings_only_error_handler : public Internal_error_handler { public: bool handle_condition(THD *thd, @@ -4323,12 +4299,16 @@ public: sql_errno == ER_TRG_NO_CREATION_CTX) return true; - return false; + if (level != MYSQL_ERROR::WARN_LEVEL_ERROR) + return false; + + if (!thd->stmt_da->is_error()) + thd->stmt_da->set_error_status(thd, sql_errno, msg, sqlstate); + return true; // handled! } }; - /** @brief Fill I_S tables whose data are retrieved from frm files and storage engine @@ -4526,25 +4506,11 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) if (!(table_open_method & ~OPEN_FRM_ONLY) && !with_i_schema) { - /* - Here we need to filter out warnings, which can happen - during loading of triggers in fill_schema_table_from_frm(), - because we don't need those warnings to pollute output of - SELECT from I_S / SHOW-statements. - */ - - Trigger_error_handler err_handler; - thd->push_internal_handler(&err_handler); - - int res= fill_schema_table_from_frm(thd, tables, schema_table, - db_name, table_name, - schema_table_idx, - &open_tables_state_backup, - can_deadlock); - - thd->pop_internal_handler(); - - if (!res) + if (!fill_schema_table_from_frm(thd, tables, schema_table, + db_name, table_name, + schema_table_idx, + &open_tables_state_backup, + can_deadlock)) continue; } @@ -7669,92 +7635,6 @@ int make_schema_select(THD *thd, SELECT_LEX *sel, } -/** - Fill INFORMATION_SCHEMA-table, leave correct Diagnostics_area / - Warning_info state after itself. - - This function is a wrapper around ST_SCHEMA_TABLE::fill_table(), which - may "partially silence" some errors. The thing is that during - fill_table() many errors might be emitted. These errors stem from the - nature of fill_table(). - - For example, SELECT ... FROM INFORMATION_SCHEMA.xxx WHERE TABLE_NAME = 'xxx' - results in a number of 'Table <db name>.xxx does not exist' errors, - because fill_table() tries to open the 'xxx' table in every possible - database. - - Those errors are cleared (the error status is cleared from - Diagnostics_area) inside fill_table(), but they remain in Warning_info - (Warning_info is not cleared because it may contain useful warnings). - - This function is responsible for making sure that Warning_info does not - contain warnings corresponding to the cleared errors. - - @note: THD::no_warnings_for_error used to be set before calling - fill_table(), thus those errors didn't go to Warning_info. This is not - the case now (THD::no_warnings_for_error was eliminated as a hack), so we - need to take care of those warnings here. - - @param thd Thread context. - @param table_list I_S table. - @param join_table JOIN/SELECT table. - - @return Error status. - @retval TRUE Error. - @retval FALSE Success. -*/ -static bool do_fill_table(THD *thd, - TABLE_LIST *table_list, - JOIN_TAB *join_table) -{ - // NOTE: fill_table() may generate many "useless" warnings, which will be - // ignored afterwards. On the other hand, there might be "useful" - // warnings, which should be presented to the user. Warning_info usually - // stores no more than THD::variables.max_error_count warnings. - // The problem is that "useless warnings" may occupy all the slots in the - // Warning_info, so "useful warnings" get rejected. In order to avoid - // that problem we create a Warning_info instance, which is capable of - // storing "unlimited" number of warnings. - Warning_info wi(thd->query_id, true); - Warning_info *wi_saved= thd->warning_info; - - thd->warning_info= &wi; - - bool res= table_list->schema_table->fill_table( - thd, table_list, join_table->select_cond); - - thd->warning_info= wi_saved; - - // Pass an error if any. - - if (thd->stmt_da->is_error()) - { - thd->warning_info->push_warning(thd, - thd->stmt_da->sql_errno(), - thd->stmt_da->get_sqlstate(), - MYSQL_ERROR::WARN_LEVEL_ERROR, - thd->stmt_da->message()); - } - - // Pass warnings (if any). - // - // Filter out warnings with WARN_LEVEL_ERROR level, because they - // correspond to the errors which were filtered out in fill_table(). - - - List_iterator_fast<MYSQL_ERROR> it(wi.warn_list()); - MYSQL_ERROR *err; - - while ((err= it++)) - { - if (err->get_level() != MYSQL_ERROR::WARN_LEVEL_ERROR) - thd->warning_info->push_warning(thd, err); - } - - return res; -} - - /* Fill temporary schema tables before SELECT @@ -7776,6 +7656,8 @@ bool get_schema_tables_result(JOIN *join, bool result= 0; DBUG_ENTER("get_schema_tables_result"); + Warnings_only_error_handler err_handler; + thd->push_internal_handler(&err_handler); for (JOIN_TAB *tab= first_linear_tab(join, WITH_CONST_TABLES); tab; tab= next_linear_tab(join, tab, WITHOUT_BUSH_ROOTS)) @@ -7828,20 +7710,42 @@ bool get_schema_tables_result(JOIN *join, else table_list->table->file->stats.records= 0; - if (do_fill_table(thd, table_list, tab)) + + if (table_list->schema_table->fill_table(thd, table_list, + tab->select_cond)) { result= 1; join->error= 1; tab->read_record.table->file= table_list->table->file; table_list->schema_table_state= executed_place; - if (!thd->is_error()) - my_error(ER_UNKNOWN_ERROR, MYF(0)); break; } tab->read_record.table->file= table_list->table->file; table_list->schema_table_state= executed_place; } } + thd->pop_internal_handler(); + if (thd->is_error()) + { + /* + This hack is here, because I_S code uses thd->clear_error() a lot. + Which means, a Warnings_only_error_handler cannot handle the error + corectly as it does not know whether an error is real (e.g. caused + by tab->select_cond->val_int()) or will be cleared later. + Thus it ignores all errors, and the real one (that is, the error + that was not cleared) is pushed now. + + It also means that an audit plugin cannot process the error correctly + either. See also thd->clear_error() + */ + thd->warning_info->push_warning(thd, + thd->stmt_da->sql_errno(), + thd->stmt_da->get_sqlstate(), + MYSQL_ERROR::WARN_LEVEL_ERROR, + thd->stmt_da->message()); + } + else if (result) + my_error(ER_UNKNOWN_ERROR, MYF(0)); DBUG_RETURN(result); } diff --git a/sql/sql_state.c b/sql/sql_state.c index c733d4b37c0..2bfd61d6696 100644 --- a/sql/sql_state.c +++ b/sql/sql_state.c @@ -1,4 +1,5 @@ /* Copyright (C) 2000-2003 MySQL AB + Use is subject to license terms This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/sql_table.cc b/sql/sql_table.cc index dda8a5fc710..6977d85dff5 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -6975,7 +6975,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, if (is_PK(key_info)) { merged[0]= key_info[0]; - if (is_PK(table->key_info)) + if (table->key_info && is_PK(table->key_info)) { old_cnt--; table->key_info++; diff --git a/sql/sql_test.cc b/sql/sql_test.cc index 311400c0c6c..ec426e39ee3 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -409,6 +409,15 @@ void print_sjm(SJ_MATERIALIZATION_INFO *sjm) } /* purecov: end */ +/* + Debugging help: force List<...>::elem function not be removed as unused. +*/ +Item* (List<Item>:: *dbug_list_item_elem_ptr)(int)= &List<Item>::elem; +Item_equal* (List<Item_equal>:: *dbug_list_item_equal_elem_ptr)(int)= + &List<Item_equal>::elem; +TABLE_LIST* (List<TABLE_LIST>:: *dbug_list_table_list_elem_ptr)(int) = + &List<TABLE_LIST>::elem; + #endif typedef struct st_debug_lock diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index e0ba7d94f9f..2b64239c41b 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -458,6 +458,13 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) */ thd->lex->sql_command= backup.sql_command; + if (opt_readonly && !(thd->security_ctx->master_access & SUPER_ACL) && + !thd->slave_thread) + { + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only"); + goto end; + } + if (add_table_for_trigger(thd, thd->lex->spname, if_exists, & tables)) goto end; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index de6bd59cf7e..0a116b41308 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1,6 +1,6 @@ /* - Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2010, 2011, Monty Program Ab. + Copyright (c) 2000, 2014, Oracle and/or its affiliates. + Copyright (c) 2010, 2014, Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -438,6 +438,13 @@ set_system_variable(THD *thd, struct sys_var_with_base *tmp, if (lex->spcont && tmp->var == Sys_autocommit_ptr) lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT; + if (val && val->type() == Item::FIELD_ITEM && + ((Item_field*)val)->table_name) + { + my_error(ER_WRONG_TYPE_FOR_VAR, MYF(0), tmp->var->name.str); + return TRUE; + } + if (! (var= new set_var(var_type, tmp->var, &tmp->base_name, val))) return TRUE; diff --git a/sql/table.cc b/sql/table.cc index 93fa1949478..db1205b538b 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -3957,7 +3957,7 @@ void TABLE::init(THD *thd, TABLE_LIST *tl) status= STATUS_NO_RECORD; insert_values= 0; fulltext_searched= 0; - file->ha_start_of_new_statement(); + file->ft_handler= 0; #ifdef WITH_WSREP if (file->ht->db_type == DB_TYPE_PARTITION_DB) { diff --git a/sql/table.h b/sql/table.h index 83b2a7a99a9..94b1cf1eff4 100644 --- a/sql/table.h +++ b/sql/table.h @@ -2083,9 +2083,11 @@ struct TABLE_LIST } inline void set_merged_derived() { + DBUG_ENTER("set_merged_derived"); derived_type= ((derived_type & DTYPE_MASK) | DTYPE_TABLE | DTYPE_MERGE); set_check_merged(); + DBUG_VOID_RETURN; } inline bool is_materialized_derived() { @@ -2093,9 +2095,11 @@ struct TABLE_LIST } void set_materialized_derived() { + DBUG_ENTER("set_materialized_derived"); derived_type= ((derived_type & DTYPE_MASK) | DTYPE_TABLE | DTYPE_MATERIALIZE); set_check_materialized(); + DBUG_VOID_RETURN; } inline bool is_multitable() { diff --git a/sql/unireg.cc b/sql/unireg.cc index edcfe9eb934..528c3025c57 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -971,7 +971,7 @@ static bool pack_fields(File file, List<Create_field> &create_fields, while ((field=it++)) { char *pos= strmov((char*) buff,field->field_name); - *pos++=NAMES_SEP_CHAR; + * (uchar*) pos++= (uchar) NAMES_SEP_CHAR; if (i == create_fields.elements-1) *pos++=0; if (mysql_file_write(file, buff, (size_t) (pos-(char*) buff), MYF_RW)) |