summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/filesort.cc21
-rw-r--r--sql/ha_partition.cc146
-rw-r--r--sql/ha_partition.h23
-rw-r--r--sql/handler.cc7
-rw-r--r--sql/handler.h18
-rw-r--r--sql/item.cc2
-rw-r--r--sql/item.h2
-rw-r--r--sql/item_strfunc.h2
-rw-r--r--sql/log_event.cc83
-rw-r--r--sql/log_event.h16
-rw-r--r--sql/mysqld.cc14
-rw-r--r--sql/mysqld.h2
-rw-r--r--sql/protocol.cc11
-rw-r--r--sql/protocol.h8
-rw-r--r--sql/share/charsets/Index.xml1
-rw-r--r--sql/share/charsets/ascii.xml1
-rw-r--r--sql/share/charsets/cp1250.xml1
-rw-r--r--sql/share/charsets/cp1256.xml1
-rw-r--r--sql/share/charsets/cp1257.xml1
-rw-r--r--sql/share/charsets/cp850.xml1
-rw-r--r--sql/share/charsets/cp866.xml1
-rw-r--r--sql/share/charsets/dec8.xml1
-rw-r--r--sql/share/charsets/geostd8.xml1
-rw-r--r--sql/share/charsets/greek.xml1
-rw-r--r--sql/share/charsets/hebrew.xml1
-rw-r--r--sql/share/charsets/hp8.xml1
-rw-r--r--sql/share/charsets/keybcs2.xml1
-rw-r--r--sql/share/charsets/koi8r.xml1
-rw-r--r--sql/share/charsets/koi8u.xml1
-rw-r--r--sql/share/charsets/languages.html1
-rw-r--r--sql/share/charsets/latin1.xml1
-rw-r--r--sql/share/charsets/latin2.xml1
-rw-r--r--sql/share/charsets/latin5.xml1
-rw-r--r--sql/share/charsets/latin7.xml1
-rw-r--r--sql/share/charsets/macce.xml1
-rw-r--r--sql/share/charsets/macroman.xml1
-rw-r--r--sql/share/charsets/swe7.xml1
-rw-r--r--sql/slave.cc3
-rw-r--r--sql/sp_head.cc3
-rw-r--r--sql/sql_acl.cc7
-rw-r--r--sql/sql_audit.cc4
-rw-r--r--sql/sql_audit.h12
-rw-r--r--sql/sql_base.cc11
-rw-r--r--sql/sql_class.cc10
-rw-r--r--sql/sql_class.h22
-rw-r--r--sql/sql_derived.cc50
-rw-r--r--sql/sql_list.h9
-rw-r--r--sql/sql_plugin.cc15
-rw-r--r--sql/sql_select.cc33
-rw-r--r--sql/sql_show.cc184
-rw-r--r--sql/sql_state.c1
-rw-r--r--sql/sql_table.cc2
-rw-r--r--sql/sql_test.cc9
-rw-r--r--sql/sql_trigger.cc7
-rw-r--r--sql/sql_yacc.yy11
-rw-r--r--sql/table.cc2
-rw-r--r--sql/table.h4
-rw-r--r--sql/unireg.cc2
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))