1 /*
2 Copyright (c) 2000, 2010, Oracle and/or its affiliates.
3 Copyright (c) 2009, 2017, MariaDB Corporation
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; version 2 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
17
18 #ifdef USE_PRAGMA_INTERFACE
19 #pragma implementation /* gcc class implementation */
20 #endif
21
22 /**
23 @file
24
25 @brief
26 Functions for easy reading of records, possible through a cache
27 */
28
29 #include "mariadb.h"
30 #include "records.h"
31 #include "sql_priv.h"
32 #include "records.h"
33 #include "opt_range.h" // SQL_SELECT
34 #include "sql_class.h" // THD
35 #include "sql_base.h"
36 #include "sql_sort.h" // SORT_ADDON_FIELD
37
38 static int rr_quick(READ_RECORD *info);
39 int rr_sequential(READ_RECORD *info);
40 static int rr_from_tempfile(READ_RECORD *info);
41 template<bool> static int rr_unpack_from_tempfile(READ_RECORD *info);
42 template<bool,bool> static int rr_unpack_from_buffer(READ_RECORD *info);
43 int rr_from_pointers(READ_RECORD *info);
44 static int rr_from_cache(READ_RECORD *info);
45 static int init_rr_cache(THD *thd, READ_RECORD *info);
46 static int rr_cmp(uchar *a,uchar *b);
47 static int rr_index_first(READ_RECORD *info);
48 static int rr_index_last(READ_RECORD *info);
49 static int rr_index(READ_RECORD *info);
50 static int rr_index_desc(READ_RECORD *info);
51
52
53 /**
54 Initialize READ_RECORD structure to perform full index scan in desired
55 direction using read_record.read_record() interface
56
57 This function has been added at late stage and is used only by
58 UPDATE/DELETE. Other statements perform index scans using
59 join_read_first/next functions.
60
61 @param info READ_RECORD structure to initialize.
62 @param thd Thread handle
63 @param table Table to be accessed
64 @param print_error If true, call table->file->print_error() if an error
65 occurs (except for end-of-records error)
66 @param idx index to scan
67 @param reverse Scan in the reverse direction
68 */
69
init_read_record_idx(READ_RECORD * info,THD * thd,TABLE * table,bool print_error,uint idx,bool reverse)70 bool init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table,
71 bool print_error, uint idx, bool reverse)
72 {
73 int error= 0;
74 DBUG_ENTER("init_read_record_idx");
75
76 empty_record(table);
77 bzero((char*) info,sizeof(*info));
78 info->thd= thd;
79 info->table= table;
80 info->print_error= print_error;
81 info->unlock_row= rr_unlock_row;
82
83 table->status=0; /* And it's always found */
84 if (!table->file->inited &&
85 unlikely(error= table->file->ha_index_init(idx, 1)))
86 {
87 if (print_error)
88 table->file->print_error(error, MYF(0));
89 }
90
91 /* read_record_func will be changed to rr_index in rr_index_first */
92 info->read_record_func= reverse ? rr_index_last : rr_index_first;
93 DBUG_RETURN(error != 0);
94 }
95
96
97 /*
98 init_read_record is used to scan by using a number of different methods.
99 Which method to use is set-up in this call so that later calls to
100 the info->read_record will call the appropriate method using a function
101 pointer.
102
103 There are five methods that relate completely to the sort function
104 filesort. The result of a filesort is retrieved using read_record
105 calls. The other two methods are used for normal table access.
106
107 The filesort will produce references to the records sorted, these
108 references can be stored in memory or in a temporary file.
109
110 The temporary file is normally used when the references doesn't fit into
111 a properly sized memory buffer. For most small queries the references
112 are stored in the memory buffer.
113 SYNOPSIS
114 init_read_record()
115 info OUT read structure
116 thd Thread handle
117 table Table the data [originally] comes from.
118 select SQL_SELECT structure. We may select->quick or
119 select->file as data source
120 use_record_cache Call file->extra_opt(HA_EXTRA_CACHE,...)
121 if we're going to do sequential read and some
122 additional conditions are satisfied.
123 print_error Copy this to info->print_error
124 disable_rr_cache Don't use rr_from_cache (used by sort-union
125 index-merge which produces rowid sequences that
126 are already ordered)
127
128 DESCRIPTION
129 This function sets up reading data via one of the methods:
130
131 The temporary file is also used when performing an update where a key is
132 modified.
133
134 Methods used when ref's are in memory (using rr_from_pointers):
135 rr_unpack_from_buffer:
136 ----------------------
137 This method is used when table->sort.addon_field is allocated.
138 This is allocated for most SELECT queries not involving any BLOB's.
139 In this case the records are fetched from a memory buffer.
140 rr_from_pointers:
141 -----------------
142 Used when the above is not true, UPDATE, DELETE and so forth and
143 SELECT's involving BLOB's. It is also used when the addon_field
144 buffer is not allocated due to that its size was bigger than the
145 session variable max_length_for_sort_data.
146 In this case the record data is fetched from the handler using the
147 saved reference using the rnd_pos handler call.
148
149 Methods used when ref's are in a temporary file (using rr_from_tempfile)
150 rr_unpack_from_tempfile:
151 ------------------------
152 Same as rr_unpack_from_buffer except that references are fetched from
153 temporary file. Should obviously not really happen other than in
154 strange configurations.
155
156 rr_from_tempfile:
157 -----------------
158 Same as rr_from_pointers except that references are fetched from
159 temporary file instead of from
160 rr_from_cache:
161 --------------
162 This is a special variant of rr_from_tempfile that can be used for
163 handlers that is not using the HA_FAST_KEY_READ table flag. Instead
164 of reading the references one by one from the temporary file it reads
165 a set of them, sorts them and reads all of them into a buffer which
166 is then used for a number of subsequent calls to rr_from_cache.
167 It is only used for SELECT queries and a number of other conditions
168 on table size.
169
170 All other accesses use either index access methods (rr_quick) or a full
171 table scan (rr_sequential).
172 rr_quick:
173 ---------
174 rr_quick uses one of the QUICK_SELECT classes in opt_range.cc to
175 perform an index scan. There are loads of functionality hidden
176 in these quick classes. It handles all index scans of various kinds.
177 rr_sequential:
178 --------------
179 This is the most basic access method of a table using rnd_init,
180 rnd_next and rnd_end. No indexes are used.
181 */
182
init_read_record(READ_RECORD * info,THD * thd,TABLE * table,SQL_SELECT * select,SORT_INFO * filesort,int use_record_cache,bool print_error,bool disable_rr_cache)183 bool init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
184 SQL_SELECT *select,
185 SORT_INFO *filesort,
186 int use_record_cache, bool print_error,
187 bool disable_rr_cache)
188 {
189 IO_CACHE *tempfile;
190 DBUG_ENTER("init_read_record");
191
192 const bool using_addon_fields= filesort && filesort->using_addon_fields();
193 bool using_packed_sortkeys= filesort && filesort->using_packed_sortkeys();
194
195 bzero((char*) info,sizeof(*info));
196 info->thd=thd;
197 info->table=table;
198 info->sort_info= filesort;
199
200 if ((table->s->tmp_table == INTERNAL_TMP_TABLE) &&
201 !using_addon_fields)
202 (void) table->file->extra(HA_EXTRA_MMAP);
203
204 if (using_addon_fields)
205 {
206 info->rec_buf= filesort->addon_fields->get_addon_buf();
207 info->ref_length= filesort->addon_fields->get_addon_buf_length();
208 }
209 else
210 {
211 empty_record(table);
212 info->ref_length= (uint)table->file->ref_length;
213 }
214 info->select=select;
215 info->print_error=print_error;
216 info->unlock_row= rr_unlock_row;
217 table->status= 0; /* Rows are always found */
218
219 tempfile= 0;
220 if (select && my_b_inited(&select->file))
221 tempfile= &select->file;
222 else if (filesort && my_b_inited(&filesort->io_cache))
223 tempfile= &filesort->io_cache;
224
225 if (tempfile && !(select && select->quick))
226 {
227 if (using_addon_fields)
228 {
229 DBUG_PRINT("info",("using rr_from_tempfile"));
230 if (filesort->addon_fields->using_packed_addons())
231 info->read_record_func= rr_unpack_from_tempfile<true>;
232 else
233 info->read_record_func= rr_unpack_from_tempfile<false>;
234 }
235 else
236 {
237 DBUG_PRINT("info",("using rr_from_tempfile"));
238 info->read_record_func= rr_from_tempfile;
239 }
240
241 info->io_cache= tempfile;
242 reinit_io_cache(info->io_cache,READ_CACHE,0L,0,0);
243 info->ref_pos=table->file->ref;
244 if (!table->file->inited)
245 if (unlikely(table->file->ha_rnd_init_with_error(0)))
246 DBUG_RETURN(1);
247
248 /*
249 addon_field is checked because if we use addon fields,
250 it doesn't make sense to use cache - we don't read from the table
251 and filesort->io_cache is read sequentially
252 */
253 if (!disable_rr_cache &&
254 !using_addon_fields &&
255 thd->variables.read_rnd_buff_size &&
256 !(table->file->ha_table_flags() & HA_FAST_KEY_READ) &&
257 (table->db_stat & HA_READ_ONLY ||
258 table->reginfo.lock_type <= TL_READ_NO_INSERT) &&
259 (ulonglong) table->s->reclength* (table->file->stats.records+
260 table->file->stats.deleted) >
261 (ulonglong) MIN_FILE_LENGTH_TO_USE_ROW_CACHE &&
262 info->io_cache->end_of_file/info->ref_length * table->s->reclength >
263 (my_off_t) MIN_ROWS_TO_USE_TABLE_CACHE &&
264 !table->s->blob_fields &&
265 info->ref_length <= MAX_REFLENGTH)
266 {
267 if (! init_rr_cache(thd, info))
268 {
269 DBUG_PRINT("info",("using rr_from_cache"));
270 info->read_record_func= rr_from_cache;
271 }
272 }
273 }
274 else if (select && select->quick)
275 {
276 DBUG_PRINT("info",("using rr_quick"));
277 info->read_record_func= rr_quick;
278 }
279 else if (filesort && filesort->has_filesort_result_in_memory())
280 {
281 DBUG_PRINT("info",("using record_pointers"));
282 if (unlikely(table->file->ha_rnd_init_with_error(0)))
283 DBUG_RETURN(1);
284
285 info->cache_pos= filesort->record_pointers;
286 if (using_addon_fields)
287 {
288 DBUG_PRINT("info",("using rr_unpack_from_buffer"));
289 DBUG_ASSERT(filesort->sorted_result_in_fsbuf);
290 info->unpack_counter= 0;
291
292 if (filesort->using_packed_addons())
293 {
294 info->read_record_func= using_packed_sortkeys ?
295 rr_unpack_from_buffer<true, true> :
296 rr_unpack_from_buffer<true, false>;
297 }
298 else
299 {
300 info->read_record_func= using_packed_sortkeys ?
301 rr_unpack_from_buffer<false, true> :
302 rr_unpack_from_buffer<false, false>;
303 }
304 }
305 else
306 {
307 info->cache_end= (info->cache_pos+
308 filesort->return_rows * info->ref_length);
309 info->read_record_func= rr_from_pointers;
310 }
311 }
312 else if (table->file->keyread_enabled())
313 {
314 int error;
315 info->read_record_func= rr_index_first;
316 if (!table->file->inited &&
317 unlikely((error= table->file->ha_index_init(table->file->keyread, 1))))
318 {
319 if (print_error)
320 table->file->print_error(error, MYF(0));
321 DBUG_RETURN(1);
322 }
323 }
324 else
325 {
326 DBUG_PRINT("info",("using rr_sequential"));
327 info->read_record_func= rr_sequential;
328 if (unlikely(table->file->ha_rnd_init_with_error(1)))
329 DBUG_RETURN(1);
330 /* We can use record cache if we don't update dynamic length tables */
331 if (!table->no_cache &&
332 (use_record_cache > 0 ||
333 (int) table->reginfo.lock_type <= (int) TL_READ_HIGH_PRIORITY ||
334 !(table->s->db_options_in_use & HA_OPTION_PACK_RECORD) ||
335 (use_record_cache < 0 &&
336 !(table->file->ha_table_flags() & HA_NOT_DELETE_WITH_CACHE))))
337 (void) table->file->extra_opt(HA_EXTRA_CACHE,
338 thd->variables.read_buff_size);
339 }
340 /* Condition pushdown to storage engine */
341 if ((table->file->ha_table_flags() & HA_CAN_TABLE_CONDITION_PUSHDOWN) &&
342 select && select->cond &&
343 (select->cond->used_tables() & table->map) &&
344 !table->file->pushed_cond)
345 table->file->cond_push(select->cond);
346
347 DBUG_RETURN(0);
348 } /* init_read_record */
349
350
351
end_read_record(READ_RECORD * info)352 void end_read_record(READ_RECORD *info)
353 {
354 /* free cache if used */
355 free_cache(info);
356 if (info->table)
357 {
358 if (info->table->db_stat) // if opened
359 (void) info->table->file->extra(HA_EXTRA_NO_CACHE);
360 if (info->read_record_func != rr_quick) // otherwise quick_range does it
361 (void) info->table->file->ha_index_or_rnd_end();
362 info->table=0;
363 }
364 }
365
366
free_cache(READ_RECORD * info)367 void free_cache(READ_RECORD *info)
368 {
369 if (info->cache)
370 {
371 my_free_lock(info->cache);
372 info->cache=0;
373 }
374 }
375
376
rr_handle_error(READ_RECORD * info,int error)377 static int rr_handle_error(READ_RECORD *info, int error)
378 {
379 if (info->thd->killed)
380 {
381 info->thd->send_kill_message();
382 return 1;
383 }
384
385 if (error == HA_ERR_END_OF_FILE)
386 error= -1;
387 else
388 {
389 if (info->print_error)
390 info->table->file->print_error(error, MYF(0));
391 if (error < 0) // Fix negative BDB errno
392 error= 1;
393 }
394 return error;
395 }
396
397
398 /** Read a record from head-database. */
399
rr_quick(READ_RECORD * info)400 static int rr_quick(READ_RECORD *info)
401 {
402 int tmp;
403 while ((tmp= info->select->quick->get_next()))
404 {
405 tmp= rr_handle_error(info, tmp);
406 break;
407 }
408 return tmp;
409 }
410
411
412 /**
413 Reads first row in an index scan.
414
415 @param info Scan info
416
417 @retval
418 0 Ok
419 @retval
420 -1 End of records
421 @retval
422 1 Error
423 */
424
rr_index_first(READ_RECORD * info)425 static int rr_index_first(READ_RECORD *info)
426 {
427 int tmp;
428 // tell handler that we are doing an index scan
429 if ((tmp = info->table->file->prepare_index_scan()))
430 {
431 tmp= rr_handle_error(info, tmp);
432 return tmp;
433 }
434
435 tmp= info->table->file->ha_index_first(info->record());
436 info->read_record_func= rr_index;
437 if (tmp)
438 tmp= rr_handle_error(info, tmp);
439 return tmp;
440 }
441
442
443 /**
444 Reads last row in an index scan.
445
446 @param info Scan info
447
448 @retval
449 0 Ok
450 @retval
451 -1 End of records
452 @retval
453 1 Error
454 */
455
rr_index_last(READ_RECORD * info)456 static int rr_index_last(READ_RECORD *info)
457 {
458 int tmp= info->table->file->ha_index_last(info->record());
459 info->read_record_func= rr_index_desc;
460 if (tmp)
461 tmp= rr_handle_error(info, tmp);
462 return tmp;
463 }
464
465
466 /**
467 Reads index sequentially after first row.
468
469 Read the next index record (in forward direction) and translate return
470 value.
471
472 @param info Scan info
473
474 @retval
475 0 Ok
476 @retval
477 -1 End of records
478 @retval
479 1 Error
480 */
481
rr_index(READ_RECORD * info)482 static int rr_index(READ_RECORD *info)
483 {
484 int tmp= info->table->file->ha_index_next(info->record());
485 if (tmp)
486 tmp= rr_handle_error(info, tmp);
487 return tmp;
488 }
489
490
491 /**
492 Reads index sequentially from the last row to the first.
493
494 Read the prev index record (in backward direction) and translate return
495 value.
496
497 @param info Scan info
498
499 @retval
500 0 Ok
501 @retval
502 -1 End of records
503 @retval
504 1 Error
505 */
506
rr_index_desc(READ_RECORD * info)507 static int rr_index_desc(READ_RECORD *info)
508 {
509 int tmp= info->table->file->ha_index_prev(info->record());
510 if (tmp)
511 tmp= rr_handle_error(info, tmp);
512 return tmp;
513 }
514
515
rr_sequential(READ_RECORD * info)516 int rr_sequential(READ_RECORD *info)
517 {
518 int tmp;
519 while ((tmp= info->table->file->ha_rnd_next(info->record())))
520 {
521 tmp= rr_handle_error(info, tmp);
522 break;
523 }
524 return tmp;
525 }
526
527
rr_from_tempfile(READ_RECORD * info)528 static int rr_from_tempfile(READ_RECORD *info)
529 {
530 int tmp;
531 for (;;)
532 {
533 if (my_b_read(info->io_cache,info->ref_pos,info->ref_length))
534 return -1; /* End of file */
535 if (!(tmp= info->table->file->ha_rnd_pos(info->record(), info->ref_pos)))
536 break;
537 /* The following is extremely unlikely to happen */
538 if (tmp == HA_ERR_KEY_NOT_FOUND)
539 continue;
540 tmp= rr_handle_error(info, tmp);
541 break;
542 }
543 return tmp;
544 } /* rr_from_tempfile */
545
546
547 /**
548 Read a result set record from a temporary file after sorting.
549
550 The function first reads the next sorted record from the temporary file.
551 into a buffer. If a success it calls a callback function that unpacks
552 the fields values use in the result set from this buffer into their
553 positions in the regular record buffer.
554
555 @param info Reference to the context including record
556 descriptors
557 @param Packed_addon_fields Are the addon fields packed?
558 This is a compile-time constant, to
559 avoid if (....) tests during execution.
560
561 @retval
562 0 Record successfully read.
563 @retval
564 -1 There is no record to be read anymore.
565 */
566
567 template<bool Packed_addon_fields>
rr_unpack_from_tempfile(READ_RECORD * info)568 static int rr_unpack_from_tempfile(READ_RECORD *info)
569 {
570 uchar *destination= info->rec_buf;
571 #ifndef DBUG_OFF
572 my_off_t where= my_b_tell(info->io_cache);
573 #endif
574 if (Packed_addon_fields)
575 {
576 const uint len_sz= Addon_fields::size_of_length_field;
577
578 // First read length of the record.
579 if (my_b_read(info->io_cache, destination, len_sz))
580 return -1;
581 uint res_length= Addon_fields::read_addon_length(destination);
582 DBUG_PRINT("info", ("rr_unpack from %llu to %p sz %u",
583 static_cast<ulonglong>(where),
584 destination, res_length));
585 DBUG_ASSERT(res_length > len_sz);
586 DBUG_ASSERT(info->sort_info->using_addon_fields());
587
588 // Then read the rest of the record.
589 if (my_b_read(info->io_cache, destination + len_sz, res_length - len_sz))
590 return -1; /* purecov: inspected */
591 }
592 else
593 {
594 if (my_b_read(info->io_cache, destination, info->ref_length))
595 return -1;
596 }
597
598 info->sort_info->unpack_addon_fields<Packed_addon_fields>(destination);
599
600 return 0;
601 }
602
rr_from_pointers(READ_RECORD * info)603 int rr_from_pointers(READ_RECORD *info)
604 {
605 int tmp;
606 uchar *cache_pos;
607
608 for (;;)
609 {
610 if (info->cache_pos == info->cache_end)
611 return -1; /* End of file */
612 cache_pos= info->cache_pos;
613 info->cache_pos+= info->ref_length;
614
615 if (!(tmp= info->table->file->ha_rnd_pos(info->record(), cache_pos)))
616 break;
617
618 /* The following is extremely unlikely to happen */
619 if (tmp == HA_ERR_KEY_NOT_FOUND)
620 continue;
621 tmp= rr_handle_error(info, tmp);
622 break;
623 }
624 return tmp;
625 }
626
627 /**
628 Read a result set record from a buffer after sorting.
629
630 The function first reads the next sorted record from the sort buffer.
631 If a success it calls a callback function that unpacks
632 the fields values use in the result set from this buffer into their
633 positions in the regular record buffer.
634
635 @param info Reference to the context including record
636 descriptors
637 @param Packed_addon_fields Are the addon fields packed?
638 This is a compile-time constant, to
639 avoid if (....) tests during execution.
640
641 @retval
642 0 Record successfully read.
643 @retval
644 -1 There is no record to be read anymore.
645 */
646
647 template<bool Packed_addon_fields, bool Packed_sort_keys>
rr_unpack_from_buffer(READ_RECORD * info)648 static int rr_unpack_from_buffer(READ_RECORD *info)
649 {
650 if (info->unpack_counter == info->sort_info->return_rows)
651 return -1; /* End of buffer */
652
653 uchar *record= info->sort_info->get_sorted_record(
654 static_cast<uint>(info->unpack_counter));
655
656 uint sort_length= Packed_sort_keys ?
657 Sort_keys::read_sortkey_length(record):
658 info->sort_info->get_sort_length();
659
660 uchar *plen= record + sort_length;
661 info->sort_info->unpack_addon_fields<Packed_addon_fields>(plen);
662 info->unpack_counter++;
663 return 0;
664 }
665 /* cacheing of records from a database */
666
667 static const uint STRUCT_LENGTH= 3 + MAX_REFLENGTH;
668
init_rr_cache(THD * thd,READ_RECORD * info)669 static int init_rr_cache(THD *thd, READ_RECORD *info)
670 {
671 uint rec_cache_size, cache_records;
672 DBUG_ENTER("init_rr_cache");
673
674 info->reclength= ALIGN_SIZE(info->table->s->reclength+1);
675 if (info->reclength < STRUCT_LENGTH)
676 info->reclength= ALIGN_SIZE(STRUCT_LENGTH);
677
678 info->error_offset= info->table->s->reclength;
679 cache_records= thd->variables.read_rnd_buff_size /
680 (info->reclength + STRUCT_LENGTH);
681 rec_cache_size= cache_records * info->reclength;
682 info->rec_cache_size= cache_records * info->ref_length;
683
684 // We have to allocate one more byte to use uint3korr (see comments for it)
685 if (cache_records <= 2 ||
686 !(info->cache= (uchar*) my_malloc_lock(rec_cache_size + cache_records *
687 STRUCT_LENGTH + 1,
688 MYF(MY_THREAD_SPECIFIC))))
689 DBUG_RETURN(1);
690 #ifdef HAVE_valgrind
691 // Avoid warnings in qsort
692 bzero(info->cache, rec_cache_size + cache_records * STRUCT_LENGTH + 1);
693 #endif
694 DBUG_PRINT("info", ("Allocated buffer for %d records", cache_records));
695 info->read_positions=info->cache+rec_cache_size;
696 info->cache_pos=info->cache_end=info->cache;
697 DBUG_RETURN(0);
698 } /* init_rr_cache */
699
700
rr_from_cache(READ_RECORD * info)701 static int rr_from_cache(READ_RECORD *info)
702 {
703 uint i;
704 ulong length;
705 my_off_t rest_of_file;
706 int16 error;
707 uchar *position,*ref_position,*record_pos;
708 ulong record;
709
710 for (;;)
711 {
712 if (info->cache_pos != info->cache_end)
713 {
714 if (unlikely(info->cache_pos[info->error_offset]))
715 {
716 shortget(error,info->cache_pos);
717 if (info->print_error)
718 info->table->file->print_error(error,MYF(0));
719 }
720 else
721 {
722 error=0;
723 memcpy(info->record(), info->cache_pos,
724 (size_t) info->table->s->reclength);
725 }
726 info->cache_pos+=info->reclength;
727 return ((int) error);
728 }
729 length=info->rec_cache_size;
730 rest_of_file=info->io_cache->end_of_file - my_b_tell(info->io_cache);
731 if ((my_off_t) length > rest_of_file)
732 length= (ulong) rest_of_file;
733 if (!length || my_b_read(info->io_cache,info->cache,length))
734 {
735 DBUG_PRINT("info",("Found end of file"));
736 return -1; /* End of file */
737 }
738
739 length/=info->ref_length;
740 position=info->cache;
741 ref_position=info->read_positions;
742 for (i=0 ; i < length ; i++,position+=info->ref_length)
743 {
744 memcpy(ref_position,position,(size_t) info->ref_length);
745 ref_position+=MAX_REFLENGTH;
746 int3store(ref_position,(long) i);
747 ref_position+=3;
748 }
749 my_qsort(info->read_positions, length, STRUCT_LENGTH, (qsort_cmp) rr_cmp);
750
751 position=info->read_positions;
752 for (i=0 ; i < length ; i++)
753 {
754 memcpy(info->ref_pos,position,(size_t) info->ref_length);
755 position+=MAX_REFLENGTH;
756 record=uint3korr(position);
757 position+=3;
758 record_pos=info->cache+record*info->reclength;
759 if (unlikely((error= (int16) info->table->file->
760 ha_rnd_pos(record_pos,info->ref_pos))))
761 {
762 record_pos[info->error_offset]=1;
763 shortstore(record_pos,error);
764 DBUG_PRINT("error",("Got error: %d:%d when reading row",
765 my_errno, error));
766 }
767 else
768 record_pos[info->error_offset]=0;
769 }
770 info->cache_end=(info->cache_pos=info->cache)+length*info->reclength;
771 }
772 } /* rr_from_cache */
773
774
rr_cmp(uchar * a,uchar * b)775 static int rr_cmp(uchar *a,uchar *b)
776 {
777 if (a[0] != b[0])
778 return (int) a[0] - (int) b[0];
779 if (a[1] != b[1])
780 return (int) a[1] - (int) b[1];
781 if (a[2] != b[2])
782 return (int) a[2] - (int) b[2];
783 #if MAX_REFLENGTH == 4
784 return (int) a[3] - (int) b[3];
785 #else
786 if (a[3] != b[3])
787 return (int) a[3] - (int) b[3];
788 if (a[4] != b[4])
789 return (int) a[4] - (int) b[4];
790 if (a[5] != b[5])
791 return (int) a[5] - (int) b[5];
792 if (a[6] != b[6])
793 return (int) a[6] - (int) b[6];
794 return (int) a[7] - (int) b[7];
795 #endif
796 }
797
798
799 /**
800 Copy (unpack) values appended to sorted fields from a buffer back to
801 their regular positions specified by the Field::ptr pointers.
802
803 @param addon_field Array of descriptors for appended fields
804 @param buff Buffer which to unpack the value from
805
806 @note
807 The function is supposed to be used only as a callback function
808 when getting field values for the sorted result set.
809
810 */
811 template<bool Packed_addon_fields>
unpack_addon_fields(uchar * buff)812 inline void SORT_INFO::unpack_addon_fields(uchar *buff)
813 {
814 SORT_ADDON_FIELD *addonf= addon_fields->begin();
815 uchar *buff_end= buff + sort_buffer_size();
816 const uchar *start_of_record= buff + addonf->offset;
817
818 for ( ; addonf != addon_fields->end() ; addonf++)
819 {
820 Field *field= addonf->field;
821 if (addonf->null_bit && (addonf->null_bit & buff[addonf->null_offset]))
822 {
823 field->set_null();
824 continue;
825 }
826 field->set_notnull();
827 if (Packed_addon_fields)
828 start_of_record= field->unpack(field->ptr, start_of_record, buff_end, 0);
829 else
830 field->unpack(field->ptr, buff + addonf->offset, buff_end, 0);
831 }
832 }
833