summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorMichael Widenius <monty@mysql.com>2010-11-30 23:11:03 +0200
committerMichael Widenius <monty@mysql.com>2010-11-30 23:11:03 +0200
commit1e5061fe3be981d6f685a2865fd1e2bcd3fcc23a (patch)
treea0c58838a4dd7bdf2ed4d739563da27727ada7b0 /sql
parentb2e979d868d5d5964d58c97ed9580e07f6123217 (diff)
parent6f279f40145624c1ffab06c63521f96ce4ac3a02 (diff)
downloadmariadb-git-1e5061fe3be981d6f685a2865fd1e2bcd3fcc23a.tar.gz
merge with 5.1
Diffstat (limited to 'sql')
-rw-r--r--sql/create_options.cc3
-rw-r--r--sql/ha_ndbcluster.cc9
-rw-r--r--sql/ha_partition.cc107
-rw-r--r--sql/ha_partition.h11
-rw-r--r--sql/handler.cc10
-rw-r--r--sql/item.cc13
-rw-r--r--sql/item.h2
-rw-r--r--sql/item_cmpfunc.cc86
-rw-r--r--sql/item_func.cc28
-rw-r--r--sql/item_func.h2
-rw-r--r--sql/item_strfunc.cc43
-rw-r--r--sql/item_subselect.cc86
-rw-r--r--sql/item_sum.cc6
-rw-r--r--sql/item_timefunc.cc4
-rw-r--r--sql/item_timefunc.h1
-rw-r--r--sql/lock.cc8
-rw-r--r--sql/log.cc74
-rw-r--r--sql/log_event.cc59
-rw-r--r--sql/log_event.h8
-rw-r--r--sql/my_decimal.h2
-rw-r--r--sql/mysql_priv.h3
-rw-r--r--sql/net_serv.cc12
-rw-r--r--sql/opt_range.cc114
-rw-r--r--sql/opt_range.h12
-rw-r--r--sql/rpl_record.cc2
-rw-r--r--sql/rpl_rli.h10
-rw-r--r--sql/set_var.cc2
-rw-r--r--sql/share/Makefile.am3
-rw-r--r--sql/slave.cc78
-rw-r--r--sql/sql_acl.cc17
-rw-r--r--sql/sql_base.cc2
-rw-r--r--sql/sql_cache.cc61
-rw-r--r--sql/sql_class.cc40
-rw-r--r--sql/sql_class.h29
-rw-r--r--sql/sql_db.cc6
-rw-r--r--sql/sql_help.cc2
-rw-r--r--sql/sql_insert.cc4
-rw-r--r--sql/sql_lex.cc6
-rw-r--r--sql/sql_load.cc2
-rw-r--r--sql/sql_parse.cc17
-rw-r--r--sql/sql_partition.cc4
-rw-r--r--sql/sql_prepare.cc4
-rw-r--r--sql/sql_select.cc63
-rw-r--r--sql/sql_string.h10
-rw-r--r--sql/sql_table.cc6
-rw-r--r--sql/sql_trigger.cc9
-rw-r--r--sql/sql_union.cc9
-rw-r--r--sql/sql_update.cc46
-rw-r--r--sql/sql_yacc.yy19
-rw-r--r--sql/table.cc10
-rw-r--r--sql/table.h1
51 files changed, 875 insertions, 290 deletions
diff --git a/sql/create_options.cc b/sql/create_options.cc
index 4478fc14791..a7124310279 100644
--- a/sql/create_options.cc
+++ b/sql/create_options.cc
@@ -187,7 +187,8 @@ static bool set_one_value(ha_create_table_option *opt,
*val= num;
DBUG_RETURN(0);
}
- if (*end) *end++;
+ if (*end)
+ end++;
start= end;
num++;
}
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 782b77eac51..b7b7cdf1cce 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -6269,8 +6269,7 @@ void ha_ndbcluster::get_auto_increment(ulonglong offset, ulonglong increment,
Ndb_tuple_id_range_guard g(m_share);
if ((m_skip_auto_increment &&
ndb->readAutoIncrementValue(m_table, g.range, auto_value)) ||
- ndb->getAutoIncrementValue(m_table, g.range, auto_value, cache_size,
- increment, offset))
+ ndb->getAutoIncrementValue(m_table, g.range, auto_value, cache_size, increment, offset))
{
if (--retries &&
ndb->getNdbError().status == NdbError::TemporaryError)
@@ -9919,10 +9918,8 @@ bool ha_ndbcluster::check_if_incompatible_data(HA_CREATE_INFO *create_info,
{
Field *field= table->field[i];
const NDBCOL *col= tab->getColumn(i);
- if ((col->getStorageType() == NDB_STORAGETYPE_MEMORY &&
- create_info->storage_media != HA_SM_MEMORY) ||
- (col->getStorageType() == NDB_STORAGETYPE_DISK &&
- create_info->storage_media != HA_SM_DISK))
+ if ((col->getStorageType() == NDB_STORAGETYPE_MEMORY && create_info->storage_media != HA_SM_MEMORY) ||
+ (col->getStorageType() == NDB_STORAGETYPE_DISK && create_info->storage_media != HA_SM_DISK))
{
DBUG_PRINT("info", ("Column storage media is changed"));
DBUG_RETURN(COMPATIBLE_DATA_NO);
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index a27dfc0e851..e7de3fb5289 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -233,6 +233,8 @@ void ha_partition::init_handler_variables()
m_innodb= FALSE;
m_extra_cache= FALSE;
m_extra_cache_size= 0;
+ m_extra_prepare_for_update= FALSE;
+ m_extra_cache_part_id= NO_CURRENT_PART_ID;
m_handler_status= handler_not_initialized;
m_low_byte_first= 1;
m_part_field_array= NULL;
@@ -2452,6 +2454,21 @@ err1:
/****************************************************************************
MODULE open/close object
****************************************************************************/
+
+
+/**
+ A destructor for partition-specific TABLE_SHARE data.
+*/
+
+void ha_data_partition_destroy(void *ha_data)
+{
+ if (ha_data)
+ {
+ HA_DATA_PARTITION *ha_part_data= (HA_DATA_PARTITION*) ha_data;
+ pthread_mutex_destroy(&ha_part_data->LOCK_auto_inc);
+ }
+}
+
/*
Open handler object
@@ -2608,6 +2625,8 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
}
DBUG_PRINT("info", ("table_share->ha_data 0x%p", ha_data));
bzero(ha_data, sizeof(HA_DATA_PARTITION));
+ table_share->ha_data_destroy= ha_data_partition_destroy;
+ VOID(pthread_mutex_init(&ha_data->LOCK_auto_inc, MY_MUTEX_INIT_FAST));
}
if (is_not_tmp_table)
pthread_mutex_unlock(&table_share->mutex);
@@ -4222,8 +4241,12 @@ int ha_partition::index_read_idx_map(uchar *buf, uint index,
get_partition_set(table, buf, index, &m_start_key, &m_part_spec);
- /* How can it be more than one partition with the current use? */
- DBUG_ASSERT(m_part_spec.start_part == m_part_spec.end_part);
+ /*
+ We have either found exactly 1 partition
+ (in which case start_part == end_part)
+ or no matching partitions (start_part > end_part)
+ */
+ DBUG_ASSERT(m_part_spec.start_part >= m_part_spec.end_part);
for (part= m_part_spec.start_part; part <= m_part_spec.end_part; part++)
{
@@ -4461,6 +4484,7 @@ int ha_partition::partition_scan_set_up(uchar * buf, bool idx_read_flag)
key not found.
*/
DBUG_PRINT("info", ("scan with no partition to scan"));
+ table->status= STATUS_NOT_FOUND;
DBUG_RETURN(HA_ERR_END_OF_FILE);
}
if (m_part_spec.start_part == m_part_spec.end_part)
@@ -4485,6 +4509,7 @@ int ha_partition::partition_scan_set_up(uchar * buf, bool idx_read_flag)
if (start_part == MY_BIT_NONE)
{
DBUG_PRINT("info", ("scan with no partition to scan"));
+ table->status= STATUS_NOT_FOUND;
DBUG_RETURN(HA_ERR_END_OF_FILE);
}
if (start_part > m_part_spec.start_part)
@@ -5391,9 +5416,6 @@ void ha_partition::get_dynamic_partition_info(PARTITION_INFO *stat_info,
when performing the sequential scan we will check this recorded value
and call extra_opt whenever we start scanning a new partition.
- monty: Neads to be fixed so that it's passed to all handlers when we
- move to another partition during table scan.
-
HA_EXTRA_NO_CACHE:
When performing a UNION SELECT HA_EXTRA_NO_CACHE is called from the
flush method in the select_union class.
@@ -5405,7 +5427,7 @@ void ha_partition::get_dynamic_partition_info(PARTITION_INFO *stat_info,
for. If no cache is in use they will quickly return after finding
this out. And we also ensure that all caches are disabled and no one
is left by mistake.
- In the future this call will probably be deleted an we will instead call
+ In the future this call will probably be deleted and we will instead call
::reset();
HA_EXTRA_WRITE_CACHE:
@@ -5417,8 +5439,9 @@ void ha_partition::get_dynamic_partition_info(PARTITION_INFO *stat_info,
This is called as part of a multi-table update. When the table to be
updated is also scanned then this informs MyISAM handler to drop any
caches if dynamic records are used (fixed size records do not care
- about this call). We pass this along to all underlying MyISAM handlers
- and ignore it for the rest.
+ about this call). We pass this along to the first partition to scan, and
+ flag that it is to be called after HA_EXTRA_CACHE when moving to the next
+ partition to scan.
HA_EXTRA_PREPARE_FOR_DROP:
Only used by MyISAM, called in preparation for a DROP TABLE.
@@ -5565,9 +5588,23 @@ int ha_partition::extra(enum ha_extra_function operation)
/* Category 3), used by MyISAM handlers */
case HA_EXTRA_PREPARE_FOR_RENAME:
DBUG_RETURN(prepare_for_rename());
+ break;
+ case HA_EXTRA_PREPARE_FOR_UPDATE:
+ /*
+ Needs to be run on the first partition in the range now, and
+ later in late_extra_cache, when switching to a new partition to scan.
+ */
+ m_extra_prepare_for_update= TRUE;
+ if (m_part_spec.start_part != NO_CURRENT_PART_ID)
+ {
+ if (!m_extra_cache)
+ m_extra_cache_part_id= m_part_spec.start_part;
+ DBUG_ASSERT(m_extra_cache_part_id == m_part_spec.start_part);
+ VOID(m_file[m_part_spec.start_part]->extra(HA_EXTRA_PREPARE_FOR_UPDATE));
+ }
+ break;
case HA_EXTRA_NORMAL:
case HA_EXTRA_QUICK:
- case HA_EXTRA_PREPARE_FOR_UPDATE:
case HA_EXTRA_FORCE_REOPEN:
case HA_EXTRA_PREPARE_FOR_DROP:
case HA_EXTRA_FLUSH_CACHE:
@@ -5588,10 +5625,22 @@ int ha_partition::extra(enum ha_extra_function operation)
break;
}
case HA_EXTRA_NO_CACHE:
+ {
+ int ret= 0;
+ if (m_extra_cache_part_id != NO_CURRENT_PART_ID)
+ ret= m_file[m_extra_cache_part_id]->extra(HA_EXTRA_NO_CACHE);
+ m_extra_cache= FALSE;
+ m_extra_cache_size= 0;
+ m_extra_prepare_for_update= FALSE;
+ m_extra_cache_part_id= NO_CURRENT_PART_ID;
+ DBUG_RETURN(ret);
+ }
case HA_EXTRA_WRITE_CACHE:
{
m_extra_cache= FALSE;
m_extra_cache_size= 0;
+ m_extra_prepare_for_update= FALSE;
+ m_extra_cache_part_id= NO_CURRENT_PART_ID;
DBUG_RETURN(loop_extra(operation));
}
case HA_EXTRA_IGNORE_NO_KEY:
@@ -5719,6 +5768,7 @@ int ha_partition::extra_opt(enum ha_extra_function operation, ulong cachesize)
void ha_partition::prepare_extra_cache(uint cachesize)
{
DBUG_ENTER("ha_partition::prepare_extra_cache()");
+ DBUG_PRINT("info", ("cachesize %u", cachesize));
m_extra_cache= TRUE;
m_extra_cache_size= cachesize;
@@ -5777,16 +5827,18 @@ int ha_partition::loop_extra(enum ha_extra_function operation)
{
int result= 0, tmp;
handler **file;
+ bool is_select;
DBUG_ENTER("ha_partition::loop_extra()");
- /*
- TODO, 5.2: this is where you could possibly add optimisations to add the
- bitmap _if_ a SELECT.
- */
+ is_select= (thd_sql_command(ha_thd()) == SQLCOM_SELECT);
for (file= m_file; *file; file++)
{
- if ((tmp= (*file)->extra(operation)))
- result= tmp;
+ if (!is_select ||
+ bitmap_is_set(&(m_part_info->used_partitions), file - m_file))
+ {
+ if ((tmp= (*file)->extra(operation)))
+ result= tmp;
+ }
}
DBUG_RETURN(result);
}
@@ -5807,14 +5859,25 @@ void ha_partition::late_extra_cache(uint partition_id)
{
handler *file;
DBUG_ENTER("ha_partition::late_extra_cache");
+ DBUG_PRINT("info", ("extra_cache %u prepare %u partid %u size %u",
+ m_extra_cache, m_extra_prepare_for_update,
+ partition_id, m_extra_cache_size));
- if (!m_extra_cache)
+ if (!m_extra_cache && !m_extra_prepare_for_update)
DBUG_VOID_RETURN;
file= m_file[partition_id];
- if (m_extra_cache_size == 0)
- VOID(file->extra(HA_EXTRA_CACHE));
- else
- VOID(file->extra_opt(HA_EXTRA_CACHE, m_extra_cache_size));
+ if (m_extra_cache)
+ {
+ if (m_extra_cache_size == 0)
+ VOID(file->extra(HA_EXTRA_CACHE));
+ else
+ VOID(file->extra_opt(HA_EXTRA_CACHE, m_extra_cache_size));
+ }
+ if (m_extra_prepare_for_update)
+ {
+ VOID(file->extra(HA_EXTRA_PREPARE_FOR_UPDATE));
+ }
+ m_extra_cache_part_id= partition_id;
DBUG_VOID_RETURN;
}
@@ -5835,10 +5898,12 @@ void ha_partition::late_extra_no_cache(uint partition_id)
handler *file;
DBUG_ENTER("ha_partition::late_extra_no_cache");
- if (!m_extra_cache)
+ if (!m_extra_cache && !m_extra_prepare_for_update)
DBUG_VOID_RETURN;
file= m_file[partition_id];
VOID(file->extra(HA_EXTRA_NO_CACHE));
+ DBUG_ASSERT(partition_id == m_extra_cache_part_id);
+ m_extra_cache_part_id= NO_CURRENT_PART_ID;
DBUG_VOID_RETURN;
}
diff --git a/sql/ha_partition.h b/sql/ha_partition.h
index 1a9ec5bbf70..1489ead8b5a 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -44,6 +44,7 @@ typedef struct st_partition_share
typedef struct st_ha_data_partition
{
ulonglong next_auto_inc_val; /**< first non reserved value */
+ pthread_mutex_t LOCK_auto_inc;
bool auto_inc_initialized;
} HA_DATA_PARTITION;
@@ -153,6 +154,10 @@ private:
*/
bool m_extra_cache;
uint m_extra_cache_size;
+ /* The same goes for HA_EXTRA_PREPARE_FOR_UPDATE */
+ bool m_extra_prepare_for_update;
+ /* Which partition has active cache */
+ uint m_extra_cache_part_id;
void init_handler_variables();
/*
@@ -942,8 +947,9 @@ private:
DBUG_ASSERT(table_share->ha_data && !auto_increment_lock);
if(table_share->tmp_table == NO_TMP_TABLE)
{
+ HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data;
auto_increment_lock= TRUE;
- pthread_mutex_lock(&table_share->mutex);
+ pthread_mutex_lock(&ha_data->LOCK_auto_inc);
}
}
virtual void unlock_auto_increment()
@@ -956,7 +962,8 @@ private:
*/
if(auto_increment_lock && !auto_increment_safe_stmt_log_lock)
{
- pthread_mutex_unlock(&table_share->mutex);
+ HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data;
+ pthread_mutex_unlock(&ha_data->LOCK_auto_inc);
auto_increment_lock= FALSE;
}
}
diff --git a/sql/handler.cc b/sql/handler.cc
index 570ee66b172..e851d9248c2 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -1135,7 +1135,7 @@ int ha_commit_trans(THD *thd, bool all)
uint rw_ha_count;
bool rw_trans;
- DBUG_EXECUTE_IF("crash_commit_before", abort(););
+ DBUG_EXECUTE_IF("crash_commit_before", DBUG_SUICIDE(););
/* Close all cursors that can not survive COMMIT */
if (is_real_trans) /* not a statement commit */
@@ -1187,7 +1187,7 @@ int ha_commit_trans(THD *thd, bool all)
}
status_var_increment(thd->status_var.ha_prepare_count);
}
- DBUG_EXECUTE_IF("crash_commit_after_prepare", DBUG_ABORT(););
+ DBUG_EXECUTE_IF("crash_commit_after_prepare", DBUG_SUICIDE(););
if (error || (is_real_trans && xid &&
(error= !(cookie= tc_log->log_xid(thd, xid)))))
{
@@ -1195,13 +1195,13 @@ int ha_commit_trans(THD *thd, bool all)
error= 1;
goto end;
}
- DBUG_EXECUTE_IF("crash_commit_after_log", DBUG_ABORT(););
+ DBUG_EXECUTE_IF("crash_commit_after_log", DBUG_SUICIDE(););
}
error=ha_commit_one_phase(thd, all) ? (cookie ? 2 : 1) : 0;
- DBUG_EXECUTE_IF("crash_commit_before_unlog", DBUG_ABORT(););
+ DBUG_EXECUTE_IF("crash_commit_before_unlog", DBUG_SUICIDE(););
if (cookie)
tc_log->unlog(cookie, xid);
- DBUG_EXECUTE_IF("crash_commit_after", DBUG_ABORT(););
+ DBUG_EXECUTE_IF("crash_commit_after", DBUG_SUICIDE(););
end:
if (rw_trans)
start_waiting_global_read_lock(thd);
diff --git a/sql/item.cc b/sql/item.cc
index 090286b179c..2fb2f5e91e2 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -380,6 +380,7 @@ Item::Item():
{
marker= 0;
maybe_null=null_value=with_sum_func=unsigned_flag=0;
+ in_rollup= 0;
decimals= 0; max_length= 0;
with_subselect= 0;
cmp_context= IMPOSSIBLE_RESULT;
@@ -420,6 +421,7 @@ Item::Item(THD *thd, Item *item):
marker(item->marker),
decimals(item->decimals),
maybe_null(item->maybe_null),
+ in_rollup(item->in_rollup),
null_value(item->null_value),
unsigned_flag(item->unsigned_flag),
with_sum_func(item->with_sum_func),
@@ -7034,14 +7036,14 @@ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item)
enum_field_types field_type= field->type();
- if (field_type == MYSQL_TYPE_DATE || field_type == MYSQL_TYPE_DATETIME)
+ if (field_type == MYSQL_TYPE_DATE || field_type == MYSQL_TYPE_DATETIME ||
+ field_type == MYSQL_TYPE_TIMESTAMP)
{
enum_mysql_timestamp_type type= MYSQL_TIMESTAMP_ERROR;
if (field_type == MYSQL_TYPE_DATE)
type= MYSQL_TIMESTAMP_DATE;
-
- if (field_type == MYSQL_TYPE_DATETIME)
+ else
type= MYSQL_TIMESTAMP_DATETIME;
const char *field_name= field->field_name;
@@ -7468,9 +7470,12 @@ bool Item_cache_row::null_inside()
void Item_cache_row::bring_value()
{
+ if (!example)
+ return;
+ example->bring_value();
+ null_value= example->null_value;
for (uint i= 0; i < item_count; i++)
values[i]->bring_value();
- return;
}
diff --git a/sql/item.h b/sql/item.h
index f11c9d88841..dcfe1b58122 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -536,6 +536,8 @@ public:
int8 marker;
uint8 decimals;
bool maybe_null; /* If item may be null */
+ bool in_rollup; /* If used in GROUP BY list
+ of a query with ROLLUP */
bool null_value; /* if item is null */
bool unsigned_flag;
bool with_sum_func;
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 746eb482d5a..d7fa6cba030 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -1596,6 +1596,13 @@ int Arg_comparator::compare_row()
bool was_null= 0;
(*a)->bring_value();
(*b)->bring_value();
+
+ if ((*a)->null_value || (*b)->null_value)
+ {
+ owner->null_value= 1;
+ return -1;
+ }
+
uint n= (*a)->cols();
for (uint i= 0; i<n; i++)
{
@@ -1764,6 +1771,76 @@ bool Item_in_optimizer::fix_fields(THD *thd, Item **ref)
}
+/**
+ The implementation of optimized \<outer expression\> [NOT] IN \<subquery\>
+ predicates. The implementation works as follows.
+
+ For the current value of the outer expression
+
+ - If it contains only NULL values, the original (before rewrite by the
+ Item_in_subselect rewrite methods) inner subquery is non-correlated and
+ was previously executed, there is no need to re-execute it, and the
+ previous return value is returned.
+
+ - If it contains NULL values, check if there is a partial match for the
+ inner query block by evaluating it. For clarity we repeat here the
+ transformation previously performed on the sub-query. The expression
+
+ <tt>
+ ( oc_1, ..., oc_n )
+ \<in predicate\>
+ ( SELECT ic_1, ..., ic_n
+ FROM \<table\>
+ WHERE \<inner where\>
+ )
+ </tt>
+
+ was transformed into
+
+ <tt>
+ ( oc_1, ..., oc_n )
+ \<in predicate\>
+ ( SELECT ic_1, ..., ic_n
+ FROM \<table\>
+ WHERE \<inner where\> AND ... ( ic_k = oc_k OR ic_k IS NULL )
+ HAVING ... NOT ic_k IS NULL
+ )
+ </tt>
+
+ The evaluation will now proceed according to special rules set up
+ elsewhere. These rules include:
+
+ - The HAVING NOT \<inner column\> IS NULL conditions added by the
+ aforementioned rewrite methods will detect whether they evaluated (and
+ rejected) a NULL value and if so, will cause the subquery to evaluate
+ to NULL.
+
+ - The added WHERE and HAVING conditions are present only for those inner
+ columns that correspond to outer column that are not NULL at the moment.
+
+ - If there is an eligible index for executing the subquery, the special
+ access method "Full scan on NULL key" is employed which ensures that
+ the inner query will detect if there are NULL values resulting from the
+ inner query. This access method will quietly resort to table scan if it
+ needs to find NULL values as well.
+
+ - Under these conditions, the sub-query need only be evaluated in order to
+ find out whether it produced any rows.
+
+ - If it did, we know that there was a partial match since there are
+ NULL values in the outer row expression.
+
+ - If it did not, the result is FALSE or UNKNOWN. If at least one of the
+ HAVING sub-predicates rejected a NULL value corresponding to an outer
+ non-NULL, and hence the inner query block returns UNKNOWN upon
+ evaluation, there was a partial match and the result is UNKNOWN.
+
+ - If it contains no NULL values, the call is forwarded to the inner query
+ block.
+
+ @see Item_in_subselect::val_bool()
+ @see Item_is_not_null_test::val_int()
+ */
longlong Item_in_optimizer::val_int()
{
bool tmp;
@@ -1817,7 +1894,7 @@ longlong Item_in_optimizer::val_int()
all_left_cols_null= false;
}
- if (!((Item_in_subselect*)args[1])->is_correlated &&
+ if (!item_subs->is_correlated &&
all_left_cols_null && result_for_null_param != UNKNOWN)
{
/*
@@ -1831,8 +1908,11 @@ longlong Item_in_optimizer::val_int()
else
{
/* The subquery has to be evaluated */
- (void) args[1]->val_bool_result();
- null_value= !item_subs->engine->no_rows();
+ (void) item_subs->val_bool_result();
+ if (item_subs->engine->no_rows())
+ null_value= item_subs->null_value;
+ else
+ null_value= TRUE;
if (all_left_cols_null)
result_for_null_param= null_value;
}
diff --git a/sql/item_func.cc b/sql/item_func.cc
index b53f9604963..389f2a25a2a 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -1355,9 +1355,13 @@ longlong Item_func_int_div::val_int()
signal_divide_by_null();
return 0;
}
- return (unsigned_flag ?
- (ulonglong) value / (ulonglong) val2 :
- value / val2);
+
+ if (unsigned_flag)
+ return ((ulonglong) value / (ulonglong) val2);
+ else if (value == LONGLONG_MIN && val2 == -1)
+ return LONGLONG_MIN;
+ else
+ return value / val2;
}
@@ -1391,9 +1395,9 @@ longlong Item_func_mod::int_op()
if (args[0]->unsigned_flag)
result= args[1]->unsigned_flag ?
((ulonglong) value) % ((ulonglong) val2) : ((ulonglong) value) % val2;
- else
- result= args[1]->unsigned_flag ?
- value % ((ulonglong) val2) : value % val2;
+ else result= args[1]->unsigned_flag ?
+ value % ((ulonglong) val2) :
+ (val2 == -1) ? 0 : value % val2;
return result;
}
@@ -4705,7 +4709,7 @@ void Item_func_get_user_var::fix_length_and_dec()
decimals=0;
break;
case STRING_RESULT:
- max_length= MAX_BLOB_WIDTH;
+ max_length= MAX_BLOB_WIDTH - 1;
break;
case DECIMAL_RESULT:
max_length= DECIMAL_MAX_STR_LENGTH;
@@ -5340,7 +5344,17 @@ void Item_func_match::init_search(bool no_order)
/* Check if init_search() has been called before */
if (ft_handler)
+ {
+ /*
+ We should reset ft_handler as it is cleaned up
+ on destruction of FT_SELECT object
+ (necessary in case of re-execution of subquery).
+ TODO: FT_SELECT should not clean up ft_handler.
+ */
+ if (join_key)
+ table->file->ft_handler= ft_handler;
DBUG_VOID_RETURN;
+ }
if (key == NO_SUCH_KEY)
{
diff --git a/sql/item_func.h b/sql/item_func.h
index 9d64bcad490..792f31d4f39 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -1583,7 +1583,7 @@ public:
join_key(0), ft_handler(0), table(0), master(0), concat_ws(0) { }
void cleanup()
{
- DBUG_ENTER("Item_func_match");
+ DBUG_ENTER("Item_func_match::cleanup");
Item_real_func::cleanup();
if (!master && ft_handler)
ft_handler->please->close_search(ft_handler);
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index cafabe9a3ee..aebbc21b0fc 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1014,6 +1014,20 @@ String *Item_func_insert::val_str(String *str)
if ((length < 0) || (length > res->length()))
length= res->length();
+ /*
+ There is one exception not handled (intentionaly) by the character set
+ aggregation code. If one string is strong side and is binary, and
+ another one is weak side and is a multi-byte character string,
+ then we need to operate on the second string in terms on bytes when
+ calling ::numchars() and ::charpos(), rather than in terms of characters.
+ Lets substitute its character set to binary.
+ */
+ if (collation.collation == &my_charset_bin)
+ {
+ res->set_charset(&my_charset_bin);
+ res2->set_charset(&my_charset_bin);
+ }
+
/* start and length are now sufficiently valid to pass to charpos function */
start= res->charpos((int) start);
length= res->charpos((int) length, (uint32) start);
@@ -2515,6 +2529,20 @@ String *Item_func_rpad::val_str(String *str)
/* Set here so that rest of code sees out-of-bound value as such. */
if ((ulonglong) count > INT_MAX32)
count= INT_MAX32;
+ /*
+ There is one exception not handled (intentionaly) by the character set
+ aggregation code. If one string is strong side and is binary, and
+ another one is weak side and is a multi-byte character string,
+ then we need to operate on the second string in terms on bytes when
+ calling ::numchars() and ::charpos(), rather than in terms of characters.
+ Lets substitute its character set to binary.
+ */
+ if (collation.collation == &my_charset_bin)
+ {
+ res->set_charset(&my_charset_bin);
+ rpad->set_charset(&my_charset_bin);
+ }
+
if (count <= (res_char_length= res->numchars()))
{ // String to pad is big enough
res->length(res->charpos((int) count)); // Shorten result if longer
@@ -2617,6 +2645,20 @@ String *Item_func_lpad::val_str(String *str)
if ((ulonglong) count > INT_MAX32)
count= INT_MAX32;
+ /*
+ There is one exception not handled (intentionaly) by the character set
+ aggregation code. If one string is strong side and is binary, and
+ another one is weak side and is a multi-byte character string,
+ then we need to operate on the second string in terms on bytes when
+ calling ::numchars() and ::charpos(), rather than in terms of characters.
+ Lets substitute its character set to binary.
+ */
+ if (collation.collation == &my_charset_bin)
+ {
+ res->set_charset(&my_charset_bin);
+ pad->set_charset(&my_charset_bin);
+ }
+
res_char_length= res->numchars();
if (count <= res_char_length)
@@ -3094,6 +3136,7 @@ String* Item_func_inet_ntoa::val_str(String* str)
if ((null_value= (args[0]->null_value || n > (ulonglong) LL(4294967295))))
return 0; // Null value
+ str->set_charset(collation.collation);
str->length(0);
int4store(buf,n);
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index a82c93304e6..6d3a4c66649 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -48,7 +48,7 @@ Item_subselect::Item_subselect():
item value is NULL if select_subselect not changed this value
(i.e. some rows will be found returned)
*/
- null_value= 1;
+ null_value= TRUE;
}
@@ -452,9 +452,9 @@ void Item_maxmin_subselect::print(String *str, enum_query_type query_type)
void Item_singlerow_subselect::reset()
{
eliminated= FALSE;
- null_value= 1;
+ null_value= TRUE;
if (value)
- value->null_value= 1;
+ value->null_value= TRUE;
}
@@ -591,7 +591,10 @@ bool Item_singlerow_subselect::null_inside()
void Item_singlerow_subselect::bring_value()
{
- exec();
+ if (!exec() && assigned())
+ null_value= 0;
+ else
+ reset();
}
double Item_singlerow_subselect::val_real()
@@ -599,7 +602,7 @@ double Item_singlerow_subselect::val_real()
DBUG_ASSERT(fixed == 1);
if (!exec() && !value->null_value)
{
- null_value= 0;
+ null_value= FALSE;
return value->val_real();
}
else
@@ -614,7 +617,7 @@ longlong Item_singlerow_subselect::val_int()
DBUG_ASSERT(fixed == 1);
if (!exec() && !value->null_value)
{
- null_value= 0;
+ null_value= FALSE;
return value->val_int();
}
else
@@ -628,7 +631,7 @@ String *Item_singlerow_subselect::val_str(String *str)
{
if (!exec() && !value->null_value)
{
- null_value= 0;
+ null_value= FALSE;
return value->val_str(str);
}
else
@@ -643,7 +646,7 @@ my_decimal *Item_singlerow_subselect::val_decimal(my_decimal *decimal_value)
{
if (!exec() && !value->null_value)
{
- null_value= 0;
+ null_value= FALSE;
return value->val_decimal(decimal_value);
}
else
@@ -658,7 +661,7 @@ bool Item_singlerow_subselect::val_bool()
{
if (!exec() && !value->null_value)
{
- null_value= 0;
+ null_value= FALSE;
return value->val_bool();
}
else
@@ -676,7 +679,7 @@ Item_exists_subselect::Item_exists_subselect(st_select_lex *select_lex):
bool val_bool();
init(select_lex, new select_exists_subselect(this));
max_columns= UINT_MAX;
- null_value= 0; //can't be NULL
+ null_value= FALSE; //can't be NULL
maybe_null= 0; //can't be NULL
value= 0;
DBUG_VOID_RETURN;
@@ -839,15 +842,14 @@ double Item_in_subselect::val_real()
*/
DBUG_ASSERT(0);
DBUG_ASSERT(fixed == 1);
- null_value= 0;
+ null_value= was_null= FALSE;
if (exec())
{
reset();
- null_value= 1;
return 0;
}
if (was_null && !value)
- null_value= 1;
+ null_value= TRUE;
return (double) value;
}
@@ -860,15 +862,14 @@ longlong Item_in_subselect::val_int()
*/
DBUG_ASSERT(0);
DBUG_ASSERT(fixed == 1);
- null_value= 0;
+ null_value= was_null= FALSE;
if (exec())
{
reset();
- null_value= 1;
return 0;
}
if (was_null && !value)
- null_value= 1;
+ null_value= TRUE;
return value;
}
@@ -881,16 +882,15 @@ String *Item_in_subselect::val_str(String *str)
*/
DBUG_ASSERT(0);
DBUG_ASSERT(fixed == 1);
- null_value= 0;
+ null_value= was_null= FALSE;
if (exec())
{
reset();
- null_value= 1;
return 0;
}
if (was_null && !value)
{
- null_value= 1;
+ null_value= TRUE;
return 0;
}
str->set((ulonglong)value, &my_charset_bin);
@@ -901,20 +901,14 @@ String *Item_in_subselect::val_str(String *str)
bool Item_in_subselect::val_bool()
{
DBUG_ASSERT(fixed == 1);
- null_value= 0;
+ null_value= was_null= FALSE;
if (exec())
{
reset();
- /*
- Must mark the IN predicate as NULL so as to make sure an enclosing NOT
- predicate will return FALSE. See the comments in
- subselect_uniquesubquery_engine::copy_ref_key for further details.
- */
- null_value= 1;
return 0;
}
if (was_null && !value)
- null_value= 1;
+ null_value= TRUE;
return value;
}
@@ -925,16 +919,15 @@ my_decimal *Item_in_subselect::val_decimal(my_decimal *decimal_value)
method should not be used
*/
DBUG_ASSERT(0);
- null_value= 0;
+ null_value= was_null= FALSE;
DBUG_ASSERT(fixed == 1);
if (exec())
{
reset();
- null_value= 1;
return 0;
}
if (was_null && !value)
- null_value= 1;
+ null_value= TRUE;
int2my_decimal(E_DEC_FATAL_ERROR, value, 0, decimal_value);
return decimal_value;
}
@@ -1942,19 +1935,28 @@ int subselect_single_select_engine::exec()
DBUG_RETURN(join->error ? join->error : 1);
}
if (!select_lex->uncacheable && thd->lex->describe &&
- !(join->select_options & SELECT_DESCRIBE) &&
- join->need_tmp && item->const_item())
+ !(join->select_options & SELECT_DESCRIBE))
{
- /*
- Force join->join_tmp creation, because this subquery will be replaced
- by a simple select from the materialization temp table by optimize()
- called by EXPLAIN and we need to preserve the initial query structure
- so we can display it.
- */
- select_lex->uncacheable|= UNCACHEABLE_EXPLAIN;
- select_lex->master_unit()->uncacheable|= UNCACHEABLE_EXPLAIN;
- if (join->init_save_join_tab())
- DBUG_RETURN(1); /* purecov: inspected */
+ item->update_used_tables();
+ if (item->const_item())
+ {
+ /*
+ It's necessary to keep original JOIN table because
+ create_sort_index() function may overwrite original
+ JOIN_TAB::type and wrong optimization method can be
+ selected on re-execution.
+ */
+ select_lex->uncacheable|= UNCACHEABLE_EXPLAIN;
+ select_lex->master_unit()->uncacheable|= UNCACHEABLE_EXPLAIN;
+ /*
+ Force join->join_tmp creation, because this subquery will be replaced
+ by a simple select from the materialization temp table by optimize()
+ called by EXPLAIN and we need to preserve the initial query structure
+ so we can display it.
+ */
+ if (join->need_tmp && join->init_save_join_tab())
+ DBUG_RETURN(1); /* purecov: inspected */
+ }
}
if (item->engine_changed)
{
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index f4297f73a10..86d1b693f28 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -3423,8 +3423,6 @@ String* Item_func_group_concat::val_str(String* str)
void Item_func_group_concat::print(String *str, enum_query_type query_type)
{
- /* orig_args is not filled with valid values until fix_fields() */
- Item **pargs= fixed ? orig_args : args;
str->append(STRING_WITH_LEN("group_concat("));
if (distinct)
str->append(STRING_WITH_LEN("distinct "));
@@ -3432,7 +3430,7 @@ void Item_func_group_concat::print(String *str, enum_query_type query_type)
{
if (i)
str->append(',');
- pargs[i]->print(str, query_type);
+ orig_args[i]->print(str, query_type);
}
if (arg_count_order)
{
@@ -3441,7 +3439,7 @@ void Item_func_group_concat::print(String *str, enum_query_type query_type)
{
if (i)
str->append(',');
- pargs[i + arg_count_field]->print(str, query_type);
+ orig_args[i + arg_count_field]->print(str, query_type);
if (order[i]->asc)
str->append(STRING_WITH_LEN(" ASC"));
else
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 57656f30294..443bf3faf6f 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -2277,8 +2277,6 @@ void Item_extract::print(String *str, enum_query_type query_type)
void Item_extract::fix_length_and_dec()
{
- value.alloc(32); // alloc buffer
-
maybe_null=1; // If wrong date
switch (int_type) {
case INTERVAL_YEAR: max_length=4; date_value=1; break;
@@ -2321,6 +2319,8 @@ longlong Item_extract::val_int()
}
else
{
+ char buf[40];
+ String value(buf, sizeof(buf), &my_charset_bin);;
String *res= args[0]->val_str(&value);
if (!res || str_to_time_with_warn(res->ptr(), res->length(), &ltime))
{
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 22df9f34926..49fa87efd7b 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -737,7 +737,6 @@ public:
class Item_extract :public Item_int_func
{
- String value;
bool date_value;
public:
const interval_type int_type; // keep it public
diff --git a/sql/lock.cc b/sql/lock.cc
index 566275c5ea2..e5ea85e7ce7 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -736,7 +736,6 @@ TABLE_LIST *mysql_lock_have_duplicate(THD *thd, TABLE_LIST *needle,
TABLE_LIST *haystack)
{
MYSQL_LOCK *mylock;
- TABLE **lock_tables;
TABLE *table;
TABLE *table2;
THR_LOCK_DATA **lock_locks;
@@ -765,12 +764,11 @@ TABLE_LIST *mysql_lock_have_duplicate(THD *thd, TABLE_LIST *needle,
if (mylock->table_count < 2)
goto end;
- lock_locks= mylock->locks;
- lock_tables= mylock->table;
+ lock_locks= mylock->locks;
/* Prepare table related variables that don't change in loop. */
DBUG_ASSERT((table->lock_position < mylock->table_count) &&
- (table == lock_tables[table->lock_position]));
+ (table == mylock->table[table->lock_position]));
table_lock_data= lock_locks + table->lock_data_start;
end_data= table_lock_data + table->lock_count;
@@ -784,7 +782,7 @@ TABLE_LIST *mysql_lock_have_duplicate(THD *thd, TABLE_LIST *needle,
/* All tables in list must be in lock. */
DBUG_ASSERT((table2->lock_position < mylock->table_count) &&
- (table2 == lock_tables[table2->lock_position]));
+ (table2 == mylock->table[table2->lock_position]));
for (lock_data2= lock_locks + table2->lock_data_start,
end_data2= lock_data2 + table2->lock_count;
diff --git a/sql/log.cc b/sql/log.cc
index 07d9890ff78..e853fedc3d1 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -1252,7 +1252,7 @@ void LOGGER::deactivate_log_handler(THD *thd, uint log_type)
file_log= file_log_handler->get_mysql_log();
break;
default:
- assert(0); // Impossible
+ MY_ASSERT_UNREACHABLE();
}
if (!(*tmp_opt))
@@ -1748,7 +1748,9 @@ static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv)
String log_query;
if (log_query.append(STRING_WITH_LEN("SAVEPOINT ")) ||
- log_query.append(thd->lex->ident.str, thd->lex->ident.length))
+ log_query.append("`") ||
+ log_query.append(thd->lex->ident.str, thd->lex->ident.length) ||
+ log_query.append("`"))
DBUG_RETURN(1);
int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
Query_log_event qinfo(thd, log_query.c_ptr_safe(), log_query.length(),
@@ -1770,7 +1772,9 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv)
{
String log_query;
if (log_query.append(STRING_WITH_LEN("ROLLBACK TO ")) ||
- log_query.append(thd->lex->ident.str, thd->lex->ident.length))
+ log_query.append("`") ||
+ log_query.append(thd->lex->ident.str, thd->lex->ident.length) ||
+ log_query.append("`"))
DBUG_RETURN(1);
int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
Query_log_event qinfo(thd, log_query.c_ptr_safe(), log_query.length(),
@@ -2657,7 +2661,7 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
sql_print_error("MSYQL_BIN_LOG::open failed to sync the index file.");
DBUG_RETURN(1);
}
- DBUG_EXECUTE_IF("crash_create_non_critical_before_update_index", abort(););
+ DBUG_EXECUTE_IF("crash_create_non_critical_before_update_index", DBUG_SUICIDE(););
#endif
write_error= 0;
@@ -2754,7 +2758,7 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
if (write_file_name_to_index_file)
{
#ifdef HAVE_REPLICATION
- DBUG_EXECUTE_IF("crash_create_critical_before_update_index", abort(););
+ DBUG_EXECUTE_IF("crash_create_critical_before_update_index", DBUG_SUICIDE(););
#endif
DBUG_ASSERT(my_b_inited(&index_file) != 0);
@@ -2773,7 +2777,7 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
goto err;
#ifdef HAVE_REPLICATION
- DBUG_EXECUTE_IF("crash_create_after_update_index", abort(););
+ DBUG_EXECUTE_IF("crash_create_after_update_index", DBUG_SUICIDE(););
#endif
}
}
@@ -3225,7 +3229,7 @@ int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included)
/* Store where we are in the new file for the execution thread */
flush_relay_log_info(rli);
- DBUG_EXECUTE_IF("crash_before_purge_logs", abort(););
+ DBUG_EXECUTE_IF("crash_before_purge_logs", DBUG_SUICIDE(););
pthread_mutex_lock(&rli->log_space_lock);
rli->relay_log.purge_logs(to_purge_if_included, included,
@@ -3353,7 +3357,7 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log,
break;
}
- DBUG_EXECUTE_IF("crash_purge_before_update_index", abort(););
+ DBUG_EXECUTE_IF("crash_purge_before_update_index", DBUG_SUICIDE(););
if ((error= sync_purge_index_file()))
{
@@ -3368,7 +3372,7 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log,
goto err;
}
- DBUG_EXECUTE_IF("crash_purge_critical_after_update_index", abort(););
+ DBUG_EXECUTE_IF("crash_purge_critical_after_update_index", DBUG_SUICIDE(););
err:
/* Read each entry from purge_index_file and delete the file. */
@@ -3378,7 +3382,7 @@ err:
" that would be purged.");
close_purge_index_file();
- DBUG_EXECUTE_IF("crash_purge_non_critical_after_update_index", abort(););
+ DBUG_EXECUTE_IF("crash_purge_non_critical_after_update_index", DBUG_SUICIDE(););
if (need_mutex)
pthread_mutex_unlock(&LOCK_index);
@@ -4899,7 +4903,7 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event,
DBUG_PRINT("info", ("error writing binlog cache: %d",
write_error));
DBUG_PRINT("info", ("crashing before writing xid"));
- abort();
+ DBUG_SUICIDE();
});
if ((write_error= write_cache(thd, cache, FALSE, FALSE)))
@@ -4918,7 +4922,7 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event,
if (flush_and_sync())
goto err;
- DBUG_EXECUTE_IF("half_binlogged_transaction", DBUG_ABORT(););
+ DBUG_EXECUTE_IF("half_binlogged_transaction", DBUG_SUICIDE(););
if (cache->error) // Error on read
{
sql_print_error(ER(ER_ERROR_ON_READ), cache->file_name, errno);
@@ -5144,10 +5148,32 @@ extern "C" my_bool reopen_fstreams(const char *filename,
FILE *outstream, FILE *errstream)
{
int handle_fd;
- int stream_fd;
+ int err_fd, out_fd;
HANDLE osfh;
- DBUG_ASSERT(filename && (outstream || errstream));
+ DBUG_ASSERT(filename && errstream);
+
+ // Services don't have stdout/stderr on Windows, so _fileno returns -1.
+ err_fd= _fileno(errstream);
+ if (err_fd < 0)
+ {
+ if (!freopen(filename, "a+", errstream))
+ return TRUE;
+
+ setbuf(errstream, NULL);
+ err_fd= _fileno(errstream);
+ }
+
+ if (outstream)
+ {
+ out_fd= _fileno(outstream);
+ if (out_fd < 0)
+ {
+ if (!freopen(filename, "a+", outstream))
+ return TRUE;
+ out_fd= _fileno(outstream);
+ }
+ }
if ((osfh= CreateFile(filename, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE |
@@ -5163,24 +5189,16 @@ extern "C" my_bool reopen_fstreams(const char *filename,
return TRUE;
}
- if (outstream)
+ if (_dup2(handle_fd, err_fd) < 0)
{
- stream_fd= _fileno(outstream);
- if (_dup2(handle_fd, stream_fd) < 0)
- {
- CloseHandle(osfh);
- return TRUE;
- }
+ CloseHandle(osfh);
+ return TRUE;
}
- if (errstream)
+ if (outstream && _dup2(handle_fd, out_fd) < 0)
{
- stream_fd= _fileno(errstream);
- if (_dup2(handle_fd, stream_fd) < 0)
- {
- CloseHandle(osfh);
- return TRUE;
- }
+ CloseHandle(osfh);
+ return TRUE;
}
_close(handle_fd);
diff --git a/sql/log_event.cc b/sql/log_event.cc
index fa7bb01077d..2268b61b492 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -144,16 +144,21 @@ static void inline slave_rows_error_report(enum loglevel level, int ha_error,
len= my_snprintf(slider, buff_end - slider,
" %s, Error_code: %d;", err->msg, err->code);
}
-
- rli->report(level, thd->is_error()? thd->main_da.sql_errno() : 0,
- "Could not execute %s event on table %s.%s;"
- "%s handler error %s; "
- "the event's master log %s, end_log_pos %lu",
- type, table->s->db.str,
- table->s->table_name.str,
- buff,
- handler_error == NULL? "<unknown>" : handler_error,
- log_name, pos);
+
+ if (ha_error != 0)
+ rli->report(level, thd->is_error() ? thd->main_da.sql_errno() : 0,
+ "Could not execute %s event on table %s.%s;"
+ "%s handler error %s; "
+ "the event's master log %s, end_log_pos %lu",
+ type, table->s->db.str, table->s->table_name.str,
+ buff, handler_error == NULL ? "<unknown>" : handler_error,
+ log_name, pos);
+ else
+ rli->report(level, thd->is_error() ? thd->main_da.sql_errno() : 0,
+ "Could not execute %s event on table %s.%s;"
+ "%s the event's master log %s, end_log_pos %lu",
+ type, table->s->db.str, table->s->table_name.str,
+ buff, log_name, pos);
}
#endif
@@ -1224,7 +1229,7 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
break;
#ifdef HAVE_REPLICATION
case SLAVE_EVENT: /* can never happen (unused event) */
- ev = new Slave_log_event(buf, event_len);
+ ev = new Slave_log_event(buf, event_len, description_event);
break;
#endif /* HAVE_REPLICATION */
case CREATE_FILE_EVENT:
@@ -1312,8 +1317,10 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
(because constructor is "void") ; so instead we leave the pointer we
wanted to allocate (e.g. 'query') to 0 and we test it in is_valid().
Same for Format_description_log_event, member 'post_header_len'.
+
+ SLAVE_EVENT is never used, so it should not be read ever.
*/
- if (!ev || !ev->is_valid())
+ if (!ev || !ev->is_valid() || (event_type == SLAVE_EVENT))
{
DBUG_PRINT("error",("Found invalid event in binary log"));
@@ -2306,7 +2313,7 @@ bool Query_log_event::write(IO_CACHE* file)
start+= 4;
}
- if (thd && thd->is_current_user_used())
+ if (thd && thd->need_binlog_invoker())
{
LEX_STRING user;
LEX_STRING host;
@@ -5981,8 +5988,12 @@ void Slave_log_event::init_from_mem_pool(int data_size)
/** This code is not used, so has not been updated to be format-tolerant. */
-Slave_log_event::Slave_log_event(const char* buf, uint event_len)
- :Log_event(buf,0) /*unused event*/ ,mem_pool(0),master_host(0)
+/* We are using description_event so that slave does not crash on Log_event
+ constructor */
+Slave_log_event::Slave_log_event(const char* buf,
+ uint event_len,
+ const Format_description_log_event* description_event)
+ :Log_event(buf,description_event),mem_pool(0),master_host(0)
{
if (event_len < LOG_EVENT_HEADER_LEN)
return;
@@ -7653,7 +7664,6 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
get_type_str(),
RPL_LOG_NAME, (ulong) log_pos);
thd->reset_current_stmt_binlog_row_based();
- const_cast<Relay_log_info*>(rli)->cleanup_context(thd, error);
thd->is_slave_error= 1;
DBUG_RETURN(error);
}
@@ -7684,14 +7694,12 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
const_cast<Relay_log_info*>(rli)->last_event_start_time= my_time(0);
}
- if (get_flags(STMT_END_F))
- if ((error= rows_event_stmt_cleanup(rli, thd)))
- rli->report(ERROR_LEVEL, error,
- "Error in %s event: commit of row events failed, "
- "table `%s`.`%s`",
- get_type_str(), m_table->s->db.str,
- m_table->s->table_name.str);
-
+ if (get_flags(STMT_END_F) && (error= rows_event_stmt_cleanup(rli, thd)))
+ slave_rows_error_report(ERROR_LEVEL,
+ thd->is_error() ? 0 : error,
+ rli, thd, table,
+ get_type_str(),
+ RPL_LOG_NAME, (ulong) log_pos);
DBUG_RETURN(error);
}
@@ -8359,6 +8367,7 @@ int Table_map_log_event::do_apply_event(Relay_log_info const *rli)
m_field_metadata, m_field_metadata_size,
m_null_bits, m_flags);
table_list->m_tabledef_valid= TRUE;
+ table_list->skip_temporary= 1;
/*
We record in the slave's information that the table should be
@@ -8463,7 +8472,7 @@ void Table_map_log_event::pack_info(Protocol *protocol)
#ifdef MYSQL_CLIENT
-void Table_map_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info)
+void Table_map_log_event::print(FILE *, PRINT_EVENT_INFO *print_event_info)
{
if (!print_event_info->short_form)
{
diff --git a/sql/log_event.h b/sql/log_event.h
index 3c7ba766545..770fb29301b 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -986,9 +986,9 @@ public:
return (void*) my_malloc((uint)size, MYF(MY_WME|MY_FAE));
}
- static void operator delete(void *ptr, size_t size)
+ static void operator delete(void *ptr, size_t)
{
- my_free((uchar*) ptr, MYF(MY_WME|MY_ALLOW_ZERO_PTR));
+ my_free(ptr, MYF(MY_WME|MY_ALLOW_ZERO_PTR));
}
/* Placement version of the above operators */
@@ -1794,7 +1794,9 @@ public:
void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
#endif
- Slave_log_event(const char* buf, uint event_len);
+ Slave_log_event(const char* buf,
+ uint event_len,
+ const Format_description_log_event *description_event);
~Slave_log_event();
int get_data_size();
bool is_valid() const { return master_host != 0; }
diff --git a/sql/my_decimal.h b/sql/my_decimal.h
index d736bad9a4b..86f5db29ed7 100644
--- a/sql/my_decimal.h
+++ b/sql/my_decimal.h
@@ -308,7 +308,7 @@ int my_decimal2int(uint mask, const my_decimal *d, my_bool unsigned_flag,
inline
-int my_decimal2double(uint mask, const my_decimal *d, double *result)
+int my_decimal2double(uint, const my_decimal *d, double *result)
{
/* No need to call check_result as this will always succeed */
return decimal2double((decimal_t*) d, result);
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index d671ebd244b..3f836a5ab1f 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -1086,7 +1086,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
char* packet, uint packet_length);
void log_slow_statement(THD *thd);
bool check_dup(const char *db, const char *name, TABLE_LIST *tables);
-bool compare_record(TABLE *table);
+bool records_are_comparable(const TABLE *table);
+bool compare_record(const TABLE *table);
bool append_file_to_dir(THD *thd, const char **filename_ptr,
const char *table_name);
void wait_while_table_is_used(THD *thd, TABLE *table,
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index 4796a5601bf..ff426a4a608 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -168,7 +168,17 @@ my_bool net_realloc(NET *net, size_t length)
DBUG_ENTER("net_realloc");
DBUG_PRINT("enter",("length: %lu", (ulong) length));
- if (length >= net->max_packet_size)
+ /*
+ When compression is off, net->where_b is always 0.
+ With compression turned on, net->where_b may indicate
+ that we still have a piece of the previous logical
+ packet in the buffer, unprocessed. Take it into account
+ when checking that max_allowed_packet is not exceeded.
+ This ensures that the client treats max_allowed_packet
+ limit identically, regardless of compression being on
+ or off.
+ */
+ if (length >= (net->max_packet_size + net->where_b))
{
DBUG_PRINT("error", ("Packet too large. Max size: %lu",
net->max_packet_size));
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 51bc076ed00..caacec164d2 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -1406,15 +1406,17 @@ failure:
*/
int QUICK_ROR_INTERSECT_SELECT::init_ror_merged_scan(bool reuse_handler)
{
- List_iterator_fast<QUICK_RANGE_SELECT> quick_it(quick_selects);
- QUICK_RANGE_SELECT* quick;
+ List_iterator_fast<QUICK_SELECT_WITH_RECORD> quick_it(quick_selects);
+ QUICK_SELECT_WITH_RECORD *cur;
+ QUICK_RANGE_SELECT *quick;
DBUG_ENTER("QUICK_ROR_INTERSECT_SELECT::init_ror_merged_scan");
/* Initialize all merged "children" quick selects */
DBUG_ASSERT(!need_to_fetch_row || reuse_handler);
if (!need_to_fetch_row && reuse_handler)
{
- quick= quick_it++;
+ cur= quick_it++;
+ quick= cur->quick;
/*
There is no use of this->file. Use it for the first of merged range
selects.
@@ -1423,8 +1425,9 @@ int QUICK_ROR_INTERSECT_SELECT::init_ror_merged_scan(bool reuse_handler)
DBUG_RETURN(1);
quick->file->extra(HA_EXTRA_KEYREAD_PRESERVE_FIELDS);
}
- while ((quick= quick_it++))
+ while ((cur= quick_it++))
{
+ quick= cur->quick;
if (quick->init_ror_merged_scan(FALSE))
DBUG_RETURN(1);
quick->file->extra(HA_EXTRA_KEYREAD_PRESERVE_FIELDS);
@@ -1456,10 +1459,10 @@ int QUICK_ROR_INTERSECT_SELECT::reset()
if (!scans_inited && init_ror_merged_scan(TRUE))
DBUG_RETURN(1);
scans_inited= TRUE;
- List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
- QUICK_RANGE_SELECT *quick;
- while ((quick= it++))
- quick->reset();
+ List_iterator_fast<QUICK_SELECT_WITH_RECORD> it(quick_selects);
+ QUICK_SELECT_WITH_RECORD *qr;
+ while ((qr= it++))
+ qr->quick->reset();
DBUG_RETURN(0);
}
@@ -1469,6 +1472,7 @@ int QUICK_ROR_INTERSECT_SELECT::reset()
SYNOPSIS
QUICK_ROR_INTERSECT_SELECT::push_quick_back()
+ alloc Mem root to create auxiliary structures on
quick Quick select to be added. The quick select must return
rows in rowid order.
NOTES
@@ -1480,11 +1484,17 @@ int QUICK_ROR_INTERSECT_SELECT::reset()
*/
bool
-QUICK_ROR_INTERSECT_SELECT::push_quick_back(QUICK_RANGE_SELECT *quick)
+QUICK_ROR_INTERSECT_SELECT::push_quick_back(MEM_ROOT *alloc, QUICK_RANGE_SELECT *quick)
{
- return quick_selects.push_back(quick);
+ QUICK_SELECT_WITH_RECORD *qr;
+ if (!(qr= new QUICK_SELECT_WITH_RECORD) ||
+ !(qr->key_tuple= (uchar*)alloc_root(alloc, quick->max_used_key_length)))
+ return TRUE;
+ qr->quick= quick;
+ return quick_selects.push_back(qr);
}
+
QUICK_ROR_INTERSECT_SELECT::~QUICK_ROR_INTERSECT_SELECT()
{
DBUG_ENTER("QUICK_ROR_INTERSECT_SELECT::~QUICK_ROR_INTERSECT_SELECT");
@@ -4947,7 +4957,7 @@ QUICK_SELECT_I *TRP_ROR_INTERSECT::make_quick(PARAM *param,
{
if (!(quick= get_quick_select(param, (*first_scan)->idx,
(*first_scan)->sel_arg, alloc)) ||
- quick_intrsect->push_quick_back(quick))
+ quick_intrsect->push_quick_back(alloc, quick))
{
delete quick_intrsect;
DBUG_RETURN(NULL);
@@ -7977,11 +7987,11 @@ bool QUICK_INDEX_MERGE_SELECT::is_keys_used(const MY_BITMAP *fields)
bool QUICK_ROR_INTERSECT_SELECT::is_keys_used(const MY_BITMAP *fields)
{
- QUICK_RANGE_SELECT *quick;
- List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
- while ((quick= it++))
+ QUICK_SELECT_WITH_RECORD *qr;
+ List_iterator_fast<QUICK_SELECT_WITH_RECORD> it(quick_selects);
+ while ((qr= it++))
{
- if (is_key_used(head, quick->index, fields))
+ if (is_key_used(head, qr->quick->index, fields))
return 1;
}
return 0;
@@ -8280,7 +8290,8 @@ int QUICK_INDEX_MERGE_SELECT::get_next()
int QUICK_ROR_INTERSECT_SELECT::get_next()
{
- List_iterator_fast<QUICK_RANGE_SELECT> quick_it(quick_selects);
+ List_iterator_fast<QUICK_SELECT_WITH_RECORD> quick_it(quick_selects);
+ QUICK_SELECT_WITH_RECORD *qr;
QUICK_RANGE_SELECT* quick;
int error, cmp;
uint last_rowid_count=0;
@@ -8289,7 +8300,8 @@ int QUICK_ROR_INTERSECT_SELECT::get_next()
do
{
/* Get a rowid for first quick and save it as a 'candidate' */
- quick= quick_it++;
+ qr= quick_it++;
+ quick= qr->quick;
error= quick->get_next();
if (cpk_quick)
{
@@ -8299,17 +8311,22 @@ int QUICK_ROR_INTERSECT_SELECT::get_next()
if (error)
DBUG_RETURN(error);
+ /* Save the read key tuple */
+ key_copy(qr->key_tuple, record, head->key_info + quick->index,
+ quick->max_used_key_length);
+
quick->file->position(quick->record);
memcpy(last_rowid, quick->file->ref, head->file->ref_length);
last_rowid_count= 1;
while (last_rowid_count < quick_selects.elements)
{
- if (!(quick= quick_it++))
+ if (!(qr= quick_it++))
{
quick_it.rewind();
- quick= quick_it++;
+ qr= quick_it++;
}
+ quick= qr->quick;
do
{
@@ -8319,6 +8336,9 @@ int QUICK_ROR_INTERSECT_SELECT::get_next()
cmp= head->file->cmp_ref(quick->file->ref, last_rowid);
} while (cmp < 0);
+ key_copy(qr->key_tuple, record, head->key_info + quick->index,
+ quick->max_used_key_length);
+
/* Ok, current select 'caught up' and returned ref >= cur_ref */
if (cmp > 0)
{
@@ -8334,6 +8354,10 @@ int QUICK_ROR_INTERSECT_SELECT::get_next()
}
memcpy(last_rowid, quick->file->ref, head->file->ref_length);
last_rowid_count= 1;
+
+ //save the fields here
+ key_copy(qr->key_tuple, record, head->key_info + quick->index,
+ quick->max_used_key_length);
}
else
{
@@ -8346,6 +8370,21 @@ int QUICK_ROR_INTERSECT_SELECT::get_next()
if (need_to_fetch_row)
error= head->file->ha_rnd_pos(head->record[0], last_rowid);
} while (error == HA_ERR_RECORD_DELETED);
+
+ if (!need_to_fetch_row)
+ {
+ /* Restore the columns we've read/saved with other quick selects */
+ quick_it.rewind();
+ while ((qr= quick_it++))
+ {
+ if (qr->quick != quick)
+ {
+ key_restore(record, qr->key_tuple, head->key_info + qr->quick->index,
+ qr->quick->max_used_key_length);
+ }
+ }
+ }
+
DBUG_RETURN(error);
}
@@ -8426,9 +8465,14 @@ int QUICK_RANGE_SELECT::reset()
in_range= FALSE;
cur_range= (QUICK_RANGE**) ranges.buffer;
- if (file->inited == handler::NONE && (error= file->ha_index_init(index,1)))
- DBUG_RETURN(error);
-
+ if (file->inited == handler::NONE)
+ {
+ if (in_ror_merged_scan)
+ head->column_bitmaps_set_no_signal(&column_bitmap, &column_bitmap);
+ if ((error= file->ha_index_init(index,1)))
+ DBUG_RETURN(error);
+ }
+
/* Do not allocate the buffers twice. */
if (multi_range_length)
{
@@ -8965,12 +9009,12 @@ void QUICK_INDEX_MERGE_SELECT::add_info_string(String *str)
void QUICK_ROR_INTERSECT_SELECT::add_info_string(String *str)
{
bool first= TRUE;
- QUICK_RANGE_SELECT *quick;
- List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
+ QUICK_SELECT_WITH_RECORD *qr;
+ List_iterator_fast<QUICK_SELECT_WITH_RECORD> it(quick_selects);
str->append(STRING_WITH_LEN("intersect("));
- while ((quick= it++))
+ while ((qr= it++))
{
- KEY *key_info= head->key_info + quick->index;
+ KEY *key_info= head->key_info + qr->quick->index;
if (!first)
str->append(',');
else
@@ -9057,11 +9101,11 @@ void QUICK_ROR_INTERSECT_SELECT::add_keys_and_lengths(String *key_names,
char buf[64];
uint length;
bool first= TRUE;
- QUICK_RANGE_SELECT *quick;
- List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
- while ((quick= it++))
+ QUICK_SELECT_WITH_RECORD *qr;
+ List_iterator_fast<QUICK_SELECT_WITH_RECORD> it(quick_selects);
+ while ((qr= it++))
{
- KEY *key_info= head->key_info + quick->index;
+ KEY *key_info= head->key_info + qr->quick->index;
if (first)
first= FALSE;
else
@@ -9070,7 +9114,7 @@ void QUICK_ROR_INTERSECT_SELECT::add_keys_and_lengths(String *key_names,
used_lengths->append(',');
}
key_names->append(key_info->name);
- length= longlong10_to_str(quick->max_used_key_length, buf, 10) - buf;
+ length= longlong10_to_str(qr->quick->max_used_key_length, buf, 10) - buf;
used_lengths->append(buf, length);
}
@@ -11427,13 +11471,13 @@ void QUICK_INDEX_MERGE_SELECT::dbug_dump(int indent, bool verbose)
void QUICK_ROR_INTERSECT_SELECT::dbug_dump(int indent, bool verbose)
{
- List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
- QUICK_RANGE_SELECT *quick;
+ List_iterator_fast<QUICK_SELECT_WITH_RECORD> it(quick_selects);
+ QUICK_SELECT_WITH_RECORD *qr;
fprintf(DBUG_FILE, "%*squick ROR-intersect select, %scovering\n",
indent, "", need_to_fetch_row? "":"non-");
fprintf(DBUG_FILE, "%*smerged scans {\n", indent, "");
- while ((quick= it++))
- quick->dbug_dump(indent+2, verbose);
+ while ((qr= it++))
+ qr->quick->dbug_dump(indent+2, verbose);
if (cpk_quick)
{
fprintf(DBUG_FILE, "%*sclustered PK quick:\n", indent, "");
diff --git a/sql/opt_range.h b/sql/opt_range.h
index 758dffe7a52..29df043cb69 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -585,13 +585,21 @@ public:
void dbug_dump(int indent, bool verbose);
#endif
int init_ror_merged_scan(bool reuse_handler);
- bool push_quick_back(QUICK_RANGE_SELECT *quick_sel_range);
+ bool push_quick_back(MEM_ROOT *alloc, QUICK_RANGE_SELECT *quick_sel_range);
+
+ class QUICK_SELECT_WITH_RECORD : public Sql_alloc
+ {
+ public:
+ QUICK_RANGE_SELECT *quick;
+ uchar *key_tuple;
+ ~QUICK_SELECT_WITH_RECORD() { delete quick; }
+ };
/*
Range quick selects this intersection consists of, not including
cpk_quick.
*/
- List<QUICK_RANGE_SELECT> quick_selects;
+ List<QUICK_SELECT_WITH_RECORD> quick_selects;
/*
Merged quick select that uses Clustered PK, if there is one. This quick
diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc
index 3a46bbcd6ee..ecae1efdce4 100644
--- a/sql/rpl_record.cc
+++ b/sql/rpl_record.cc
@@ -77,7 +77,7 @@ pack_row(TABLE *table, MY_BITMAP const* cols,
unsigned int null_mask= 1U;
for ( ; (field= *p_field) ; p_field++)
{
- DBUG_PRINT("debug", ("null_mask=%d; null_ptr=%p; row_data=%p; null_byte_count=%d",
+ DBUG_PRINT("debug", ("null_mask: %d null_ptr: %p row_data: %p null_byte_count: %d",
null_mask, null_ptr, row_data, null_byte_count));
if (bitmap_is_set(cols, p_field - table->field))
{
diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h
index 2c1f581e156..5cafcf47086 100644
--- a/sql/rpl_rli.h
+++ b/sql/rpl_rli.h
@@ -94,6 +94,16 @@ public:
*/
MYSQL_BIN_LOG relay_log;
LOG_INFO linfo;
+
+ /*
+ cur_log
+ Pointer that either points at relay_log.get_log_file() or
+ &rli->cache_buf, depending on whether the log is hot or there was
+ the need to open a cold relay_log.
+
+ cache_buf
+ IO_CACHE used when opening cold relay logs.
+ */
IO_CACHE cache_buf,*cur_log;
/* The following variables are safe to read any time */
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 95fd2d05f31..38721c154e6 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -2672,7 +2672,7 @@ bool update_sys_var_str_path(THD *thd, sys_var_str *var_str,
file_log= logger.get_log_file_handler();
break;
default:
- assert(0); // Impossible
+ MY_ASSERT_UNREACHABLE();
}
if (!old_value)
diff --git a/sql/share/Makefile.am b/sql/share/Makefile.am
index 68b393e619f..cb7cc2224a8 100644
--- a/sql/share/Makefile.am
+++ b/sql/share/Makefile.am
@@ -57,6 +57,3 @@ distclean-local:
# Do nothing
link_sources:
-
-# Don't update the files from bitkeeper
-%::SCCS/s.%
diff --git a/sql/slave.cc b/sql/slave.cc
index 55bfcceeb47..0e41d897dd4 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -740,8 +740,17 @@ static bool sql_slave_killed(THD* thd, Relay_log_info* rli)
DBUG_ASSERT(rli->slave_running == 1);// tracking buffer overrun
if (abort_loop || thd->killed || rli->abort_slave)
{
+ /*
+ The transaction should always be binlogged if OPTION_KEEP_LOG is set
+ (it implies that something can not be rolled back). And such case
+ should be regarded similarly as modifing a non-transactional table
+ because retrying of the transaction will lead to an error or inconsistency
+ as well.
+ Example: OPTION_KEEP_LOG is set if a temporary table is created or dropped.
+ */
if (rli->abort_slave && rli->is_in_group() &&
- thd->transaction.all.modified_non_trans_table)
+ (thd->transaction.all.modified_non_trans_table ||
+ (thd->options & OPTION_KEEP_LOG)))
DBUG_RETURN(0);
/*
If we are in an unsafe situation (stopping could corrupt replication),
@@ -2304,7 +2313,7 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli)
else
{
exec_res= 0;
- end_trans(thd, ROLLBACK);
+ rli->cleanup_context(thd, 1);
/* chance for concurrent connection to get more locks */
safe_sleep(thd, min(rli->trans_retries, MAX_SLAVE_RETRY_PAUSE),
(CHECK_KILLED_FUNC)sql_slave_killed, (void*)rli);
@@ -3120,6 +3129,7 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \
request is detected only by the present function, not by events), so we
must "proactively" clear playgrounds:
*/
+ thd->clear_error();
rli->cleanup_context(thd, 1);
/*
Some extra safety, which should not been needed (normally, event deletion
@@ -4312,12 +4322,66 @@ static Log_event* next_event(Relay_log_info* rli)
DBUG_ASSERT(rli->cur_log_fd == -1);
/*
- Read pointer has to be at the start since we are the only
- reader.
- We must keep the LOCK_log to read the 4 first bytes, as this is a hot
- log (same as when we call read_log_event() above: for a hot log we
- take the mutex).
+ When the SQL thread is [stopped and] (re)started the
+ following may happen:
+
+ 1. Log was hot at stop time and remains hot at restart
+
+ SQL thread reads again from hot_log (SQL thread was
+ reading from the active log when it was stopped and the
+ very same log is still active on SQL thread restart).
+
+ In this case, my_b_seek is performed on cur_log, while
+ cur_log points to relay_log.get_log_file();
+
+ 2. Log was hot at stop time but got cold before restart
+
+ The log was hot when SQL thread stopped, but it is not
+ anymore when the SQL thread restarts.
+
+ In this case, the SQL thread reopens the log, using
+ cache_buf, ie, cur_log points to &cache_buf, and thence
+ its coordinates are reset.
+
+ 3. Log was already cold at stop time
+
+ The log was not hot when the SQL thread stopped, and, of
+ course, it will not be hot when it restarts.
+
+ In this case, the SQL thread opens the cold log again,
+ using cache_buf, ie, cur_log points to &cache_buf, and
+ thence its coordinates are reset.
+
+ 4. Log was hot at stop time, DBA changes to previous cold
+ log and restarts SQL thread
+
+ The log was hot when the SQL thread was stopped, but the
+ user changed the coordinates of the SQL thread to
+ restart from a previous cold log.
+
+ In this case, at start time, cur_log points to a cold
+ log, opened using &cache_buf as cache, and coordinates
+ are reset. However, as it moves on to the next logs, it
+ will eventually reach the hot log. If the hot log is the
+ same at the time the SQL thread was stopped, then
+ coordinates were not reset - the cur_log will point to
+ relay_log.get_log_file(), and not a freshly opened
+ IO_CACHE through cache_buf. For this reason we need to
+ deploy a my_b_seek before calling check_binlog_magic at
+ this point of the code (see: BUG#55263 for more
+ details).
+
+ NOTES:
+ - We must keep the LOCK_log to read the 4 first bytes, as
+ this is a hot log (same as when we call read_log_event()
+ above: for a hot log we take the mutex).
+
+ - Because of scenario #4 above, we need to have a
+ my_b_seek here. Otherwise, we might hit the assertion
+ inside check_binlog_magic.
*/
+
+ my_b_seek(cur_log, (my_off_t) 0);
if (check_binlog_magic(cur_log,&errmsg))
{
if (!hot_log) pthread_mutex_unlock(log_lock);
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 496e8c310dd..87e27d68b98 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -1593,6 +1593,7 @@ bool change_password(THD *thd, const char *host, const char *user,
/* Buffer should be extended when password length is extended. */
char buff[512];
ulong query_length;
+ bool save_binlog_row_based;
uint new_password_len= (uint) strlen(new_password);
bool result= 1;
DBUG_ENTER("change_password");
@@ -1628,6 +1629,14 @@ bool change_password(THD *thd, const char *host, const char *user,
if (!(table= open_ltable(thd, &tables, TL_WRITE, 0)))
DBUG_RETURN(1);
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ if ((save_binlog_row_based= thd->current_stmt_binlog_row_based))
+ thd->clear_current_stmt_binlog_row_based();
+
VOID(pthread_mutex_lock(&acl_cache->lock));
ACL_USER *acl_user;
if (!(acl_user= find_acl_user(host, user, TRUE)))
@@ -1671,6 +1680,12 @@ bool change_password(THD *thd, const char *host, const char *user,
}
end:
close_thread_tables(thd);
+
+ /* Restore the state of binlog format */
+ DBUG_ASSERT(!thd->current_stmt_binlog_row_based);
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_row_based();
+
DBUG_RETURN(result);
}
@@ -5509,7 +5524,7 @@ static int handle_grant_struct(uint struct_no, bool drop,
host= grant_name->host.hostname;
break;
default:
- DBUG_ASSERT(0);
+ MY_ASSERT_UNREACHABLE();
}
if (! user)
user= "";
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index c6260d0a857..a1458259d11 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -3114,8 +3114,6 @@ bool reopen_table(TABLE *table)
tmp.maybe_null= table->maybe_null;
tmp.status= table->status;
- tmp.s->table_map_id= table->s->table_map_id;
-
/* Get state */
tmp.in_use= thd;
tmp.reginfo.lock_type=table->reginfo.lock_type;
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index fb3d201e222..81cc87723c5 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -1349,6 +1349,57 @@ end:
}
+#ifndef EMBEDDED_LIBRARY
+/**
+ Send a single memory block from the query cache.
+
+ Respects the client/server protocol limits for the
+ size of the network packet, and splits a large block
+ in pieces to ensure that individual piece doesn't exceed
+ the maximal allowed size of the network packet (16M).
+
+ @param[in] net NET handler
+ @param[in] packet packet to send
+ @param[in] len packet length
+
+ @return Operation status
+ @retval FALSE On success
+ @retval TRUE On error
+*/
+static bool
+send_data_in_chunks(NET *net, const uchar *packet, ulong len)
+{
+ /*
+ On the client we may require more memory than max_allowed_packet
+ to keep, both, the truncated last logical packet, and the
+ compressed next packet. This never (or in practice never)
+ happens without compression, since without compression it's very
+ unlikely that a) a truncated logical packet would remain on the
+ client when it's time to read the next packet b) a subsequent
+ logical packet that is being read would be so large that
+ size-of-new-packet + size-of-old-packet-tail >
+ max_allowed_packet. To remedy this issue, we send data in 1MB
+ sized packets, that's below the current client default of 16MB
+ for max_allowed_packet, but large enough to ensure there is no
+ unnecessary overhead from too many syscalls per result set.
+ */
+ static const ulong MAX_CHUNK_LENGTH= 1024*1024;
+
+ while (len > MAX_CHUNK_LENGTH)
+ {
+ if (net_real_write(net, packet, MAX_CHUNK_LENGTH))
+ return TRUE;
+ packet+= MAX_CHUNK_LENGTH;
+ len-= MAX_CHUNK_LENGTH;
+ }
+ if (len && net_real_write(net, packet, len))
+ return TRUE;
+
+ return FALSE;
+}
+#endif
+
+
/*
Check if the query is in the cache. If it was cached, send it
to the user.
@@ -1660,11 +1711,11 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
ALIGN_SIZE(sizeof(Query_cache_result)))));
Query_cache_result *result = result_block->result();
- if (net_real_write(&thd->net, result->data(),
- result_block->used -
- result_block->headers_len() -
- ALIGN_SIZE(sizeof(Query_cache_result))))
- break; // Client aborted
+ if (send_data_in_chunks(&thd->net, result->data(),
+ result_block->used -
+ result_block->headers_len() -
+ ALIGN_SIZE(sizeof(Query_cache_result))))
+ break; // Client aborted
result_block = result_block->next;
thd->net.pkt_nr= query->last_pkt_nr; // Keep packet number updated
} while (result_block != first_result_block);
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 20898d68500..b64a5a71514 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -91,7 +91,9 @@ extern "C" void free_user_var(user_var_entry *entry)
bool Key_part_spec::operator==(const Key_part_spec& other) const
{
- return length == other.length && !strcmp(field_name, other.field_name);
+ return length == other.length &&
+ !my_strcasecmp(system_charset_info, field_name,
+ other.field_name);
}
/**
@@ -803,7 +805,7 @@ THD::THD()
m_internal_handler= NULL;
arena_for_cached_items= 0;
- current_user_used= FALSE;
+ m_binlog_invoker= FALSE;
memset(&invoker_user, 0, sizeof(invoker_user));
memset(&invoker_host, 0, sizeof(invoker_host));
}
@@ -1431,7 +1433,7 @@ void THD::cleanup_after_query()
where= THD::DEFAULT_WHERE;
/* reset table map for multi-table update */
table_map_for_update= 0;
- clean_current_user_used();
+ m_binlog_invoker= FALSE;
}
@@ -1740,6 +1742,36 @@ void THD::nocheck_register_item_tree_change(Item **place, Item *old_value,
change_list.append(change);
}
+/**
+ Check and register item change if needed
+
+ @param place place where we should assign new value
+ @param new_value place of the new value
+
+ @details
+ Let C be a reference to an item that changed the reference A
+ at the location (occurrence) L1 and this change has been registered.
+ If C is substituted for reference A another location (occurrence) L2
+ that is to be registered as well than this change has to be
+ consistent with the first change in order the procedure that rollback
+ changes to substitute the same reference at both locations L1 and L2.
+*/
+
+void THD::check_and_register_item_tree_change(Item **place, Item **new_value,
+ MEM_ROOT *runtime_memroot)
+{
+ Item_change_record *change;
+ I_List_iterator<Item_change_record> it(change_list);
+ while ((change= it++))
+ {
+ if (change->place == new_value)
+ break; // we need only very first value
+ }
+ if (change)
+ nocheck_register_item_tree_change(place, change->old_value,
+ runtime_memroot);
+}
+
void THD::rollback_item_tree_changes()
{
@@ -3460,7 +3492,7 @@ void THD::set_query(char *query_arg, uint32 query_length_arg)
void THD::get_definer(LEX_USER *definer)
{
- set_current_user_used();
+ binlog_invoker();
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
if (slave_thread && has_invoker())
{
diff --git a/sql/sql_class.h b/sql/sql_class.h
index bb986d6377f..2fe579713e1 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1584,7 +1584,7 @@ public:
/*
This is to track items changed during execution of a prepared
statement/stored procedure. It's created by
- register_item_tree_change() in memory root of THD, and freed in
+ nocheck_register_item_tree_change() in memory root of THD, and freed in
rollback_item_tree_changes(). For conventional execution it's always
empty.
*/
@@ -2208,8 +2208,26 @@ public:
nocheck_register_item_tree_change(place, *place, mem_root);
*place= new_value;
}
+ /**
+ Make change in item tree after checking whether it needs registering
+
+
+ @param place place where we should assign new value
+ @param new_value place of the new value
+
+ @details
+ see check_and_register_item_tree_change details
+ */
+ void check_and_register_item_tree(Item **place, Item **new_value)
+ {
+ if (!stmt_arena->is_conventional())
+ check_and_register_item_tree_change(place, new_value, mem_root);
+ *place= *new_value;
+ }
void nocheck_register_item_tree_change(Item **place, Item *old_value,
MEM_ROOT *runtime_memroot);
+ void check_and_register_item_tree_change(Item **place, Item **new_value,
+ MEM_ROOT *runtime_memroot);
void rollback_item_tree_changes();
/*
@@ -2404,9 +2422,8 @@ public:
Protected with LOCK_thd_data mutex.
*/
void set_query(char *query_arg, uint32 query_length_arg);
- void set_current_user_used() { current_user_used= TRUE; }
- bool is_current_user_used() { return current_user_used; }
- void clean_current_user_used() { current_user_used= FALSE; }
+ void binlog_invoker() { m_binlog_invoker= TRUE; }
+ bool need_binlog_invoker() { return m_binlog_invoker; }
void get_definer(LEX_USER *definer);
void set_invoker(const LEX_STRING *user, const LEX_STRING *host)
{
@@ -2462,10 +2479,10 @@ private:
statements or default definer is set in CREATE/ALTER SP, SF, Event,
TRIGGER or VIEW statements.
- Current user will be binlogged into Query_log_event if current_user_used
+ Current user will be binlogged into Query_log_event if m_binlog_invoker
is TRUE; It will be stored into invoker_host and invoker_user by SQL thread.
*/
- bool current_user_used;
+ bool m_binlog_invoker;
/**
It points to the invoker in the Query_log_event.
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 1dd659283ac..7aa48524b20 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -1197,6 +1197,12 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
VOID(filename_to_tablename(file->name, table_list->table_name,
MYSQL50_TABLE_NAME_PREFIX_LENGTH +
strlen(file->name) + 1));
+
+ /* To be able to correctly look up the table in the table cache. */
+ if (lower_case_table_names)
+ table_list->table_name_length= my_casedn_str(files_charset_info,
+ table_list->table_name);
+
table_list->alias= table_list->table_name; // If lower_case_table_names=2
table_list->internal_tmp_table= is_prefix(file->name, tmp_file_prefix);
/* Link into list */
diff --git a/sql/sql_help.cc b/sql/sql_help.cc
index 916557a46c4..6ede7bb9574 100644
--- a/sql/sql_help.cc
+++ b/sql/sql_help.cc
@@ -696,7 +696,7 @@ bool mysqld_help(THD *thd, const char *mask)
if (count_topics == 0)
{
- int key_id;
+ int UNINIT_VAR(key_id);
if (!(select=
prepare_select_for_name(thd,mask,mlen,tables,tables[3].table,
used_fields[help_keyword_name].field,
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 3c2f90e8080..72ca7310ee1 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1515,9 +1515,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
table->file->adjust_next_insert_id_after_explicit_value(
table->next_number_field->val_int());
info->touched++;
- if (((table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ) &&
- !bitmap_is_subset(table->write_set, table->read_set)) ||
- compare_record(table))
+ if (!records_are_comparable(table) || compare_record(table))
{
if ((error=table->file->ha_update_row(table->record[1],
table->record[0])) &&
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 524206d0af1..6256a0f89d6 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -2892,7 +2892,7 @@ static void fix_prepare_info_in_table_list(THD *thd, TABLE_LIST *tbl)
{
if (tbl->on_expr)
{
- tbl->prep_on_expr= tbl->on_expr;
+ thd->check_and_register_item_tree(&tbl->prep_on_expr, &tbl->on_expr);
tbl->on_expr= tbl->on_expr->copy_andor_structure(thd);
}
fix_prepare_info_in_table_list(thd, tbl->merge_underlying_list);
@@ -2926,12 +2926,12 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds,
first_execution= 0;
if (*conds)
{
- prep_where= *conds;
+ thd->check_and_register_item_tree(&prep_where, conds);
*conds= where= prep_where->copy_andor_structure(thd);
}
if (*having_conds)
{
- prep_having= *having_conds;
+ thd->check_and_register_item_tree(&prep_having, having_conds);
*having_conds= having= prep_having->copy_andor_structure(thd);
}
fix_prepare_info_in_table_list(thd, table_list.first);
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 366c01b1754..a909335bfa7 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -1147,7 +1147,7 @@ READ_INFO::~READ_INFO()
if (need_end_io_cache)
::end_io_cache(&cache);
}
- my_free((uchar*) buffer,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(buffer, MYF(MY_ALLOW_ZERO_PTR));
}
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index f997bbcfaaf..61c5ab8d245 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -27,6 +27,7 @@
#include "sp_cache.h"
#include "events.h"
#include "sql_trigger.h"
+#include "debug_sync.h"
#ifdef WITH_ARIA_STORAGE_ENGINE
#include "../storage/maria/ha_maria.h"
@@ -3230,6 +3231,15 @@ end_with_restore_list:
thd->first_successful_insert_id_in_cur_stmt=
thd->first_successful_insert_id_in_prev_stmt;
+ DBUG_EXECUTE_IF("after_mysql_insert",
+ {
+ const char act[]=
+ "now "
+ "wait_for signal.continue";
+ DBUG_ASSERT(opt_debug_sync_timeout > 0);
+ DBUG_ASSERT(!debug_sync_set_action(current_thd,
+ STRING_WITH_LEN(act)));
+ };);
break;
}
case SQLCOM_REPLACE_SELECT:
@@ -3885,6 +3895,10 @@ end_with_restore_list:
if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) &&
check_global_access(thd,CREATE_USER_ACL))
break;
+
+ /* Replicate current user as grantor */
+ thd->binlog_invoker();
+
/* Conditionally writes to binlog */
if (!(res = mysql_revoke_all(thd, lex->users_list)))
my_ok(thd);
@@ -3905,6 +3919,9 @@ end_with_restore_list:
is_schema_db(select_lex->db) : 0))
goto error;
+ /* Replicate current user as grantor */
+ thd->binlog_invoker();
+
if (thd->security_ctx->user) // If not replication
{
LEX_USER *user, *tmp_user;
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index 551f19694ef..851bd6b875b 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -6787,8 +6787,8 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
}
}
else
- assert(0);
-
+ MY_ASSERT_UNREACHABLE();
+
can_match_multiple_values= (flags || !min_value || !max_value ||
memcmp(min_value, max_value, field_len));
if (can_match_multiple_values &&
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index bf1632d1d53..98434439998 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -2366,11 +2366,15 @@ void reinit_stmt_before_use(THD *thd, LEX *lex)
sl->where= sl->prep_where->copy_andor_structure(thd);
sl->where->cleanup();
}
+ else
+ sl->where= NULL;
if (sl->prep_having)
{
sl->having= sl->prep_having->copy_andor_structure(thd);
sl->having->cleanup();
}
+ else
+ sl->having= NULL;
DBUG_ASSERT(sl->join == 0);
ORDER *order;
/* Fix GROUP list */
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index e185996126d..3f88a6adf80 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1472,6 +1472,15 @@ JOIN::optimize()
if (order)
{
/*
+ Do we need a temporary table due to the ORDER BY not being equal to
+ the GROUP BY? The call to test_if_skip_sort_order above tests for the
+ GROUP BY clause only and hence is not valid in this case. So the
+ estimated number of rows to be read from the first table is not valid.
+ We clear it here so that it doesn't show up in EXPLAIN.
+ */
+ if (need_tmp && (select_options & SELECT_DESCRIBE) != 0)
+ join_tab[const_tables].limit= 0;
+ /*
Force using of tmp table if sorting by a SP or UDF function due to
their expensive and probably non-deterministic nature.
*/
@@ -1694,11 +1703,14 @@ JOIN::reinit()
/* Reset effect of possible no_rows_in_result() */
List_iterator_fast<Item> it(fields_list);
Item *item;
-
no_rows_in_result_called= 0;
while ((item= it++))
item->restore_to_before_no_rows_in_result();
- }
+ }
+
+ if (!(select_options & SELECT_DESCRIBE))
+ init_ftfuncs(thd, select_lex, test(order));
+
DBUG_RETURN(0);
}
@@ -2485,6 +2497,13 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
{
DBUG_RETURN(TRUE);
}
+ /*
+ Original join tabs might be overwritten at first
+ subselect execution. So we need to restore them.
+ */
+ Item_subselect *subselect= select_lex->master_unit()->item;
+ if (subselect && subselect->is_uncacheable() && join->reinit())
+ DBUG_RETURN(TRUE);
}
else
{
@@ -8896,6 +8915,8 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
For some of the inner tables there are conjunctive predicates
that reject nulls => the outer join can be replaced by an inner join.
*/
+ if (table->outer_join && !table->embedding && table->table)
+ table->table->maybe_null= FALSE;
table->outer_join= 0;
if (table->on_expr)
{
@@ -8982,6 +9003,8 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
while ((tbl= it++))
{
tbl->embedding= table->embedding;
+ if (!tbl->embedding && !tbl->on_expr && tbl->table)
+ tbl->table->maybe_null= FALSE;
tbl->join_list= table->join_list;
}
li.replace(nested_join->join_list);
@@ -9861,7 +9884,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
If item have to be able to store NULLs but underlaid field can't do it,
create_tmp_field_from_field() can't be used for tmp field creation.
*/
- if (field->maybe_null && !field->field->maybe_null())
+ if (field->maybe_null && field->in_rollup && !field->field->maybe_null())
{
result= create_tmp_field_from_item(thd, item, table, NULL,
modify_item, convert_blob_length);
@@ -11437,22 +11460,22 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
if (error == NESTED_LOOP_NO_MORE_ROWS)
error= NESTED_LOOP_OK;
+ if (table == NULL) // If sending data to client
+ {
+ /*
+ The following will unlock all cursors if the command wasn't an
+ update command
+ */
+ join->join_free(); // Unlock all cursors
+ }
if (error == NESTED_LOOP_OK)
{
/*
Sic: this branch works even if rc != 0, e.g. when
send_data above returns an error.
*/
- if (!table) // If sending data to client
- {
- /*
- The following will unlock all cursors if the command wasn't an
- update command
- */
- join->join_free(); // Unlock all cursors
- if (join->result->send_eof())
- rc= 1; // Don't send error
- }
+ if (table == NULL && join->result->send_eof()) // If sending data to client
+ rc= 1; // Don't send error
DBUG_PRINT("info",("%ld records output", (long) join->send_records));
}
else
@@ -13516,7 +13539,7 @@ list_contains_unique_index(TABLE *table,
key_part < key_part_end;
key_part++)
{
- if (key_part->field->maybe_null() ||
+ if (key_part->field->maybe_null() ||
!find_func(key_part->field, data))
break;
}
@@ -16334,6 +16357,7 @@ static bool change_group_ref(THD *thd, Item_func *expr, ORDER *group_list,
if (arg_changed)
{
expr->maybe_null= 1;
+ expr->in_rollup= 1;
*changed= TRUE;
}
}
@@ -16397,6 +16421,7 @@ bool JOIN::rollup_init()
if (*group_tmp->item == item)
{
item->maybe_null= 1;
+ item->in_rollup= 1;
found_in_group= 1;
break;
}
@@ -17026,7 +17051,15 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
if (tab->select && tab->select->quick)
examined_rows= tab->select->quick->records;
else if (tab->type == JT_NEXT || tab->type == JT_ALL)
- examined_rows= tab->limit ? tab->limit : tab->table->file->records();
+ {
+ if (tab->limit)
+ examined_rows= tab->limit;
+ else
+ {
+ tab->table->file->info(HA_STATUS_VARIABLE);
+ examined_rows= tab->table->file->stats.records;
+ }
+ }
else
examined_rows=(ha_rows)join->best_positions[i].records_read;
diff --git a/sql/sql_string.h b/sql/sql_string.h
index e595de47f99..0b521eb6f49 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -95,9 +95,13 @@ public:
}
static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
{ return (void*) alloc_root(mem_root, (uint) size); }
- static void operator delete(void *ptr_arg,size_t size)
- { TRASH(ptr_arg, size); }
- static void operator delete(void *ptr_arg, MEM_ROOT *mem_root)
+ static void operator delete(void *ptr_arg, size_t size)
+ {
+ (void) ptr_arg;
+ (void) size;
+ TRASH(ptr_arg, size);
+ }
+ static void operator delete(void *, MEM_ROOT *)
{ /* never called */ }
~String() { free(); }
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 0ef18a237dd..d702e83aefd 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -3368,6 +3368,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
key_part_info->length=(uint16) length;
/* Use packed keys for long strings on the first column */
if (!((*db_options) & HA_OPTION_NO_PACK_KEYS) &&
+ !((create_info->table_options & HA_OPTION_NO_PACK_KEYS)) &&
(length >= KEY_DEFAULT_PACK_LENGTH &&
(sql_field->sql_type == MYSQL_TYPE_STRING ||
sql_field->sql_type == MYSQL_TYPE_VARCHAR ||
@@ -3953,7 +3954,7 @@ bool mysql_create_table_no_lock(THD *thd,
Then she could create the table. This case is pretty obscure and
therefore we don't introduce a new error message only for it.
*/
- if (get_cached_table_share(db, alias))
+ if (get_cached_table_share(db, table_name))
{
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
goto unlock_and_end;
@@ -4474,9 +4475,6 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
pthread_mutex_unlock(&LOCK_open);
}
- /* A MERGE table must not come here. */
- DBUG_ASSERT(!table->child_l);
-
/*
REPAIR TABLE ... USE_FRM for temporary tables makes little sense.
*/
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index f6864add19f..e32bedd80a0 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -1986,6 +1986,7 @@ bool Table_triggers_list::process_triggers(THD *thd,
bool err_status;
Sub_statement_state statement_state;
sp_head *sp_trigger= bodies[event][time_type];
+ SELECT_LEX *save_current_select;
if (sp_trigger == NULL)
return FALSE;
@@ -2009,11 +2010,19 @@ bool Table_triggers_list::process_triggers(THD *thd,
thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER);
+ /*
+ Reset current_select before call execute_trigger() and
+ restore it after return from one. This way error is set
+ in case of failure during trigger execution.
+ */
+ save_current_select= thd->lex->current_select;
+ thd->lex->current_select= NULL;
err_status=
sp_trigger->execute_trigger(thd,
&trigger_table->s->db,
&trigger_table->s->table_name,
&subject_table_grants[event][time_type]);
+ thd->lex->current_select= save_current_select;
thd->restore_sub_statement_state(&statement_state);
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 3b2ef92ab48..2cedce497b6 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -173,7 +173,6 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
SELECT_LEX *sl, *first_sl= first_select();
select_result *tmp_result;
bool is_union_select;
- TABLE *empty_table= 0;
DBUG_ENTER("st_select_lex_unit::prepare");
describe= test(additional_options & SELECT_DESCRIBE);
@@ -275,14 +274,6 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
types= first_sl->item_list;
else if (sl == first_sl)
{
- /*
- We need to create an empty table object. It is used
- to create tmp_table fields in Item_type_holder.
- The main reason of this is that we can't create
- field object without table.
- */
- DBUG_ASSERT(!empty_table);
- empty_table= (TABLE*) thd->calloc(sizeof(TABLE));
types.empty();
List_iterator_fast<Item> it(sl->item_list);
Item *item_tmp;
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index ccf1f5b83fe..97ad7d88573 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -25,9 +25,26 @@
#include "sql_trigger.h"
#include "debug_sync.h"
-/* Return 0 if row hasn't changed */
-bool compare_record(TABLE *table)
+/**
+ True if the table's input and output record buffers are comparable using
+ compare_record(TABLE*).
+ */
+bool records_are_comparable(const TABLE *table) {
+ return ((table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ) == 0) ||
+ bitmap_is_subset(table->write_set, table->read_set);
+}
+
+
+/**
+ Compares the input and outbut record buffers of the table to see if a row
+ has changed.
+
+ @return true if row has changed.
+ @return false otherwise.
+*/
+
+bool compare_record(const TABLE *table)
{
if (table->s->can_cmp_whole_record)
return cmp_record(table,record[1]);
@@ -583,9 +600,7 @@ int mysql_update(THD *thd,
the table handler is returning all columns OR if
if all updated columns are read
*/
- can_compare_record= (!(table->file->ha_table_flags() &
- HA_PARTIAL_COLUMN_READ) ||
- bitmap_is_subset(table->write_set, table->read_set));
+ can_compare_record= records_are_comparable(table);
while (!(error=info.read_record(&info)) && !thd->killed)
{
@@ -1697,18 +1712,16 @@ bool multi_update::send_data(List<Item> &not_used_values)
if (table->status & (STATUS_NULL_ROW | STATUS_UPDATED))
continue;
- /*
- We can use compare_record() to optimize away updates if
- the table handler is returning all columns OR if
- if all updated columns are read
- */
if (table == table_to_update)
{
+ /*
+ We can use compare_record() to optimize away updates if
+ the table handler is returning all columns OR if
+ if all updated columns are read
+ */
bool can_compare_record;
- can_compare_record= (!(table->file->ha_table_flags() &
- HA_PARTIAL_COLUMN_READ) ||
- bitmap_is_subset(table->write_set,
- table->read_set));
+ can_compare_record= records_are_comparable(table);
+
table->status|= STATUS_UPDATED;
store_record(table,record[1]);
if (fill_record_n_invoke_before_triggers(thd, *fields_for_table[offset],
@@ -1959,10 +1972,7 @@ int multi_update::do_updates()
goto err;
}
- can_compare_record= (!(table->file->ha_table_flags() &
- HA_PARTIAL_COLUMN_READ) ||
- bitmap_is_subset(table->write_set,
- table->read_set));
+ can_compare_record= records_are_comparable(table);
for (;;)
{
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 87a8dd278c2..884fbe9ed76 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1282,6 +1282,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token YEAR_SYM /* SQL-2003-R */
%token ZEROFILL
+%token IMPOSSIBLE_ACTION /* To avoid warning for yyerrlab1 */
+
%left JOIN_SYM INNER_SYM STRAIGHT_JOIN CROSS LEFT RIGHT
/* A dummy token to force the priority of table_ref production in a join. */
%left TABLE_REF_PRIORITY
@@ -1480,6 +1482,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
init_key_options normal_key_options normal_key_opts all_key_opt
spatial_key_options fulltext_key_options normal_key_opt
fulltext_key_opt spatial_key_opt fulltext_key_opts spatial_key_opts
+ keep_gcc_happy
key_using_alg
server_def server_options_list server_option
definer_opt no_definer definer
@@ -1611,11 +1614,12 @@ statement:
| help
| insert
| install
+ | keep_gcc_happy
+ | keycache
| kill
| load
| lock
| optimize
- | keycache
| parse_vcol_expr
| partition_entry
| preload
@@ -11819,6 +11823,12 @@ user:
system_charset_info, 0) ||
check_host_name(&$$->host))
MYSQL_YYABORT;
+ /*
+ Convert hostname part of username to lowercase.
+ It's OK to use in-place lowercase as long as
+ the character set is utf8.
+ */
+ my_casedn_str(system_charset_info, $$->host.str);
}
| CURRENT_USER optional_braces
{
@@ -14020,6 +14030,13 @@ uninstall:
}
;
+/* Avoid compiler warning from sql_yacc.cc where yyerrlab1 is not used */
+keep_gcc_happy:
+ IMPOSSIBLE_ACTION
+ {
+ YYERROR;
+ }
+
/**
@} (end of group Parser)
*/
diff --git a/sql/table.cc b/sql/table.cc
index 7a2581d5ab8..af842937491 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -432,6 +432,11 @@ void free_table_share(TABLE_SHARE *share)
key_info->flags= 0;
}
}
+ if (share->ha_data_destroy)
+ {
+ share->ha_data_destroy(share->ha_data);
+ share->ha_data_destroy= NULL;
+ }
/* We must copy mem_root from share because share is allocated through it */
memcpy((char*) &mem_root, (char*) &share->mem_root, sizeof(mem_root));
free_root(&mem_root, MYF(0)); // Free's share
@@ -1724,6 +1729,11 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
delete crypted;
delete handler_file;
hash_free(&share->name_hash);
+ if (share->ha_data_destroy)
+ {
+ share->ha_data_destroy(share->ha_data);
+ share->ha_data_destroy= NULL;
+ }
open_table_error(share, error, share->open_errno, errarg);
DBUG_RETURN(error);
diff --git a/sql/table.h b/sql/table.h
index c31ab6b7471..f2d55929ceb 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -482,6 +482,7 @@ typedef struct st_table_share
/** place to store storage engine specific data */
void *ha_data;
+ void (*ha_data_destroy)(void *); /* An optional destructor for ha_data. */
/*