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