Below is the list of changes that have just been committed into a local
5.2 repository of igor. When igor does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet@stripped, 2007-10-03 04:09:52-07:00, igor@stripped +11 -0
WL#2771: BKA, preliminary version without some changes for NDB.
sql/ha_ndbcluster.cc@stripped, 2007-10-03 04:09:43-07:00, igor@stripped +88 -15
WL#2771: BKA, preliminary version without some changes for NDB.
sql/ha_ndbcluster.h@stripped, 2007-10-03 04:09:44-07:00, igor@stripped +9 -0
WL#2771: BKA, preliminary version without some changes for NDB.
sql/handler.h@stripped, 2007-10-03 04:09:44-07:00, igor@stripped +30 -1
WL#2771: BKA, preliminary version without some changes for NDB.
sql/mysql_priv.h@stripped, 2007-10-03 04:09:44-07:00, igor@stripped +1 -0
WL#2771: BKA, preliminary version without some changes for NDB.
sql/mysqld.cc@stripped, 2007-10-03 04:09:44-07:00, igor@stripped +8 -2
WL#2771: BKA, preliminary version without some changes for NDB.
sql/opt_range.cc@stripped, 2007-10-03 04:09:44-07:00, igor@stripped +17 -2
WL#2771: BKA, preliminary version without some changes for NDB.
sql/opt_range.h@stripped, 2007-10-03 04:09:44-07:00, igor@stripped +3 -0
WL#2771: BKA, preliminary version without some changes for NDB.
sql/sql_select.cc@stripped, 2007-10-03 04:09:45-07:00, igor@stripped +304 -148
WL#2771: BKA, preliminary version without some changes for NDB.
sql/sql_select.h@stripped, 2007-10-03 04:09:45-07:00, igor@stripped +163 -47
WL#2771: BKA, preliminary version without some changes for NDB.
storage/innobase/handler/ha_innodb.cc@stripped, 2007-10-03 04:09:45-07:00, igor@stripped +1 -0
WL#2771: BKA, preliminary version without some changes for NDB.
storage/myisam/ha_myisam.cc@stripped, 2007-10-03 04:09:45-07:00, igor@stripped +2 -0
WL#2771: BKA, preliminary version without some changes for NDB.
diff -Nrup a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
--- a/sql/ha_ndbcluster.cc 2007-08-26 04:52:54 -07:00
+++ b/sql/ha_ndbcluster.cc 2007-10-03 04:09:43 -07:00
@@ -4473,6 +4473,7 @@ int ha_ndbcluster::info(uint flag)
if (flag & HA_STATUS_VARIABLE)
{
DBUG_PRINT("info", ("HA_STATUS_VARIABLE"));
+ stats.mrr_length_per_rec= table_share->reclength + 2*sizeof(void*) + sizeof(uint16);
if (m_table_info)
{
if (m_ha_not_exact_count)
@@ -9688,6 +9689,7 @@ read_multi_needs_scan(NDB_INDEX_TYPE cur
}
struct read_multi_callback_data {
+ ha_ndbcluster *h;
const KEY *key_info;
int first_range;
int range;
@@ -9695,6 +9697,44 @@ struct read_multi_callback_data {
RANGE_SEQ_IF *mrr_funcs;
};
+
+/*** psergey: MRR helper hacks ****/
+char* mrr_get_ptr_by_idx2(ha_ndbcluster *h, range_seq_t seq, uint idx)
+{
+ static char *dummy;
+ if (h->mrr_range_cdata)
+ {
+ return h->mrr_range_cdata[idx];
+ }
+ else
+ return dummy;
+}
+
+void mrr_put_ptr2(ha_ndbcluster *h, uint idx, char *data)
+{
+ if (h->mrr_range_cdata)
+ {
+ h->mrr_range_cdata[idx]= data;
+ }
+}
+
+uint16 &mrr_persistent_flag_storage2(ha_ndbcluster *h, range_seq_t seq, uint idx)
+{
+ if (h->mrr_range_flags_buf)
+ {
+ return h->mrr_range_flags_buf[idx];
+ }
+ else
+ {
+ QUICK_RANGE_SEQ_CTX *ctx= (QUICK_RANGE_SEQ_CTX*)seq;
+ return ctx->first[idx]->flag;
+ }
+}
+
+/*** psergey: MRR helper hacks end ****/
+
+
+
/* Callback to set up scan bounds for read multi range. */
static int
read_multi_bounds_callback(void *arg, Uint32 i,
@@ -9709,7 +9749,7 @@ read_multi_bounds_callback(void *arg, Ui
{
data->mrr_funcs->next(data->mrr_iter, &mrr_cur_range);
data->range++;
- if (!(mrr_persistent_flag_storage(data->mrr_iter, data->range)
+ if (!(mrr_persistent_flag_storage2(data->h, data->mrr_iter, data->range)
& (SKIP_RANGE|UNIQUE_RANGE)))
break;
}
@@ -9721,6 +9761,8 @@ read_multi_bounds_callback(void *arg, Ui
return 0; // Success
}
+
+
int ha_ndbcluster::multi_range_read_init(RANGE_SEQ_IF *seq_funcs,
void *seq_init_param,
uint n_ranges, uint mode,
@@ -9730,6 +9772,9 @@ int ha_ndbcluster::multi_range_read_init
Thd_ndb *thd_ndb= get_thd_ndb(current_thd);
DBUG_ENTER("ha_ndbcluster::multi_range_read_init");
+ mrr_range_flags_buf= NULL;
+ mrr_range_cdata= NULL;
+
if (mode & HA_MRR_USE_DEFAULT_IMPL)
{
m_disable_multi_read= TRUE;
@@ -9744,10 +9789,36 @@ int ha_ndbcluster::multi_range_read_init
/**
* Copy arguments into member variables
*/
- multi_range_buffer= buffer;
+ multi_range_buffer= *buffer;
mrr_funcs= *seq_funcs;
mrr_iter= mrr_funcs.init(seq_init_param, n_ranges, mode);
ranges_in_seq= n_ranges;
+
+ mrr_need_range_assoc = !test(mode & HA_MRR_NO_ASSOCIATION);
+ if (mrr_need_range_assoc)
+ {
+/* uint max_records_to_fit=
+ (multi_range_buffer.buffer_end - multi_range_buffer.buffer) /
+ table_share->reclength;
+
+ uint max_size= MIN(n_ranges, max_records_to_fit);
+*/
+ // Persistent flag storage
+ // psergey-todo: check if we need to align the pointers.
+ mrr_range_flags_buf= (uint16*) multi_range_buffer.buffer;
+ multi_range_buffer.buffer += n_ranges * sizeof(uint16);
+
+ // Range associator
+ mrr_range_cdata= (char**) multi_range_buffer.buffer;
+ multi_range_buffer.buffer += n_ranges * sizeof(void*);
+ }
+
+ if (multi_range_buffer.buffer_end - multi_range_buffer.buffer <
+ (ptrdiff_t)table_share->reclength)
+ {
+ /* Not enough memory for even one record */
+ DBUG_RETURN(1);
+ }
res= multi_range_start_retrievals(-1);
if (first_unstarted_range == n_ranges)
@@ -9758,7 +9829,7 @@ int ha_ndbcluster::multi_range_read_init
* This as we don't want mysqld to reuse the buffer when we read
* the remaining ranges
*/
- buffer->end_of_used_area= multi_range_buffer->buffer_end;
+ buffer->end_of_used_area= multi_range_buffer.buffer_end;
}
else
{
@@ -9777,7 +9848,7 @@ int ha_ndbcluster::multi_range_start_ret
NdbOperation* op;
NDB_INDEX_TYPE cur_index_type= get_index_type(active_index);
DBUG_ENTER("multi_range_start_retrievals");
-
+
/**
* read multi range will read ranges as follows (if not ordered)
*
@@ -9805,8 +9876,8 @@ int ha_ndbcluster::multi_range_start_ret
const NdbOperation* lastOp= m_active_trans->getLastDefinedOperation();
NdbOperation::LockMode lm=
(NdbOperation::LockMode)get_ndb_lock_type(m_lock.type, table->read_set);
- uchar *row_buf= (uchar *)multi_range_buffer->buffer;
- const uchar *end_of_buffer= multi_range_buffer->buffer_end;
+ uchar *row_buf= (uchar *)multi_range_buffer.buffer;
+ const uchar *end_of_buffer= multi_range_buffer.buffer_end;
uint num_scan_ranges= 0;
int range_no= -1;
int mrr_range_no= starting_range;
@@ -9814,11 +9885,13 @@ int ha_ndbcluster::multi_range_start_ret
// ToDo: proper interface to save/retrieve point to iterate from
QUICK_RANGE_SEQ_CTX *ctx= (QUICK_RANGE_SEQ_CTX*)mrr_iter;
QUICK_RANGE **callback_ctx_cur= ctx->cur;
+ data.h= this;
data.first_range= starting_range;
while (!(range_res= mrr_funcs.next(mrr_iter, &mrr_cur_range)) &&
row_buf+reclength <= end_of_buffer) // ToDo: is this really correct, will not mrr_cur_range be offset on reentering
{
+ mrr_put_ptr2(this, mrr_range_no+1, mrr_cur_range.ptr);
range_no++;
mrr_range_no++;
part_id_range part_spec;
@@ -9840,11 +9913,11 @@ int ha_ndbcluster::multi_range_start_ret
partition
*/
row_buf += reclength;
- mrr_persistent_flag_storage(mrr_iter, mrr_range_no)|= SKIP_RANGE;
+ mrr_persistent_flag_storage2(this, mrr_iter, mrr_range_no)|= SKIP_RANGE;
continue;
}
}
- mrr_persistent_flag_storage(mrr_iter, mrr_range_no)&= ~(uint)SKIP_RANGE;
+ mrr_persistent_flag_storage2(this, mrr_iter, mrr_range_no)&= ~(uint)SKIP_RANGE;
if (read_multi_needs_scan(cur_index_type, key_info, &mrr_cur_range))
{
@@ -9856,7 +9929,7 @@ int ha_ndbcluster::multi_range_start_ret
break; // ToDo: is this really correct, will not mrr_cur_range be offset on reentering
/* Include this range in the ordered index scan. */
- mrr_persistent_flag_storage(mrr_iter, mrr_range_no)&= ~(uint)UNIQUE_RANGE;
+ mrr_persistent_flag_storage2(this, mrr_iter, mrr_range_no)&= ~(uint)UNIQUE_RANGE;
num_scan_ranges++;
}
else
@@ -9870,7 +9943,7 @@ int ha_ndbcluster::multi_range_start_ret
if (row_buf + reclength > end_of_buffer)
break;
- mrr_persistent_flag_storage(mrr_iter, mrr_range_no)|= UNIQUE_RANGE;
+ mrr_persistent_flag_storage2(this, mrr_iter, mrr_range_no)|= UNIQUE_RANGE;
if (!(op= pk_unique_index_read_key(active_index,
mrr_cur_range.start_key.key,
@@ -9951,7 +10024,7 @@ int ha_ndbcluster::multi_range_start_ret
if (execute_no_commit_ie(this, m_active_trans, true))
ERR_RETURN(m_active_trans->getNdbError());
- m_multi_range_result_ptr= (uchar*)multi_range_buffer->buffer;
+ m_multi_range_result_ptr= (uchar*)multi_range_buffer.buffer;
first_running_range= first_range_in_batch= starting_range + 1;
first_unstarted_range= mrr_range_no + 1;
DBUG_RETURN(0);
@@ -9971,12 +10044,12 @@ int ha_ndbcluster::multi_range_read_next
//for each range (we should have remembered the number)
for (;first_running_range < first_unstarted_range; first_running_range++)
{
- if (mrr_persistent_flag_storage(mrr_iter, first_running_range) & SKIP_RANGE)
+ if (mrr_persistent_flag_storage2(this, mrr_iter, first_running_range) & SKIP_RANGE)
{
/* Nothing in this range, move to next one. */
continue;
}
- else if (mrr_persistent_flag_storage(mrr_iter, first_running_range) & UNIQUE_RANGE)
+ else if (mrr_persistent_flag_storage2(this, mrr_iter, first_running_range) & UNIQUE_RANGE)
{
/*
Move to next range; we can have at most one record from a unique range.
@@ -9989,7 +10062,7 @@ int ha_ndbcluster::multi_range_read_next
const NdbError &error= op->getNdbError();
if (error.code == 0)
{
- *range_info= mrr_get_ptr_by_idx(mrr_iter, first_running_range++);
+ *range_info= mrr_get_ptr_by_idx2(this, mrr_iter, first_running_range++);
memcpy(table->record[0], src_row, table_share->reclength);
if (table_share->primary_key == MAX_KEY)
{
@@ -10042,7 +10115,7 @@ int ha_ndbcluster::multi_range_read_next
(expected_range_no= first_running_range - first_range_in_batch)
== current_range_no)
{
- *range_info= mrr_get_ptr_by_idx(mrr_iter, first_running_range);
+ *range_info= mrr_get_ptr_by_idx2(this, mrr_iter, current_range_no);
/* Copy out data from the new row. */
if (table_share->primary_key == MAX_KEY)
{
diff -Nrup a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h
--- a/sql/ha_ndbcluster.h 2007-08-25 12:13:31 -07:00
+++ b/sql/ha_ndbcluster.h 2007-10-03 04:09:44 -07:00
@@ -292,8 +292,17 @@ private:
uint first_running_range;
uint first_range_in_batch;
uint first_unstarted_range;
+ /* TRUE <=> need range association */
+ bool mrr_need_range_assoc;
+
int multi_range_start_retrievals(int first_range);
public:
+ /* MRR: Buffer for range flags storage (#ranges elements) */
+ uint16 *mrr_range_flags_buf;
+ /* MRR: range_no -> range_id translation table (#ranges elements) */
+ char **mrr_range_cdata;
+ // TODO ^ #ranges is too much.
+ // The real value should be MAX(#ranges, buf_size / record_size)
bool null_value_index_search(KEY_MULTI_RANGE *ranges,
KEY_MULTI_RANGE *end_range,
diff -Nrup a/sql/handler.h b/sql/handler.h
--- a/sql/handler.h 2007-08-26 04:52:54 -07:00
+++ b/sql/handler.h 2007-10-03 04:09:44 -07:00
@@ -964,6 +964,30 @@ typedef struct st_range_seq_if
1 - No more ranges
*/
uint (*next) (range_seq_t seq, KEY_MULTI_RANGE *range);
+ /*
+ The following two fields may have been added temporarrily
+ to neutralize some additional assumptions made by the current NDB code.
+ */
+
+ /*
+ Save current iterator position.
+
+ NOTE
+ The call may be made before the first (*next)() call.
+ The call may not be made after the (*next) call returned 1.
+ RETURN
+ An opaque value representing current position of the iterator.
+
+ */
+ void (*save_current_pos)(range_seq_t seq, uint *range_no, void **pos);
+
+ /*
+ Restore iterator position
+
+ restore_pos()
+ pos Value previously obtained from save_current_pos call.
+ */
+ void (*restore_pos)(range_seq_t seq,uint range_no, void *pos);
} RANGE_SEQ_IF;
uint16 &mrr_persistent_flag_storage(range_seq_t seq, uint idx);
@@ -1092,6 +1116,11 @@ public:
time_t check_time;
time_t update_time;
uint block_size; /* index block size */
+
+ /*
+ Number of buffer bytes that native MRR implementation needs,
+ */
+ uint mrr_length_per_rec;
ha_statistics():
data_file_length(0), max_data_file_length(0),
@@ -1164,7 +1193,7 @@ public:
/* Multi range read implementation-used members: */
range_seq_t mrr_iter; /* MRR range sequence iterator being traversed */
RANGE_SEQ_IF mrr_funcs; /* Saved MRR range sequence traversal functions */
- HANDLER_BUFFER *multi_range_buffer; /* Saved MRR buffer info */
+ HANDLER_BUFFER multi_range_buffer; /* Saved MRR buffer info */
uint ranges_in_seq; /* Total number of ranges in the traversed sequence */
/* TRUE <=> source MRR ranges and the output are ordered */
bool mrr_is_output_sorted;
diff -Nrup a/sql/mysql_priv.h b/sql/mysql_priv.h
--- a/sql/mysql_priv.h 2007-08-26 15:38:30 -07:00
+++ b/sql/mysql_priv.h 2007-10-03 04:09:44 -07:00
@@ -507,6 +507,7 @@ protected:
/* @@optimizer_switch flags */
#define OPTIMIZER_SWITCH_NO_MATERIALIZATION 1
#define OPTIMIZER_SWITCH_NO_SEMIJOIN 2
+#define OPTIMIZER_SWITCH_NO_BKA 4
/*
diff -Nrup a/sql/mysqld.cc b/sql/mysqld.cc
--- a/sql/mysqld.cc 2007-08-26 15:38:31 -07:00
+++ b/sql/mysqld.cc 2007-10-03 04:09:44 -07:00
@@ -267,7 +267,7 @@ TYPELIB sql_mode_typelib= { array_elemen
static const char *optimizer_switch_names[]=
{
- "no_materialization", "no_semijoin",
+ "no_materialization", "no_semijoin", "no_bka",
NullS
};
@@ -275,7 +275,8 @@ static const char *optimizer_switch_name
static const unsigned int optimizer_switch_names_len[]=
{
/*no_materialization*/ 19,
- /*no_semijoin*/ 11
+ /*no_semijoin*/ 11,
+ /*no_bka*/ 6
};
TYPELIB optimizer_switch_typelib= { array_elements(optimizer_switch_names)-1,"",
@@ -5921,8 +5922,13 @@ log and this option does nothing anymore
"The size of the buffer that is used for full joins.",
(uchar**) &global_system_variables.join_buff_size,
(uchar**) &max_system_variables.join_buff_size, 0, GET_ULONG,
+#if 0
REQUIRED_ARG, 128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, ~0L, MALLOC_OVERHEAD,
IO_SIZE, 0},
+#else
+ REQUIRED_ARG, 128*1024L, 64+MALLOC_OVERHEAD, ~0L, MALLOC_OVERHEAD,
+ 64, 0},
+#endif
{"keep_files_on_create", OPT_KEEP_FILES_ON_CREATE,
"Don't overwrite stale .MYD and .MYI even if no directory is specified.",
(uchar**) &global_system_variables.keep_files_on_create,
diff -Nrup a/sql/opt_range.cc b/sql/opt_range.cc
--- a/sql/opt_range.cc 2007-08-26 15:38:32 -07:00
+++ b/sql/opt_range.cc 2007-10-03 04:09:44 -07:00
@@ -7402,7 +7402,8 @@ ha_rows check_quick_select(PARAM *param,
uint *mrr_flags, uint *bufsize, COST_VECT *cost)
{
SEL_ARG_RANGE_SEQ seq;
- RANGE_SEQ_IF seq_if = {sel_arg_range_seq_init, sel_arg_range_seq_next};
+ RANGE_SEQ_IF seq_if = {sel_arg_range_seq_init, sel_arg_range_seq_next,
+ NULL, NULL};
handler *file= param->table->file;
ha_rows rows;
uint keynr= param->real_keynr[idx];
@@ -8312,7 +8313,9 @@ int QUICK_RANGE_SELECT::reset()
if (sorted)
mrr_flags |= HA_MRR_SORTED;
- RANGE_SEQ_IF seq_funcs= {quick_range_seq_init, quick_range_seq_next};
+ RANGE_SEQ_IF seq_funcs= {quick_range_seq_init, quick_range_seq_next,
+ quick_range_seq_save_current_pos,
+ quick_range_seq_restore_pos};
error= file->multi_range_read_init(&seq_funcs, (void*)this, ranges.elements,
mrr_flags, mrr_buf_desc? mrr_buf_desc:
&empty_buf);
@@ -8388,6 +8391,18 @@ uint quick_range_seq_next(range_seq_t rs
return 0;
}
+void quick_range_seq_save_current_pos(range_seq_t rseq,
+ uint *range_no, void **pos)
+{
+ QUICK_RANGE_SEQ_CTX *ctx= (QUICK_RANGE_SEQ_CTX*)rseq;
+ *pos= ctx->cur;
+}
+
+void quick_range_seq_restore_pos(range_seq_t rseq, uint range_no, void *pos)
+{
+ QUICK_RANGE_SEQ_CTX *ctx= (QUICK_RANGE_SEQ_CTX*)rseq;
+ ctx->cur = (QUICK_RANGE**)pos;
+}
/*
MRR range sequence interface: array<QUICK_RANGE> impl: utility func for NDB
diff -Nrup a/sql/opt_range.h b/sql/opt_range.h
--- a/sql/opt_range.h 2007-06-27 12:15:25 -07:00
+++ b/sql/opt_range.h 2007-10-03 04:09:44 -07:00
@@ -275,6 +275,9 @@ typedef struct st_quick_range_seq_ctx
range_seq_t quick_range_seq_init(void *init_param, uint n_ranges, uint flags);
uint quick_range_seq_next(range_seq_t rseq, KEY_MULTI_RANGE *range);
+void quick_range_seq_save_current_pos(range_seq_t rseq,
+ uint *range_no, void **pos);
+void quick_range_seq_restore_pos(range_seq_t rseq, uint range_no, void *pos);
/*
diff -Nrup a/sql/sql_select.cc b/sql/sql_select.cc
--- a/sql/sql_select.cc 2007-09-04 11:30:36 -07:00
+++ b/sql/sql_select.cc 2007-10-03 04:09:45 -07:00
@@ -133,8 +133,6 @@ evaluate_join_record(JOIN *join, JOIN_TA
static enum_nested_loop_state
evaluate_null_complemented_join_record(JOIN *join, JOIN_TAB *join_tab);
static enum_nested_loop_state
-flush_cached_records(JOIN *join, JOIN_TAB *join_tab, bool skip_last);
-static enum_nested_loop_state
end_send(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
static enum_nested_loop_state
end_send_group(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
@@ -193,12 +191,6 @@ static int remove_dup_with_hash_index(TH
uint field_count, Field **first_field,
ulong key_length,Item *having);
-static int join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count);
-static ulong used_blob_length(CACHE_FIELD **ptr);
-static bool store_record_in_cache(JOIN_CACHE *cache);
-static void reset_cache_read(JOIN_CACHE *cache);
-static void reset_cache_write(JOIN_CACHE *cache);
-static void read_cached_record(JOIN_TAB *tab);
static bool cmp_buffer_with_ref(JOIN_TAB *tab);
static bool setup_new_fields(THD *thd, List<Item> &fields,
List<Item> &all_fields, ORDER *new_order);
@@ -6978,7 +6970,8 @@ make_simple_join(JOIN *join,TABLE *tmp_t
join->row_limit=join->unit->select_limit_cnt;
join->do_send_rows = (join->row_limit) ? 1 : 0;
- join_tab->cache.buff=0; /* No caching */
+ join_tab->cache= 0; /* No caching */
+ join_tab->cache_select= 0;
join_tab->table=tmp_table;
join_tab->select=0;
join_tab->select_cond=0;
@@ -7533,10 +7526,10 @@ make_join_select(JOIN *join,SQL_SELECT *
current_map, 0)))
{
DBUG_EXECUTE("where",print_where(tmp,"cache"););
- tab->cache.select=(SQL_SELECT*)
+ tab->cache_select=(SQL_SELECT*)
thd->memdup((uchar*) sel, sizeof(SQL_SELECT));
- tab->cache.select->cond=tmp;
- tab->cache.select->read_tables=join->const_table_map;
+ tab->cache_select->cond=tmp;
+ tab->cache_select->read_tables=join->const_table_map;
}
}
}
@@ -8050,6 +8043,26 @@ make_join_readinfo(JOIN *join, ulonglong
tab->quick=0;
tab->read_first_record= join_read_key;
tab->read_record.read_record= join_no_more_records;
+
+ {
+ bool do_bka= !test(join->thd->variables.optimizer_switch &
+ OPTIMIZER_SWITCH_NO_BKA);
+
+ using_join_cache= FALSE;
+ if (do_bka &&
+ i != join->const_tables && !(options & SELECT_NO_JOIN_CACHE) &&
+ tab->use_quick != 2 && !tab->first_inner && i <= no_jbuf_after &&
+ !tab->insideout_match_tab)
+ {
+ if ((options & SELECT_DESCRIBE) ||
+ (tab->cache || (tab->cache= new JOIN_CACHE_BKA(join, tab))) &&
+ !tab->cache->init())
+ {
+ using_join_cache= TRUE;
+ tab[-1].next_select=sub_select_cache; /* Patch previous */
+ }
+ }
+ }
if (table->covering_keys.is_set(tab->ref.key) &&
!table->no_keyread)
{
@@ -8057,7 +8070,7 @@ make_join_readinfo(JOIN *join, ulonglong
table->file->extra(HA_EXTRA_KEYREAD);
}
else
- push_index_cond(tab, tab->ref.key, TRUE);
+ push_index_cond(tab, tab->ref.key, !using_join_cache);
break;
case JT_REF_OR_NULL:
case JT_REF:
@@ -8069,25 +8082,43 @@ make_join_readinfo(JOIN *join, ulonglong
}
delete tab->quick;
tab->quick=0;
- if (table->covering_keys.is_set(tab->ref.key) &&
- !table->no_keyread)
- {
- table->key_read=1;
- table->file->extra(HA_EXTRA_KEYREAD);
- }
- else
- push_index_cond(tab, tab->ref.key, TRUE);
if (tab->type == JT_REF)
{
tab->read_first_record= join_read_always_key;
tab->read_record.read_record= tab->insideout_match_tab?
join_read_next_same_diff : join_read_next_same;
+
+ bool do_bka= !test(join->thd->variables.optimizer_switch &
+ OPTIMIZER_SWITCH_NO_BKA);
+
+ using_join_cache= FALSE;
+ if (do_bka &&
+ i != join->const_tables && !(options & SELECT_NO_JOIN_CACHE) &&
+ tab->use_quick != 2 && !tab->first_inner && i <= no_jbuf_after &&
+ !tab->insideout_match_tab)
+ {
+ if ((options & SELECT_DESCRIBE) ||
+ (tab->cache || (tab->cache= new JOIN_CACHE_BKA(join, tab))) &&
+ !tab->cache->init())
+ {
+ using_join_cache= TRUE;
+ tab[-1].next_select=sub_select_cache; /* Patch previous */
+ }
+ }
}
else
{
tab->read_first_record= join_read_always_key_or_null;
tab->read_record.read_record= join_read_next_same_or_null;
}
+ if (table->covering_keys.is_set(tab->ref.key) &&
+ !table->no_keyread)
+ {
+ table->key_read=1;
+ table->file->extra(HA_EXTRA_KEYREAD);
+ }
+ else
+ push_index_cond(tab, tab->ref.key, !using_join_cache);
break;
case JT_FT:
table->status=STATUS_NO_RECORD;
@@ -8106,8 +8137,8 @@ make_join_readinfo(JOIN *join, ulonglong
!tab->insideout_match_tab)
{
if ((options & SELECT_DESCRIBE) ||
- !join_init_cache(join->thd,join->join_tab+join->const_tables,
- i-join->const_tables))
+ (tab->cache || (tab->cache= new JOIN_CACHE_BNL(join, tab))) &&
+ !tab->cache->init())
{
using_join_cache= TRUE;
tab[-1].next_select=sub_select_cache; /* Patch previous */
@@ -8234,8 +8265,8 @@ void JOIN_TAB::cleanup()
select= 0;
delete quick;
quick= 0;
- x_free(cache.buff);
- cache.buff= 0;
+ if (cache)
+ cache->free();
limit= 0;
if (table)
{
@@ -12911,13 +12942,16 @@ do_select(JOIN *join,List<Item> *fields,
enum_nested_loop_state
-sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
+sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)
{
enum_nested_loop_state rc;
+ JOIN_CACHE *cache= join_tab->cache;
+
+ join_tab->cache->reset_join(join);
if (end_of_records)
{
- rc= flush_cached_records(join,join_tab,FALSE);
+ rc= cache->join_records(FALSE);
if (rc == NESTED_LOOP_OK || rc == NESTED_LOOP_NO_MORE_ROWS)
rc= sub_select(join,join_tab,end_of_records);
return rc;
@@ -12929,11 +12963,11 @@ sub_select_cache(JOIN *join,JOIN_TAB *jo
}
if (join_tab->use_quick != 2 || test_if_quick_select(join_tab) <= 0)
{
- if (!store_record_in_cache(&join_tab->cache))
+ if (!cache->put_record())
return NESTED_LOOP_OK; // There is more room in cache
- return flush_cached_records(join,join_tab,FALSE);
+ return cache->join_records(FALSE);
}
- rc= flush_cached_records(join, join_tab, TRUE);
+ rc= cache->join_records(TRUE);
if (rc == NESTED_LOOP_OK || rc == NESTED_LOOP_NO_MORE_ROWS)
rc= sub_select(join, join_tab, end_of_records);
return rc;
@@ -13422,18 +13456,18 @@ evaluate_null_complemented_join_record(J
}
-static enum_nested_loop_state
-flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last)
+enum_nested_loop_state
+JOIN_CACHE_BNL::join_records(bool skip_last)
{
enum_nested_loop_state rc= NESTED_LOOP_OK;
int error;
READ_RECORD *info;
join_tab->table->null_row= 0;
- if (!join_tab->cache.records)
+ if (!records)
return NESTED_LOOP_OK; /* Nothing to do */
if (skip_last)
- (void) store_record_in_cache(&join_tab->cache); // Must save this for later
+ put_record(); // Must save this for later
if (join_tab->use_quick == 2)
{
if (join_tab->select->quick)
@@ -13442,10 +13476,10 @@ flush_cached_records(JOIN *join,JOIN_TAB
join_tab->select->quick=0;
}
}
- /* read through all records */
+ /* read through all records */
if ((error=join_init_read_record(join_tab)))
{
- reset_cache_write(&join_tab->cache);
+ reset(TRUE);
return error < 0 ? NESTED_LOOP_NO_MORE_ROWS: NESTED_LOOP_ERROR;
}
@@ -13463,25 +13497,25 @@ flush_cached_records(JOIN *join,JOIN_TAB
join->thd->send_kill_message();
return NESTED_LOOP_KILLED; // Aborted by user /* purecov: inspected */
}
- SQL_SELECT *select=join_tab->select;
if (rc == NESTED_LOOP_OK &&
- (!join_tab->cache.select || !join_tab->cache.select->skip_record()))
+ (!select || !select->skip_record()))
{
uint i;
- reset_cache_read(&join_tab->cache);
- for (i=(join_tab->cache.records- (skip_last ? 1 : 0)) ; i-- > 0 ;)
+ reset(FALSE);
+ for (i= records - (skip_last ? 1 : 0) ; i-- > 0 ;)
{
- read_cached_record(join_tab);
- if (!select || !select->skip_record())
+ get_record();
+ if (!join_tab->select || !join_tab->select->skip_record())
{
int res= 0;
if (!join_tab->check_weed_out_table ||
- !(res= do_sj_dups_weedout(join->thd, join_tab->check_weed_out_table)))
+ !(res= do_sj_dups_weedout(join->thd,
+ join_tab->check_weed_out_table)))
{
rc= (join_tab->next_select)(join,join_tab+1,0);
if (rc != NESTED_LOOP_OK && rc != NESTED_LOOP_NO_MORE_ROWS)
{
- reset_cache_write(&join_tab->cache);
+ reset(TRUE);
return rc;
}
}
@@ -13493,12 +13527,12 @@ flush_cached_records(JOIN *join,JOIN_TAB
} while (!(error=info->read_record(info)));
if (skip_last)
- read_cached_record(join_tab); // Restore current record
- reset_cache_write(&join_tab->cache);
+ get_record(); // Restore current record
+ reset(TRUE);
if (error > 0) // Fatal error
return NESTED_LOOP_ERROR; /* purecov: inspected */
for (JOIN_TAB *tmp2=join->join_tab; tmp2 != join_tab ; tmp2++)
- tmp2->table->status=tmp2->status;
+ tmp2->table->status= tmp2->status;
return NESTED_LOOP_OK;
}
@@ -16060,47 +16094,47 @@ SORT_FIELD *make_unireg_sortorder(ORDER
records
******************************************************************************/
-static int
-join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count)
+int
+JOIN_CACHE::init()
{
reg1 uint i;
- uint length, blobs;
+ uint table_count;
size_t size;
- CACHE_FIELD *copy,**blob_ptr;
- JOIN_CACHE *cache;
- JOIN_TAB *join_tab;
- DBUG_ENTER("join_init_cache");
+ CACHE_FIELD *copy;
+ CACHE_FIELD **copy_ptr;
+ JOIN_TAB * tables;
+ JOIN_TAB *tab;
+ DBUG_ENTER("JOIN_CACHE::init");
- cache= &tables[table_count].cache;
- cache->fields=blobs=0;
+ fields=blobs=0;
- join_tab=tables;
- for (i=0 ; i < table_count ; i++,join_tab++)
- {
- if (!join_tab->used_fieldlength) /* Not calced yet */
- calc_used_field_length(thd, join_tab);
- cache->fields+=join_tab->used_fields;
- blobs+=join_tab->used_blobs;
+ select= join_tab->cache_select;
+ tables= join->join_tab+join->const_tables;
+ table_count= join_tab-tables;
+ for (i= 0, tab= tables ; i < table_count ; i++, tab++)
+ {
+ if (!tab->used_fieldlength) /* Not calced yet */
+ calc_used_field_length(join->thd, tab);
+ fields+= tab->used_fields;
+ blobs+= tab->used_blobs;
/* SemiJoinDuplicateElimination: reserve space for rowid */
- if (join_tab->rowid_keep_flags & JOIN_TAB::KEEP_ROWID)
+ if (tab->rowid_keep_flags & JOIN_TAB::KEEP_ROWID)
{
- cache->fields++;
- join_tab->used_fieldlength += join_tab->table->file->ref_length;
+ fields++;
+ tab->used_fieldlength += tab->table->file->ref_length;
}
}
- if (!(cache->field=(CACHE_FIELD*)
- sql_alloc(sizeof(CACHE_FIELD)*(cache->fields+table_count*2)+(blobs+1)*
-
- sizeof(CACHE_FIELD*))))
+ if (!(field=(CACHE_FIELD*)
+ sql_alloc(sizeof(CACHE_FIELD)*(fields+table_count*2)+
+ sizeof(CACHE_FIELD*)*(blobs+1))))
{
- my_free((uchar*) cache->buff,MYF(0)); /* purecov: inspected */
- cache->buff=0; /* purecov: inspected */
+ my_free((uchar*) buff,MYF(0)); /* purecov: inspected */
+ buff=0; /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */
}
- copy=cache->field;
- blob_ptr=cache->blob_ptr=(CACHE_FIELD**)
- (cache->field+cache->fields+table_count*2);
+ copy= field;
+ copy_ptr= blob_ptr= (CACHE_FIELD**) (field+fields+table_count*2);
length=0;
for (i=0 ; i < table_count ; i++)
@@ -16116,9 +16150,9 @@ join_init_cache(THD *thd,JOIN_TAB *table
if (bitmap_is_set(read_set, field->field_index))
{
used_fields--;
- length+=field->fill_cache_field(copy);
+ length+= field->fill_cache_field(copy);
if (copy->blob_field)
- (*blob_ptr++)=copy;
+ (*copy_ptr++)= copy;
if (field->maybe_null())
null_fields++;
copy->get_rowid= NULL;
@@ -16135,7 +16169,7 @@ join_init_cache(THD *thd,JOIN_TAB *table
copy->get_rowid= NULL;
length+=copy->length;
copy++;
- cache->fields++;
+ fields++;
}
/* If outer join table, copy null_row flag */
if (tables[i].table->maybe_null)
@@ -16147,7 +16181,7 @@ join_init_cache(THD *thd,JOIN_TAB *table
copy->get_rowid= NULL;
length+=copy->length;
copy++;
- cache->fields++;
+ fields++;
}
/* SemiJoinDuplicateElimination: Allocate space for rowid if needed */
if (tables[i].rowid_keep_flags & JOIN_TAB::KEEP_ROWID)
@@ -16168,53 +16202,61 @@ join_init_cache(THD *thd,JOIN_TAB *table
}
}
- cache->length=length+blobs*sizeof(char*);
- cache->blobs=blobs;
- *blob_ptr=0; /* End sequentel */
- size=max(thd->variables.join_buff_size, cache->length);
- if (!(cache->buff=(uchar*) my_malloc(size,MYF(0))))
- DBUG_RETURN(1); /* Don't use cache */ /* purecov: inspected */
- cache->end=cache->buff+size;
- reset_cache_write(cache);
+ length+= blobs*sizeof(char*);
+ *copy_ptr=0; /* End sequentel */
+ size= max(join->thd->variables.join_buff_size, length);
+ if (!(buff=(uchar*) my_malloc(size,MYF(0))))
+ DBUG_RETURN(1); /* Don't use cache */ /* purecov: inspected */
+ end_pos= end= buff+size;
+ reset(TRUE);
DBUG_RETURN(0);
}
-static ulong
-used_blob_length(CACHE_FIELD **ptr)
+ulong JOIN_CACHE::used_blob_length()
{
- uint length,blob_length;
- for (length=0 ; *ptr ; ptr++)
+ uint length;
+ uint blob_length;
+ CACHE_FIELD **ptr= blob_ptr;
+ for (length= 0; *ptr; ptr++)
{
- (*ptr)->blob_length=blob_length=(*ptr)->blob_field->get_length();
- length+=blob_length;
+ (*ptr)->blob_length= blob_length= (*ptr)->blob_field->get_length();
+ length+= blob_length;
(*ptr)->blob_field->get_ptr(&(*ptr)->str);
}
return length;
}
-static bool
-store_record_in_cache(JOIN_CACHE *cache)
+uint JOIN_CACHE::write_record_data(bool *is_full)
{
uint length;
- uchar *pos;
- CACHE_FIELD *copy,*end_field;
+ CACHE_FIELD *copy;
+ uchar *pos= this->pos;
+ uchar *init_pos= pos;
+ CACHE_FIELD *end_field= field+fields;
bool last_record;
- pos=cache->pos;
- end_field=cache->field+cache->fields;
-
- length=cache->length;
- if (cache->blobs)
- length+=used_blob_length(cache->blob_ptr);
- if ((last_record= (length + cache->length > (size_t) (cache->end - pos))))
- cache->ptr_record=cache->records;
+ length= pack_length();
+ if (blobs)
+ length+= used_blob_length();
/*
- There is room in cache. Put record there
+ The current record is considered as the last one written in the cache if
+ there is not enough space left to store its blob values or if we can't
+ guarantee that this space is large enough to hold additionally the parts
+ of the next record excluding its blob values.
*/
- cache->records++;
- for (copy=cache->field ; copy < end_field; copy++)
+ last_record= (length+pack_length()+addon_length() > (uint) (end_pos - pos));
+
+ /*
+ This function is called only in the case when there is enough
+ space left in the cache to store at least non-blob parts of
+ the current record.
+ */
+ if (!last_record)
+ ptr_record= records;
+ records++;
+ for (copy= field; copy < end_field; copy++)
{
if (copy->blob_field)
{
@@ -16222,14 +16264,16 @@ store_record_in_cache(JOIN_CACHE *cache)
{
copy->blob_field->get_image(pos, copy->length+sizeof(char*),
copy->blob_field->charset());
- pos+=copy->length+sizeof(char*);
+ pos+= copy->length+sizeof(char*);
}
else
{
- copy->blob_field->get_image(pos, copy->length, // blob length
+ // Copy the length of the blob:
+ copy->blob_field->get_image(pos, copy->length,
copy->blob_field->charset());
- memcpy(pos+copy->length,copy->str,copy->blob_length); // Blob data
- pos+=copy->length+copy->blob_length;
+ // Copy the blob data:
+ memcpy(pos+copy->length, copy->str, copy->blob_length);
+ pos+= copy->length+copy->blob_length;
}
}
else
@@ -16240,56 +16284,54 @@ store_record_in_cache(JOIN_CACHE *cache)
if (copy->strip)
{
- uchar *str,*end;
- for (str=copy->str,end= str+copy->length;
- end > str && end[-1] == ' ' ;
+ uchar *str, *end;
+ for (str= copy->str, end= str+copy->length;
+ end > str && end[-1] == ' ';
end--) ;
length=(uint) (end-str);
- memcpy(pos+2, str, length);
int2store(pos, length);
+ memcpy(pos+2, str, length);
pos+= length+2;
}
else
{
- memcpy(pos,copy->str,copy->length);
+ memcpy(pos, copy->str, copy->length);
pos+=copy->length;
}
}
}
- cache->pos=pos;
- return last_record || (size_t) (cache->end - pos) < cache->length;
+ this->pos= pos;
+ *is_full= last_record || (size_t) (end_pos - pos) < pack_length();
+ return (uint) (pos-init_pos);
}
-static void
-reset_cache_read(JOIN_CACHE *cache)
-{
- cache->record_nr=0;
- cache->pos=cache->buff;
-}
-
-
-static void reset_cache_write(JOIN_CACHE *cache)
+void
+JOIN_CACHE::reset(bool is_for_write)
{
- reset_cache_read(cache);
- cache->records= 0;
- cache->ptr_record= (uint) ~0;
+ record_nr= 0;
+ pos= buff;
+ if (is_for_write)
+ {
+ records= 0;
+ ptr_record= (uint) ~0;
+ }
}
-static void
-read_cached_record(JOIN_TAB *tab)
+uint JOIN_CACHE::read_record_data()
{
- uchar *pos;
uint length;
- bool last_record;
- CACHE_FIELD *copy,*end_field;
+ uchar *pos= this->pos;
+ uchar *init_pos= pos;
+ bool last_record= record_nr == ptr_record;
+ CACHE_FIELD *end_field= field+fields;
+
+ if (record_nr == records)
+ return 0;
+ record_nr++;
- last_record=tab->cache.record_nr++ == tab->cache.ptr_record;
- pos=tab->cache.pos;
- for (copy=tab->cache.field,end_field=copy+tab->cache.fields ;
- copy < end_field;
- copy++)
+ for (CACHE_FIELD *copy= field; copy < end_field; copy++)
{
if (copy->blob_field)
{
@@ -16297,12 +16339,12 @@ read_cached_record(JOIN_TAB *tab)
{
copy->blob_field->set_image(pos, copy->length+sizeof(char*),
copy->blob_field->charset());
- pos+=copy->length+sizeof(char*);
+ pos+= copy->length+sizeof(char*);
}
else
{
copy->blob_field->set_ptr(pos, pos+copy->length);
- pos+=copy->length+copy->blob_field->get_length();
+ pos+= copy->length+copy->blob_field->get_length();
}
}
else
@@ -16312,17 +16354,131 @@ read_cached_record(JOIN_TAB *tab)
length= uint2korr(pos);
memcpy(copy->str, pos+2, length);
memset(copy->str+length, ' ', copy->length-length);
- pos+= 2 + length;
+ pos+= 2+length;
}
else
{
- memcpy(copy->str,pos,copy->length);
- pos+=copy->length;
+ memcpy(copy->str, pos, copy->length);
+ pos+= copy->length;
}
}
}
- tab->cache.pos=pos;
- return;
+ this->pos= pos;
+ return (uint) (pos-init_pos);
+}
+
+
+static range_seq_t bka_range_seq_init(void *init_param, uint n_ranges, uint flags)
+{
+ JOIN_CACHE_BKA *cache= (JOIN_CACHE_BKA *) init_param;
+ cache->reset(0);
+ return (range_seq_t) init_param;
+}
+
+static uint bka_range_seq_next(range_seq_t rseq, KEY_MULTI_RANGE *range)
+{
+ JOIN_CACHE_BKA *cache= (JOIN_CACHE_BKA *) rseq;
+ JOIN_TAB *tab= cache->join_tab;
+ TABLE_REF *ref= &tab->ref;
+ while (!cache->get_record())
+ {
+ if (!cp_buffer_from_ref(tab->join->thd, tab->table, ref))
+ {
+ key_range *start_key= &range->start_key;
+ start_key->key= ref->key_buff;
+ start_key->length= ref->key_length;
+ start_key->keypart_map= 1 << ref->key_parts - 1;
+ start_key->flag= HA_READ_KEY_EXACT;
+ range->end_key= *start_key;
+ range->end_key.flag= HA_READ_AFTER_KEY;
+ range->ptr= (char *) cache->get_record_label();
+ range->range_flag= EQ_RANGE;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static void bka_save_current_pos(range_seq_t rseq, uint *range_no, void **pos)
+{
+ JOIN_CACHE_BKA *cache= (JOIN_CACHE_BKA *) rseq;
+ *range_no= cache->get_record_nr();
+ *pos =cache->get_pos();
+}
+
+static void bka_restore_current_pos(range_seq_t rseq, uint range_no, void *pos)
+{
+ JOIN_CACHE_BKA *cache= (JOIN_CACHE_BKA *) rseq;
+ cache->set_record_nr(range_no);
+ cache->set_pos((uchar *) pos);
+}
+
+
+enum_nested_loop_state
+JOIN_CACHE_BKA::join_records(bool skip_last)
+{
+ handler *file= join_tab->table->file;
+ enum_nested_loop_state rc= NESTED_LOOP_OK;
+ int error;
+ uchar *rec_ptr;
+
+ join_tab->table->null_row= 0;
+ if (!records)
+ return NESTED_LOOP_OK; /* Nothing to do */
+
+ DBUG_ASSERT(!skip_last);
+ DBUG_ASSERT(join_tab->use_quick != 2);
+
+ RANGE_SEQ_IF seq_funcs= {bka_range_seq_init, bka_range_seq_next,
+ bka_save_current_pos, bka_restore_current_pos};
+ init_mrr_buff();
+ if (!file->inited)
+ file->ha_index_init(join_tab->ref.key, 1);
+ error= file->multi_range_read_init(&seq_funcs, (void*)this, records,
+ 0, &mrr_buff);
+
+ for (JOIN_TAB *tmp=join->join_tab; tmp != join_tab ; tmp++)
+ {
+ tmp->status=tmp->table->status;
+ tmp->table->status=0;
+ }
+
+ while (!(error= file->multi_range_read_next((char **) &rec_ptr)))
+ {
+ if (join->thd->killed)
+ {
+ join->thd->send_kill_message();
+ return NESTED_LOOP_KILLED; // Aborted by user /* purecov: inspected */
+ }
+ if (rc == NESTED_LOOP_OK)
+ {
+ get_record(rec_ptr);
+ if (!join_tab->select || !join_tab->select->skip_record())
+ {
+ int res= 0;
+ if (!join_tab->check_weed_out_table ||
+ !(res= do_sj_dups_weedout(join->thd,
+ join_tab->check_weed_out_table)))
+ {
+ rc= (join_tab->next_select)(join, join_tab+1, 0);
+ if (rc != NESTED_LOOP_OK && rc != NESTED_LOOP_NO_MORE_ROWS)
+ {
+ reset(TRUE);
+ return rc;
+ }
+ }
+ if (res == -1)
+ return NESTED_LOOP_ERROR;
+ }
+ }
+ };
+
+ reset(TRUE);
+ if (error > 0 && error != HA_ERR_END_OF_FILE) // Fatal error
+ return NESTED_LOOP_ERROR; /* purecov: inspected */
+ for (JOIN_TAB *tmp2=join->join_tab; tmp2 != join_tab ; tmp2++)
+ tmp2->table->status= tmp2->status;
+ return NESTED_LOOP_OK;
}
diff -Nrup a/sql/sql_select.h b/sql/sql_select.h
--- a/sql/sql_select.h 2007-09-04 11:30:37 -07:00
+++ b/sql/sql_select.h 2007-10-03 04:09:45 -07:00
@@ -100,58 +100,12 @@ typedef struct st_table_ref
/*
- CACHE_FIELD and JOIN_CACHE is used on full join to cache records in outer
- table
-*/
-
-typedef struct st_cache_field {
- /*
- Where source data is located (i.e. this points to somewhere in
- tableX->record[0])
- */
- uchar *str;
- uint length; /* Length of data at *str, in bytes */
- uint blob_length; /* Valid IFF blob_field != 0 */
- Field_blob *blob_field;
- bool strip; /* TRUE <=> Strip endspaces ?? */
-
- TABLE *get_rowid; /* _ != NULL <=> */
-} CACHE_FIELD;
-
-
-typedef struct st_join_cache
-{
- uchar *buff;
- uchar *pos; /* Start of free space in the buffer */
- uchar *end;
- uint records; /* # of row cominations currently stored in the cache */
- uint record_nr;
- uint ptr_record;
- /*
- Number of fields (i.e. cache_field objects). Those correspond to table
- columns, and there are also special fields for
- - table's column null bits
- - table's null-complementation byte
- - [new] table's rowid.
- */
- uint fields;
- uint length;
- uint blobs;
- CACHE_FIELD *field;
- CACHE_FIELD **blob_ptr;
- SQL_SELECT *select;
-} JOIN_CACHE;
-
-
-/*
The structs which holds the join connections and join states
*/
enum join_type { JT_UNKNOWN,JT_SYSTEM,JT_CONST,JT_EQ_REF,JT_REF,JT_MAYBE_REF,
JT_ALL, JT_RANGE, JT_NEXT, JT_FT, JT_REF_OR_NULL,
JT_UNIQUE_SUBQUERY, JT_INDEX_SUBQUERY, JT_INDEX_MERGE};
-class JOIN;
-
enum enum_nested_loop_state
{
NESTED_LOOP_KILLED= -2, NESTED_LOOP_ERROR= -1,
@@ -166,6 +120,7 @@ enum enum_nested_loop_state
#define TAB_INFO_USING_WHERE 4
#define TAB_INFO_FULL_SCAN_ON_NULL 8
+class JOIN_CACHE;
class SJ_TMP_TABLE;
typedef enum_nested_loop_state
@@ -250,7 +205,8 @@ typedef struct st_join_table {
*/
ha_rows limit;
TABLE_REF ref;
- JOIN_CACHE cache;
+ JOIN_CACHE *cache;
+ SQL_SELECT *cache_select;
JOIN *join;
/* SemiJoinDuplicateElimination variables: */
@@ -303,6 +259,166 @@ typedef struct st_join_table {
QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX));
}
} JOIN_TAB;
+
+
+/*
+ CACHE_FIELD and JOIN_CACHE is used on full join to cache records in outer
+ table
+*/
+
+typedef struct st_cache_field {
+ /*
+ Where source data is located (i.e. this points to somewhere in
+ tableX->record[0])
+ */
+ uchar *str;
+ uint length; /* Length of data at *str, in bytes */
+ uint blob_length; /* Valid IFF blob_field != 0 */
+ Field_blob *blob_field;
+ bool strip; /* TRUE <=> Strip endspaces ?? */
+
+ TABLE *get_rowid; /* _ != NULL <=> */
+} CACHE_FIELD;
+
+class JOIN_CACHE :public Sql_alloc
+{
+protected:
+ CACHE_FIELD *field;
+ CACHE_FIELD **blob_ptr;
+ SQL_SELECT *select;
+ /*
+ Number of fields (i.e. cache_field objects). Those correspond to table
+ columns, and there are also special fields for
+ - table's column null bits
+ - table's null-complementation byte
+ - [new] table's rowid.
+ */
+ uint fields;
+ uint blobs;
+ uint length;
+ uint records; /* number of records written into the cache */
+ uint record_nr;
+ uint ptr_record;
+ uchar *buff; /* beginning of the cache buffer */
+ uchar *end; /* end of the cache buffer */
+ uchar *pos; /* current position of free space in the buffer */
+ uchar *end_pos; /* end of the cache of free space in the buffer */
+ JOIN *join;
+ uint write_record_data(bool *is_full);
+ uint read_record_data();
+ virtual uint pack_length()
+ { return length; }
+ virtual uint addon_length()
+ { return 0; }
+public:
+ JOIN_TAB *join_tab;
+ virtual ~JOIN_CACHE() {}
+ void reset_join(JOIN *j) { join= j; }
+ uchar *get_pos() { return pos; }
+ void set_pos(uchar *arg) { pos= arg; }
+ uint get_record_nr() { return record_nr; }
+ void set_record_nr(uint arg) { record_nr= arg; }
+ ulong used_blob_length();
+ void free()
+ {
+ x_free(buff);
+ buff= 0;
+ }
+ virtual int init();
+ virtual void reset(bool is_for_write);
+ virtual bool put_record()= 0;
+ virtual bool get_record()= 0;
+ virtual enum_nested_loop_state join_records(bool skip_last)= 0;
+};
+
+class JOIN_CACHE_BNL :public JOIN_CACHE
+{
+public:
+ JOIN_CACHE_BNL(JOIN *j, JOIN_TAB *tab)
+ {
+ join= j;
+ join_tab= tab;
+ }
+ bool put_record()
+ {
+ bool is_full;
+ write_record_data(&is_full);
+ return is_full;
+ }
+ bool get_record()
+ { return read_record_data() == 0; }
+ enum_nested_loop_state join_records(bool skip_last);
+};
+
+class JOIN_CACHE_BKA :public JOIN_CACHE
+{
+protected:
+ uchar *rec_label;
+ HANDLER_BUFFER mrr_buff;
+public:
+ JOIN_CACHE_BKA(JOIN *j, JOIN_TAB *tab)
+ {
+ join= j;
+ join_tab= tab;
+ }
+ uint addon_length()
+ {
+ TABLE_REF *ref= &join_tab->ref;
+ TABLE *tab= join_tab->table;
+ uint len= 0;
+ if (end_pos == end)
+ len+= ref->key_length + tab->file->ref_length;
+ uint rec_per_key= tab->key_info[ref->key].rec_per_key[ref->key_parts-1];
+ set_if_bigger(rec_per_key, 1);
+ len+= tab->file->stats.mrr_length_per_rec * rec_per_key;
+ return len;
+ }
+
+ bool put_record()
+ {
+ bool is_full;
+ write_record_data(&is_full);
+ if (!is_full)
+ end_pos-= addon_length();
+ return is_full;
+ }
+ bool get_record()
+ {
+ rec_label= pos;
+ return read_record_data() == 0;
+ }
+ virtual uchar *get_record_label()
+ {
+ return rec_label;
+ }
+ int init()
+ {
+ int res= JOIN_CACHE::init();
+ return res;
+ }
+ virtual void reset(bool is_for_write)
+ {
+ JOIN_CACHE::reset(is_for_write);
+ if (is_for_write)
+ end_pos= end;
+ }
+ virtual void get_record(uchar *rec_ptr)
+ {
+ uchar *save_pos= pos;
+ uint save_record_nr= record_nr;
+ pos= rec_ptr;
+ record_nr= 0;
+ read_record_data();
+ pos= save_pos;
+ record_nr= save_record_nr;
+ }
+ virtual void init_mrr_buff()
+ {
+ mrr_buff.buffer= end_pos;
+ mrr_buff.buffer_end= end;
+ }
+ enum_nested_loop_state join_records(bool skip_last);
+};
enum_nested_loop_state sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool
end_of_records);
diff -Nrup a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
--- a/storage/innobase/handler/ha_innodb.cc 2007-08-26 01:01:14 -07:00
+++ b/storage/innobase/handler/ha_innodb.cc 2007-10-03 04:09:45 -07:00
@@ -5680,6 +5680,7 @@ ha_innobase::info(
* UNIV_PAGE_SIZE;
stats.delete_length = 0;
stats.check_time = 0;
+ stats.mrr_length_per_rec= ref_length + sizeof(void*);
if (stats.records == 0) {
stats.mean_rec_length = 0;
diff -Nrup a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc
--- a/storage/myisam/ha_myisam.cc 2007-08-26 04:52:55 -07:00
+++ b/storage/myisam/ha_myisam.cc 2007-10-03 04:09:45 -07:00
@@ -1598,6 +1598,8 @@ int ha_myisam::info(uint flag)
stats.max_data_file_length= misam_info.max_data_file_length;
stats.max_index_file_length= misam_info.max_index_file_length;
stats.create_time= misam_info.create_time;
+ stats.mrr_length_per_rec= misam_info.reflength + sizeof(void*);
+
ref_length= misam_info.reflength;
share->db_options_in_use= misam_info.options;
stats.block_size= myisam_block_size; /* record block size */
| Thread |
|---|
| • bk commit into 5.2 tree (igor:1.2579) | igor | 3 Oct |