summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2014-03-26 22:25:38 +0100
committerSergei Golubchik <sergii@pisem.net>2014-03-26 22:25:38 +0100
commit10740939eb824bbd792352f654380e258edd7675 (patch)
treea4c68f331f0470b8bd30822de5938a6552f69738 /sql
parenta91c59c2affdebb4b34c2c8000b0b1648d43046d (diff)
parent44002a34e680c79c01df879b540458c2885e97e8 (diff)
downloadmariadb-git-10740939eb824bbd792352f654380e258edd7675.tar.gz
5.5 merge
Diffstat (limited to 'sql')
-rw-r--r--sql/ha_partition.cc146
-rw-r--r--sql/ha_partition.h21
-rw-r--r--sql/item.cc2
-rw-r--r--sql/item.h2
-rw-r--r--sql/item_strfunc.h2
-rw-r--r--sql/mysqld.cc4
-rw-r--r--sql/slave.cc2
-rw-r--r--sql/sql_acl.cc7
-rw-r--r--sql/sql_base.cc11
-rw-r--r--sql/sql_class.cc7
-rw-r--r--sql/sql_class.h16
-rw-r--r--sql/sql_derived.cc50
-rw-r--r--sql/sql_list.h9
-rw-r--r--sql/sql_select.cc24
-rw-r--r--sql/sql_test.cc9
-rw-r--r--sql/table.h4
16 files changed, 233 insertions, 83 deletions
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index 6f8d4b4af14..e683fb91700 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -89,7 +89,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);
/*
If frm_error() is called then we will use this to to find out what file
@@ -5094,7 +5095,10 @@ bool ha_partition::init_record_priority_queue()
uint alloc_len;
uint used_parts= bitmap_bits_set(&m_part_info->read_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;
@@ -5116,12 +5120,24 @@ 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;
}
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;
@@ -5188,9 +5204,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);
@@ -5331,36 +5351,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;
@@ -5377,6 +5373,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
@@ -6077,7 +6112,7 @@ int ha_partition::handle_ordered_index_scan(uchar *buf, bool reverse_order)
i < m_part_spec.start_part;
i= bitmap_get_next_set(&m_part_info->read_partitions, i))
{
- 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, i));
@@ -6126,6 +6161,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
*/
@@ -6142,7 +6182,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)
{
@@ -6151,7 +6191,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);
@@ -6226,7 +6266,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);
@@ -6310,6 +6350,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)
@@ -6327,6 +6368,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));
@@ -8512,19 +8560,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 05262e750f7..71ae84b06a0 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -117,6 +117,8 @@ public:
};
+extern "C" int cmp_key_rowid_part_id(void *ptr, uchar *ref1, uchar *ref2);
+
class ha_partition :public handler
{
private:
@@ -157,6 +159,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
@@ -1264,6 +1282,9 @@ public:
DBUG_ASSERT(h == m_file[i]->ht);
return h;
}
+
+
+ friend int cmp_key_rowid_part_id(void *ptr, uchar *ref1, uchar *ref2);
};
#endif /* HA_PARTITION_INCLUDED */
diff --git a/sql/item.cc b/sql/item.cc
index 8b2b09c68d3..7c04dc00880 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -8497,6 +8497,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 e3ddf56511e..ba7631daeb4 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -4009,7 +4009,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 7b062ad64c6..ff8a916d200 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -1084,7 +1084,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/mysqld.cc b/sql/mysqld.cc
index bf38937979c..438c56659b0 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -2715,9 +2715,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);
thd->unlink();
diff --git a/sql/slave.cc b/sql/slave.cc
index 79a2c4ccd25..c22833abf26 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -4165,6 +4165,7 @@ err:
if (mi->using_gtid != Master_info::USE_GTID_NO)
flush_master_info(mi, TRUE, TRUE);
THD_STAGE_INFO(thd, stage_waiting_for_slave_mutex_on_exit);
+ thd->add_status_to_global();
mysql_mutex_lock(&mi->run_lock);
err_during_init:
@@ -4664,6 +4665,7 @@ log '%s' at position %s, relay log '%s' position: %s%s", RPL_LOG_NAME,
if (rli->mi->using_gtid != Master_info::USE_GTID_NO)
flush_relay_log_info(rli);
THD_STAGE_INFO(thd, stage_waiting_for_slave_mutex_on_exit);
+ thd->add_status_to_global();
mysql_mutex_lock(&rli->run_lock);
err_during_init:
/* We need data_lock, at least to wake up any waiting master_pos_wait() */
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 0578b923841..8e0361bb9bf 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -12044,7 +12044,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_base.cc b/sql/sql_base.cc
index 9c82806a461..fba5708adfe 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1347,6 +1347,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 e85a7d74851..ae863504202 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1487,9 +1487,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();
@@ -1520,6 +1518,7 @@ void THD::cleanup(void)
#endif
mysql_ha_cleanup(this);
+ locked_tables_list.unlock_locked_tables(this);
close_temporary_tables(this);
@@ -1527,8 +1526,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 16e02e6951c..77410c2b52e 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -754,6 +754,11 @@ typedef struct system_status_var
#define last_system_status_var questions
#define last_cleared_system_status_var memory_used
+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);
@@ -3616,6 +3621,13 @@ public:
/* 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);
+ }
+
wait_for_commit *wait_for_commit_ptr;
int wait_for_prior_commit()
{
@@ -4816,10 +4828,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 00ea0977a07..c2941d55dcb 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_select.cc b/sql/sql_select.cc
index d635eec0e28..240fc953f1d 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -3821,6 +3821,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)
{
@@ -14261,7 +14264,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);
@@ -16148,11 +16154,25 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
keyinfo->name= (char*) "distinct_key";
keyinfo->algorithm= HA_KEY_ALG_UNDEF;
keyinfo->is_statistics_from_stat_tables= FALSE;
- keyinfo->rec_per_key=0;
keyinfo->read_stats= NULL;
keyinfo->collected_stats= NULL;
/*
+ 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->user_defined_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
blobs can distinguish NULL from 0. This extra field is not needed
when we do not use UNIQUE indexes for blobs.
diff --git a/sql/sql_test.cc b/sql/sql_test.cc
index 542a3421fcf..c64a5d182a5 100644
--- a/sql/sql_test.cc
+++ b/sql/sql_test.cc
@@ -383,6 +383,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/table.h b/sql/table.h
index 60a8578fc0b..dfcee9e75d6 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -2170,9 +2170,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()
{
@@ -2180,9 +2182,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()
{