diff options
-rw-r--r-- | mysql-test/t/join_nested.test | 1 | ||||
-rw-r--r-- | mysql-test/t/subselect_sj2.test | 1 | ||||
-rw-r--r-- | sql/multi_range_read.cc | 415 | ||||
-rw-r--r-- | sql/multi_range_read.h | 95 | ||||
-rw-r--r-- | sql/sql_lifo_buffer.h | 179 |
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); + } +}; |