summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/t/join_nested.test1
-rw-r--r--mysql-test/t/subselect_sj2.test1
-rw-r--r--sql/multi_range_read.cc415
-rw-r--r--sql/multi_range_read.h95
-rw-r--r--sql/sql_lifo_buffer.h179
5 files changed, 218 insertions, 473 deletions
diff --git a/mysql-test/t/join_nested.test b/mysql-test/t/join_nested.test
index 5b07d8966f1..97404b0440c 100644
--- a/mysql-test/t/join_nested.test
+++ b/mysql-test/t/join_nested.test
@@ -462,7 +462,6 @@ SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
LEFT JOIN
(t1,t2)
ON t3.a=1 AND t3.b=t2.b AND t2.b=t4.b;
-
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
FROM (t3,t4)
LEFT JOIN
diff --git a/mysql-test/t/subselect_sj2.test b/mysql-test/t/subselect_sj2.test
index e73e7cfade2..5c40da0f56f 100644
--- a/mysql-test/t/subselect_sj2.test
+++ b/mysql-test/t/subselect_sj2.test
@@ -586,6 +586,7 @@ if (`select @@join_cache_level=6`)
--echo # Not anymore:
--echo # The following query gives wrong result due to Bug#49129
}
+select sin(0);
select * from t0 where t0.a in
(select t1.a from t1, t2 where t2.a=t0.a and t1.b=t2.b);
diff --git a/sql/multi_range_read.cc b/sql/multi_range_read.cc
index 9ffc9fed3df..0cf31c222c6 100644
--- a/sql/multi_range_read.cc
+++ b/sql/multi_range_read.cc
@@ -682,7 +682,7 @@ void DsMrr_impl::setup_buffer_sizes(key_range *sample_key)
{
/* Give all space to forward key buffer. */
key_buffer= &forward_key_buf;
- identical_key_it= &forward_key_it;
+ //identical_key_it= &forward_key_it;
key_buffer->set_buffer_space(full_buf, full_buf_end);
/* Just in case, tell rowid buffer that it has zero size: */
@@ -731,7 +731,7 @@ void DsMrr_impl::setup_buffer_sizes(key_range *sample_key)
rowid_buffer_end= full_buf + bytes_for_rowids;
rowid_buffer.set_buffer_space(full_buf, rowid_buffer_end);
key_buffer= &backward_key_buf;
- identical_key_it= &backward_key_it;
+ //identical_key_it= &backward_key_it;
key_buffer->set_buffer_space(rowid_buffer_end, full_buf_end);
}
@@ -771,7 +771,7 @@ void DsMrr_impl::dsmrr_fill_key_buffer()
*/
rowid_buffer.set_buffer_space(full_buf, rowid_buffer_end);
key_buffer= &backward_key_buf;
- identical_key_it= &backward_key_it;
+ //identical_key_it= &backward_key_it;
key_buffer->set_buffer_space(rowid_buffer_end, full_buf_end);
}
key_buffer->reset();
@@ -815,9 +815,12 @@ void DsMrr_impl::dsmrr_fill_key_buffer()
is_mrr_assoc? (uchar**)&cur_range_info: NULL,
sizeof(void*));
- last_identical_key_ptr= NULL;
+ //last_identical_key_ptr= NULL;
//in_identical_keys_range= FALSE;
- index_scan_state= GET_NEXT_RANGE;
+ //index_scan_state= GET_NEXT_RANGE;
+ scanning_key_val_iter= FALSE;
+ index_scan_eof= FALSE;
+
DBUG_VOID_RETURN;
}
@@ -834,22 +837,88 @@ void DsMrr_impl::reallocate_buffer_space()
}
-/**
- Read out ranges from the buffer until we've reached the range with
- last_identical_key_ptr.
-*/
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+bool Key_value_records_iterator::init(DsMrr_impl *dsmrr_arg)
+{
+ int res;
+ dsmrr= dsmrr_arg;
+ handler *file= dsmrr->do_rndpos_scan? dsmrr->h2 : dsmrr->h;
+
+ identical_key_it.init(dsmrr->key_buffer);
+ /* Get the first pair into (cur_index_tuple, cur_range_info) */
+ if (identical_key_it.read())
+ return TRUE;
+
+ uchar *key_in_buf= dsmrr->cur_index_tuple;
+
+ if (dsmrr->use_key_pointers)
+ dsmrr->cur_index_tuple= *((uchar**)dsmrr->cur_index_tuple);
+
+ /* Check out how many more identical keys are following */
+ //char *save_cur_range_info= cur_range_info;
+ uchar *save_cur_index_tuple= dsmrr->cur_index_tuple;
+ last_identical_key_ptr= dsmrr->cur_index_tuple;
+ while (!identical_key_it.read())
+ {
+ if (DsMrr_impl::key_tuple_cmp(dsmrr, key_in_buf, dsmrr->cur_index_tuple))
+ break;
+ last_identical_key_ptr= dsmrr->cur_index_tuple;
+ }
+ identical_key_it.init(dsmrr->key_buffer);
+ dsmrr->cur_index_tuple= save_cur_index_tuple;
+ //cur_range_info= save_cur_range_info;
+ res= file->ha_index_read_map(dsmrr->table->record[0],
+ dsmrr->cur_index_tuple,
+ dsmrr->key_tuple_map,
+ HA_READ_KEY_EXACT);
+
+ if (res)
+ {
+ close();
+ return res; /* Fatal error */
+ }
+ get_next_row= FALSE;
+ return 0;
+}
-void DsMrr_impl::read_out_identical_ranges()
+
+int Key_value_records_iterator::get_next()
{
- if (last_identical_key_ptr)
+ handler *file= dsmrr->do_rndpos_scan? dsmrr->h2 : dsmrr->h;
+ int res;
+
+ if (get_next_row)
+ {
+ if (dsmrr->index_ranges_unique)
+ return HA_ERR_END_OF_FILE; /* Max one match */
+
+ if ((res= file->ha_index_next_same(dsmrr->table->record[0],
+ dsmrr->cur_index_tuple,
+ dsmrr->key_tuple_length)))
+ {
+ /* EOF is EOF for iterator, also, any error means EOF on the iterator */
+ return res;
+ }
+ identical_key_it.init(dsmrr->key_buffer);
+ }
+
+ identical_key_it.read(); // This gets us next range_id.
+ if (!last_identical_key_ptr || (dsmrr->cur_index_tuple == last_identical_key_ptr))
{
- /* key_buffer.read() reads to (cur_index_tuple, cur_range_info) */
- while (!key_buffer->read() && (cur_index_tuple != last_identical_key_ptr)) {}
- last_identical_key_ptr= NULL;
+ get_next_row= TRUE;
}
+ return 0;
}
+void Key_value_records_iterator::close()
+{
+ while (!dsmrr->key_buffer->read() &&
+ (dsmrr->cur_index_tuple != last_identical_key_ptr)) {}
+}
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
/**
DS-MRR/CPK: multi_range_read_next() function
@@ -871,154 +940,55 @@ void DsMrr_impl::read_out_identical_ranges()
@retval HA_ERR_END_OF_FILE End of records
@retval Other Some other error
*/
-
int DsMrr_impl::dsmrr_next_from_index(char **range_info_arg)
{
DBUG_ENTER("DsMrr_impl::dsmrr_next_from_index");
- int res;
- handler *file= do_rndpos_scan? h2: h;
-
+ //handler *file= do_rndpos_scan? h2: h;
+
while (1)
{
bool have_record= FALSE;
- switch (index_scan_state)
+ if (scanning_key_val_iter)
{
- case GET_NEXT_IDENTICAL_KEY:
+ if (kv_it.get_next())
{
- /* Get the next range_id for the current record */
-
- /* read to (cur_index_tuple, cur_range_info) */
- bool bres= identical_key_it->read_next();
- DBUG_ASSERT(!bres);
-
- if (cur_index_tuple == last_identical_key_ptr)
- {
- /*
- We've just got to the last of identical ranges. Next step is to
- go next record
- */
- index_scan_state= index_ranges_unique? GET_NEXT_RANGE : GET_NEXT_RECORD;
- }
- have_record= TRUE;
- break;
+ kv_it.close();
+ scanning_key_val_iter= FALSE;
}
- case GET_NEXT_RECORD:
- {
- /* Get the next record from the range */
- res= file->ha_index_next_same(table->record[0], cur_index_tuple,
- key_tuple_length);
- if (res)
- {
- if (res != HA_ERR_END_OF_FILE && res != HA_ERR_KEY_NOT_FOUND)
- DBUG_RETURN(res); /* Fatal error */
-
- /* Got EOF for this range, go get the next range */
- index_scan_state= GET_NEXT_RANGE;
- break;
- }
-
+ else
have_record= TRUE;
- if (last_identical_key_ptr)
- {
- /*
- If the range we're scanning is one of the set of identical ranges,
- return this record with range_id of each range
- */
- index_scan_state= GET_NEXT_IDENTICAL_KEY;
- identical_key_it->init(key_buffer);
- cur_range_info= first_identical_range_info;
- have_record= FALSE; //psergey4
- }
- break;
- }
- case GET_NEXT_RANGE:
- {
- read_out_identical_ranges();
- if (do_rndpos_scan)
- reallocate_buffer_space();
-
- /* Get the next range to scan */
- if (key_buffer->read()) /* read to (cur_index_tuple,cur_range_info) */
- {
- index_scan_state= REFILL_KEY_BUFFER;
- break;
- }
- uchar *key_in_buf= cur_index_tuple;
-
- if (use_key_pointers)
- cur_index_tuple= *((uchar**)cur_index_tuple);
-
- res= file->ha_index_read_map(table->record[0], cur_index_tuple,
- key_tuple_map, HA_READ_KEY_EXACT);
-
- if (res && res != HA_ERR_END_OF_FILE && res != HA_ERR_KEY_NOT_FOUND)
- DBUG_RETURN(res); /* Fatal error */
-
- /*
- Check if subsequent elements in the key buffer are the same as this
- one
- */
- char *save_cur_range_info= cur_range_info;
- identical_key_it->init(key_buffer);
- last_identical_key_ptr= NULL;
- while (!identical_key_it->read_next())
- {
- if (key_tuple_cmp(this, key_in_buf, cur_index_tuple))
- break;
- last_identical_key_ptr= cur_index_tuple;
- }
- cur_range_info= save_cur_range_info;
-
- if (last_identical_key_ptr)
- {
- index_scan_state= GET_NEXT_IDENTICAL_KEY;
- identical_key_it->init(key_buffer);
- first_identical_range_info= cur_range_info;
- have_record= FALSE; //psergey4
- }
- else
- {
- index_scan_state= index_ranges_unique? GET_NEXT_RANGE : GET_NEXT_RECORD;
- have_record= TRUE;
- }
-
- if (res)
- {
- read_out_identical_ranges();
- index_scan_state= GET_NEXT_RANGE;
- have_record= FALSE;
- }
-
- break;
- }
- case REFILL_KEY_BUFFER:
+ }
+ else
+ {
+ while (kv_it.init(this))
{
- if (dsmrr_eof)
- {
- index_scan_state= SCAN_FINISHED;
- DBUG_RETURN(HA_ERR_END_OF_FILE);
- }
-
- /*
- When rowid fetching is used, it controls all buffer refills. When we're
- on our own, try refilling our buffer.
- */
- if (!do_rndpos_scan)
- dsmrr_fill_key_buffer();
-
+ /* Failed to initialize iterator */
if (key_buffer->is_empty())
{
- index_scan_state= SCAN_FINISHED;
- DBUG_RETURN(HA_ERR_END_OF_FILE);
+ if (dsmrr_eof)
+ {
+ index_scan_eof= TRUE;
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+ }
+
+ /*
+ When rowid fetching is used, it controls all buffer refills. When we're
+ on our own, try refilling our buffer.
+ */
+ if (!do_rndpos_scan)
+ dsmrr_fill_key_buffer();
+
+ if (key_buffer->is_empty())
+ {
+ index_scan_eof= TRUE;
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+ }
}
-
- index_scan_state= GET_NEXT_RANGE;
}
- default:
- DBUG_ASSERT(0);
- break;
+ /* if we got here, it means iterator was successfully initialized */
+ scanning_key_val_iter= TRUE;
}
-
+
if (have_record &&
(!h->mrr_funcs.skip_index_tuple ||
!h->mrr_funcs.skip_index_tuple(h->mrr_iter, *(char**)cur_range_info))
@@ -1030,156 +1000,11 @@ int DsMrr_impl::dsmrr_next_from_index(char **range_info_arg)
}
/* Go get another (record, range_id) combination */
} /* while */
-
+
memcpy(range_info_arg, cur_range_info, sizeof(void*));
DBUG_RETURN(0);
}
-#if 0
-int DsMrr_impl::dsmrr_next_from_index(char **range_info_arg)
-{
- int res;
- uchar *key_in_buf;
- handler *file= do_rndpos_scan? h2: h;
- bool res2;
-
- while (in_identical_keys_range)
- {
- /* This will read to (cur_index_tuple, cur_range_info): */
- res2= identical_key_it->read_next();
- DBUG_ASSERT(!res2);
-
- if (cur_index_tuple == last_identical_key_ptr)
- {
- /* We're looking at the last of the identical keys */
- in_identical_keys_range= FALSE;
- }
-check_record:
- if ((h->mrr_funcs.skip_index_tuple &&
- h->mrr_funcs.skip_index_tuple(h->mrr_iter, *(char**)cur_range_info)) ||
- (h->mrr_funcs.skip_record &&
- h->mrr_funcs.skip_record(h->mrr_iter, *(char**)cur_range_info, NULL)))
- {
- continue;
- }
- memcpy(range_info_arg, cur_range_info, sizeof(void*));
- return 0;
- }
-
- /* Try returrning next record from the current range */
- while (in_index_range)
- {
- res= file->ha_index_next_same(table->record[0], cur_index_tuple,
- key_tuple_length);
-
- if (res)
- {
- if (res != HA_ERR_END_OF_FILE && res != HA_ERR_KEY_NOT_FOUND)
- return res; /* Fatal error */
-
- in_index_range= FALSE; /* no more records here */
- break;
- }
-
- if (last_identical_key_ptr)
- {
- in_identical_keys_range= TRUE;
- identical_key_it->init(key_buffer);
- cur_range_info= first_identical_range_info;
- }
-
- goto check_record;
- }
-
- while(1)
- {
- DBUG_ASSERT(!in_identical_keys_range && !in_index_range);
-
- /* Jump over the keys that were handled by identical key processing */
- if (last_identical_key_ptr)
- {
- /* key_buffer.read() reads to (cur_index_tuple, cur_range_info) */
- while (!key_buffer->read() && (cur_index_tuple != last_identical_key_ptr)) {}
- last_identical_key_ptr= NULL;
- }
-
- /* First, make sure we have a range at start of the buffer */
- if (key_buffer->is_empty())
- {
- if (dsmrr_eof)
- {
- res= HA_ERR_END_OF_FILE;
- goto end;
- }
- /*
- When rowid fetching is used, it controls all buffer refills. When we're
- on our own, try refilling our buffer.
- */
- if (!do_rndpos_scan)
- dsmrr_fill_key_buffer();
-
- if (key_buffer->is_empty())
- {
- res= HA_ERR_END_OF_FILE;
- goto end;
- }
- }
-
- /*
- At this point we're not using anything what we've read from key
- buffer. Cut off unused key buffer space and give it to the rowid
- buffer.
- */
- if (do_rndpos_scan)
- reallocate_buffer_space();
-
- /* Get the next range to scan */
- key_buffer->read(); // reads to (cur_index_tuple, cur_range_info)
- key_in_buf= cur_index_tuple;
-
- if (use_key_pointers)
- cur_index_tuple= *((uchar**)cur_index_tuple);
-
- /* Do index lookup */
- if ((res= file->ha_index_read_map(table->record[0], cur_index_tuple,
- key_tuple_map, HA_READ_KEY_EXACT)))
- {
- if (res != HA_ERR_END_OF_FILE && res != HA_ERR_KEY_NOT_FOUND)
- return res;
- continue; /* to next key and make another lookup */
- }
-
- /* Check if subsequent keys in the key buffer are the same as this one */
- {
- char *save_cur_range_info= cur_range_info;
- identical_key_it->init(key_buffer);
- last_identical_key_ptr= NULL;
- while (!identical_key_it->read_next())
- {
- if (key_tuple_cmp(this, key_in_buf, cur_index_tuple))
- break;
-
- last_identical_key_ptr= cur_index_tuple;
- }
- cur_range_info= save_cur_range_info;
- if (last_identical_key_ptr)
- {
- in_identical_keys_range= TRUE;
- identical_key_it->init(key_buffer);
- first_identical_range_info= cur_range_info;
- }
- }
-
- in_index_range= !index_ranges_unique;
- goto check_record;
- }
-
-end:
- return res;
-}
-#endif
-
-
/**
DS-MRR implementation: multi_range_read_next() function.
@@ -1227,7 +1052,7 @@ int DsMrr_impl::dsmrr_next(char **range_info)
{
if (do_sort_keys)
{
- if (index_scan_state != SCAN_FINISHED)
+ if (index_scan_eof)
{
/* There are some sorted keys left. Use them to get rowids */
if ((res= dsmrr_fill_rowid_buffer()))
@@ -1288,9 +1113,9 @@ int DsMrr_impl::dsmrr_next(char **range_info)
Note: this implies that SQL layer doesn't touch table->record[0]
between calls.
*/
- Forward_iterator it;
+ Lifo_buffer_iterator it;
it.init(&rowid_buffer);
- while (!it.read_next()) // reads to (rowid, ...)
+ while (!it.read()) // reads to (rowid, ...)
{
if (h2->cmp_ref(rowid, cur_rowid))
break;
diff --git a/sql/multi_range_read.h b/sql/multi_range_read.h
index 2a0b4d6a59e..e93276055e5 100644
--- a/sql/multi_range_read.h
+++ b/sql/multi_range_read.h
@@ -48,6 +48,37 @@
#include "sql_lifo_buffer.h"
+class DsMrr_impl;
+
+/**
+ Iterator over (record, range_id) pairs that match given key value.
+
+ We may need to scan multiple (key_val, range_id) pairs with the same
+ key value. A key value may have multiple matching records, so we'll need to
+ produce a cross-product of sets of matching records and range_id-s.
+*/
+
+class Key_value_records_iterator
+{
+ /* Scan parameters */
+ DsMrr_impl *dsmrr;
+ Lifo_buffer_iterator identical_key_it;
+ uchar *last_identical_key_ptr;
+ bool get_next_row;
+public:
+ /*
+ */
+ bool init(DsMrr_impl *dsmrr);
+
+ /*
+ Get next (key_val, range_id) pair.
+ */
+ int get_next();
+
+ void close();
+};
+
+
/*
DS-MRR implementation for one table. Create/use one object of this class for
each ha_{myisam/innobase/etc} object. That object will be further referred to
@@ -196,17 +227,6 @@ private:
uchar *rowid_buffer_end;
/** Index scaning and key buffer-related members **/
-
-
- enum enum_index_scan_state {
- REFILL_KEY_BUFFER,
- GET_NEXT_RANGE,
- GET_NEXT_RECORD,
- GET_NEXT_IDENTICAL_KEY,
- SCAN_FINISHED
- };
-
- enum enum_index_scan_state index_scan_state;
/* TRUE <=> We can get at most one index tuple for a lookup key */
bool index_ranges_unique;
@@ -220,25 +240,26 @@ private:
buffers.
*/
Forward_lifo_buffer forward_key_buf;
- Forward_iterator forward_key_it;
Backward_lifo_buffer backward_key_buf;
- Backward_iterator backward_key_it;
/* Buffer to store (key, range_id) pairs */
Lifo_buffer *key_buffer;
-
- /* key_buffer.read() reads */
- uchar *cur_index_tuple;
-
- /* if in_index_range==TRUE: range_id of the range we're enumerating */
- char *cur_range_info;
-
+
+ /* Index scan state */
+ bool scanning_key_val_iter;
/*
TRUE <=> we've got index tuples/rowids for all keys (need this flag because
we may have a situation where we've read everything from the key buffer but
haven't finished with getting index tuples for the last key)
*/
- //bool key_eof;
+ bool index_scan_eof;
+ Key_value_records_iterator kv_it;
+
+ /* key_buffer.read() reads to here */
+ uchar *cur_index_tuple;
+
+ /* if in_index_range==TRUE: range_id of the range we're enumerating */
+ char *cur_range_info;
/* Initially FALSE, becomes TRUE when we've set key_tuple_xxx members */
bool know_key_tuple_params;
@@ -255,28 +276,6 @@ private:
/* = key_size_in_keybuf [ + sizeof(range_assoc_info) ] */
uint key_buff_elem_size;
- /*
- TRUE <=> we're doing key-ordered index scan and right now several
- subsequent key values are the same as the one we've already retrieved and
- returned index tuple for.
- */
- //bool in_identical_keys_range;
-
- /* range_id of the first of the identical keys */
- char *first_identical_range_info;
-
- /* Pointer to the last of the identical key values */
- uchar *last_identical_key_ptr;
-
- /*
- key_buffer iterator for walking the identical key range (we need to
- enumerate the set of (identical_key, range_id) pairs multiple times,
- and do that by walking from current buffer read position until we get
- last_identical_key_ptr.
- */
- Lifo_buffer::Iterator *identical_key_it;
-
-
/** rnd_pos() scan and rowid buffer-related members **/
/*
@@ -288,12 +287,7 @@ private:
/* rowid_buffer.read() will set the following: */
uchar *rowid;
uchar *rowids_range_id;
-
- /*
- not-NULL: we're traversing a group of (rowid, range_id) pairs with
- identical rowid values, and this is the pointer to the last one.
- NULL: we're not in the group of indentical rowids.
- */
+
uchar *last_identical_rowid;
bool dsmrr_eof; /* TRUE <=> We have reached EOF when reading index tuples */
@@ -315,10 +309,9 @@ private:
void setup_buffer_sizes(key_range *sample_key);
void reallocate_buffer_space();
- void read_out_identical_ranges();
-
static range_seq_t key_buf_seq_init(void *init_param, uint n_ranges, uint flags);
static uint key_buf_seq_next(range_seq_t rseq, KEY_MULTI_RANGE *range);
+ friend class Key_value_records_iterator;
};
/**
diff --git a/sql/sql_lifo_buffer.h b/sql/sql_lifo_buffer.h
index dc0ed30ab43..89b520484e4 100644
--- a/sql/sql_lifo_buffer.h
+++ b/sql/sql_lifo_buffer.h
@@ -112,40 +112,17 @@ public:
virtual void reset() = 0;
virtual uchar *end_of_space() = 0;
protected:
- bool have_data(size_t bytes)
- {
- return (used_size() >= bytes);
- }
virtual bool have_space_for(size_t bytes) = 0;
virtual size_t used_size() = 0;
-
+
+ /* To be used only by iterator class: */
+ virtual uchar *get_pos()= 0;
+ virtual bool read(uchar **position)= 0;
+ friend class Lifo_buffer_iterator;
public:
-
virtual void remove_unused_space(uchar **unused_start, uchar **unused_end)=0;
- virtual uchar *used_area() = 0;
-
- /** Iterator to walk over contents of the buffer without reading it. */
- class Iterator
- {
- public:
- virtual void init(Lifo_buffer *buf) = 0;
- /*
- Read the next value. The calling convention is the same as buf->read()
- has.
-
- @retval FALSE - ok
- @retval TRUE - EOF, reached the end of the buffer
- */
- virtual bool read_next()= 0;
- virtual ~Iterator() {}
- protected:
- Lifo_buffer *buf;
- virtual uchar *get_next(size_t nbytes)=0;
- };
+ virtual uchar *used_area() = 0;
virtual ~Lifo_buffer() {};
-
- friend class Forward_iterator;
- friend class Backward_iterator;
};
@@ -196,19 +173,24 @@ public:
memcpy(pos, data, bytes);
pos += bytes;
}
- uchar *read_bytes(size_t bytes)
+ bool have_data(uchar *position, size_t bytes)
{
- DBUG_ASSERT(have_data(bytes));
- pos= pos - bytes;
- return pos;
+ return ((position - start) >= (ptrdiff_t)bytes);
}
- bool read()
+ uchar *read_bytes(uchar **position, size_t bytes)
+ {
+ DBUG_ASSERT(have_data(*position, bytes));
+ *position= (*position) - bytes;
+ return *position;
+ }
+ bool read() { return read(&pos); }
+ bool read(uchar **position)
{
- if (!have_data(size1 + (read_ptr2 ? size2 : 0)))
+ if (!have_data(*position, size1 + (read_ptr2 ? size2 : 0)))
return TRUE;
if (read_ptr2)
- *read_ptr2= read_bytes(size2);
- *read_ptr1= read_bytes(size1);
+ *read_ptr2= read_bytes(position, size2);
+ *read_ptr1= read_bytes(position, size1);
return FALSE;
}
void remove_unused_space(uchar **unused_start, uchar **unused_end)
@@ -231,58 +213,11 @@ public:
}
/* Return pointer to start of the memory area that is occupied by the data */
uchar *used_area() { return start; }
- friend class Forward_iterator;
+ friend class Lifo_buffer_iterator;
+ uchar *get_pos() { return pos; }
};
-/**
- Iterator for Forward_lifo_buffer
-*/
-
-class Forward_iterator : public Lifo_buffer::Iterator
-{
- uchar *pos;
-
- /** Return pointer to next chunk of nbytes bytes and avance over it */
- uchar *get_next(size_t nbytes)
- {
- if (pos - nbytes < ((Forward_lifo_buffer*)buf)->start)
- return NULL;
- pos -= nbytes;
- return pos;
- }
-public:
- bool read_next()
- {
- uchar *res;
- if (buf->read_ptr2)
- {
- if ((res= get_next(buf->size2)))
- {
- *(buf->read_ptr2)= res;
- *buf->read_ptr1= get_next(buf->size1);
- return FALSE;
- }
- }
- else
- {
- if ((res= get_next(buf->size1)))
- {
- *(buf->read_ptr1)= res;
- return FALSE;
- }
- }
- return TRUE; /* EOF */
- }
-
- void init(Lifo_buffer *buf_arg)
- {
- DBUG_ASSERT(buf_arg->type() == Lifo_buffer::FORWARD);
- buf= buf_arg;
- pos= ((Forward_lifo_buffer*)buf)->pos;
- }
-};
-
/**
Backward LIFO buffer
@@ -332,18 +267,26 @@ public:
}
bool read()
{
- if (!have_data(size1 + (read_ptr2 ? size2 : 0)))
+ return read(&pos);
+ }
+ bool read(uchar **position)
+ {
+ if (!have_data(*position, size1 + (read_ptr2 ? size2 : 0)))
return TRUE;
- *read_ptr1= read_bytes(size1);
+ *read_ptr1= read_bytes(position, size1);
if (read_ptr2)
- *read_ptr2= read_bytes(size2);
+ *read_ptr2= read_bytes(position, size2);
return FALSE;
}
- uchar *read_bytes(size_t bytes)
+ bool have_data(uchar *position, size_t bytes)
+ {
+ return ((end - position) >= (ptrdiff_t)bytes);
+ }
+ uchar *read_bytes(uchar **position, size_t bytes)
{
- DBUG_ASSERT(have_data(bytes));
- uchar *ret= pos;
- pos= pos + bytes;
+ DBUG_ASSERT(have_data(*position, bytes));
+ uchar *ret= *position;
+ *position= *position + bytes;
return ret;
}
/**
@@ -363,50 +306,34 @@ public:
}
/* Return pointer to start of the memory area that is occupied by the data */
uchar *used_area() { return pos; }
- friend class Backward_iterator;
+ friend class Lifo_buffer_iterator;
+ uchar *get_pos() { return pos; }
};
-/**
- Iterator for Backward_lifo_buffer
-*/
-class Backward_iterator : public Lifo_buffer::Iterator
+/** Iterator to walk over contents of the buffer without reading it. */
+class Lifo_buffer_iterator
{
uchar *pos;
- /* Return pointer to next chunk of nbytes bytes and advance over it */
- uchar *get_next(size_t nbytes)
- {
- if (pos + nbytes > ((Backward_lifo_buffer*)buf)->end)
- return NULL;
- uchar *res= pos;
- pos += nbytes;
- return res;
- }
+ Lifo_buffer *buf;
public:
- bool read_next()
- {
- /*
- Always read the first component first (if the buffer is backwards, we
- have written the second component first).
- */
- uchar *res;
- if ((res= get_next(buf->size1)))
- {
- *(buf->read_ptr1)= res;
- if (buf->read_ptr2)
- *buf->read_ptr2= get_next(buf->size2);
- return FALSE;
- }
- return TRUE; /* EOF */
- }
void init(Lifo_buffer *buf_arg)
{
- DBUG_ASSERT(buf_arg->type() == Lifo_buffer::BACKWARD);
buf= buf_arg;
- pos= ((Backward_lifo_buffer*)buf)->pos;
+ pos= buf->get_pos();
}
-};
+ /*
+ Read the next value. The calling convention is the same as buf->read()
+ has.
+ @retval FALSE - ok
+ @retval TRUE - EOF, reached the end of the buffer
+ */
+ bool read()
+ {
+ return buf->read(&pos);
+ }
+};