Commit 51564575 authored by Sergey Petrunya's avatar Sergey Petrunya

Address review feedback

- One iterator class
- Switch back from state automaton into two-nested-iterators approach..
parent 22d5323f
......@@ -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
......
......@@ -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);
......
......@@ -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,131 +940,34 @@ 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)
{
case GET_NEXT_IDENTICAL_KEY:
{
/* 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)
if (scanning_key_val_iter)
{
/*
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;
}
case GET_NEXT_RECORD:
if (kv_it.get_next())
{
/* 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;
kv_it.close();
scanning_key_val_iter= FALSE;
}
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)
while (kv_it.init(this))
{
read_out_identical_ranges();
index_scan_state= GET_NEXT_RANGE;
have_record= FALSE;
}
break;
}
case REFILL_KEY_BUFFER:
/* Failed to initialize iterator */
if (key_buffer->is_empty())
{
if (dsmrr_eof)
{
index_scan_state= SCAN_FINISHED;
index_scan_eof= TRUE;
DBUG_RETURN(HA_ERR_END_OF_FILE);
}
......@@ -1008,15 +980,13 @@ int DsMrr_impl::dsmrr_next_from_index(char **range_info_arg)
if (key_buffer->is_empty())
{
index_scan_state= SCAN_FINISHED;
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 &&
......@@ -1035,151 +1005,6 @@ int DsMrr_impl::dsmrr_next_from_index(char **range_info_arg)
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;
......
......@@ -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
......@@ -197,17 +228,6 @@ private:
/** 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 **/
/*
......@@ -289,11 +288,6 @@ private:
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;
};
/**
......
......@@ -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 ~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()
void init(Lifo_buffer *buf_arg)
{
buf= buf_arg;
pos= buf->get_pos();
}
/*
Always read the first component first (if the buffer is backwards, we
have written the second component first).
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
*/
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)
bool read()
{
DBUG_ASSERT(buf_arg->type() == Lifo_buffer::BACKWARD);
buf= buf_arg;
pos= ((Backward_lifo_buffer*)buf)->pos;
return buf->read(&pos);
}
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment