~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

Viewing changes to sql/records.cc

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2000-2006 MySQL AB
 
2
 
 
3
   This program is free software; you can redistribute it and/or modify
 
4
   it under the terms of the GNU General Public License as published by
 
5
   the Free Software Foundation; version 2 of the License.
 
6
 
 
7
   This program is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
   GNU General Public License for more details.
 
11
 
 
12
   You should have received a copy of the GNU General Public License
 
13
   along with this program; if not, write to the Free Software
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
 
 
17
/**
 
18
  @file
 
19
 
 
20
  @brief
 
21
  Functions for easy reading of records, possible through a cache
 
22
*/
 
23
 
 
24
#include "mysql_priv.h"
 
25
 
 
26
static int rr_quick(READ_RECORD *info);
 
27
int rr_sequential(READ_RECORD *info);
 
28
static int rr_from_tempfile(READ_RECORD *info);
 
29
static int rr_unpack_from_tempfile(READ_RECORD *info);
 
30
static int rr_unpack_from_buffer(READ_RECORD *info);
 
31
static int rr_from_pointers(READ_RECORD *info);
 
32
static int rr_from_cache(READ_RECORD *info);
 
33
static int init_rr_cache(THD *thd, READ_RECORD *info);
 
34
static int rr_cmp(uchar *a,uchar *b);
 
35
static int rr_index_first(READ_RECORD *info);
 
36
static int rr_index(READ_RECORD *info);
 
37
 
 
38
 
 
39
/**
 
40
  Initialize READ_RECORD structure to perform full index scan (in forward
 
41
  direction) using read_record.read_record() interface.
 
42
 
 
43
    This function has been added at late stage and is used only by
 
44
    UPDATE/DELETE. Other statements perform index scans using
 
45
    join_read_first/next functions.
 
46
 
 
47
  @param info         READ_RECORD structure to initialize.
 
48
  @param thd          Thread handle
 
49
  @param table        Table to be accessed
 
50
  @param print_error  If true, call table->file->print_error() if an error
 
51
                      occurs (except for end-of-records error)
 
52
  @param idx          index to scan
 
53
*/
 
54
 
 
55
void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table,
 
56
                          bool print_error, uint idx)
 
57
{
 
58
  empty_record(table);
 
59
  bzero((char*) info,sizeof(*info));
 
60
  info->thd= thd;
 
61
  info->table= table;
 
62
  info->file=  table->file;
 
63
  info->record= table->record[0];
 
64
  info->print_error= print_error;
 
65
  info->unlock_row= rr_unlock_row;
 
66
 
 
67
  table->status=0;                      /* And it's always found */
 
68
  if (!table->file->inited)
 
69
    table->file->ha_index_init(idx, 1);
 
70
  /* read_record will be changed to rr_index in rr_index_first */
 
71
  info->read_record= rr_index_first;
 
72
}
 
73
 
 
74
 
 
75
/*
 
76
  init_read_record is used to scan by using a number of different methods.
 
77
  Which method to use is set-up in this call so that later calls to
 
78
  the info->read_record will call the appropriate method using a function
 
79
  pointer.
 
80
 
 
81
  There are five methods that relate completely to the sort function
 
82
  filesort. The result of a filesort is retrieved using read_record
 
83
  calls. The other two methods are used for normal table access.
 
84
 
 
85
  The filesort will produce references to the records sorted, these
 
86
  references can be stored in memory or in a temporary file.
 
87
 
 
88
  The temporary file is normally used when the references doesn't fit into
 
89
  a properly sized memory buffer. For most small queries the references
 
90
  are stored in the memory buffer.
 
91
  SYNOPSIS
 
92
    init_read_record()
 
93
      info              OUT read structure
 
94
      thd               Thread handle
 
95
      table             Table the data [originally] comes from.
 
96
      select            SQL_SELECT structure. We may select->quick or 
 
97
                        select->file as data source
 
98
      use_record_cache  Call file->extra_opt(HA_EXTRA_CACHE,...)
 
99
                        if we're going to do sequential read and some
 
100
                        additional conditions are satisfied.
 
101
      print_error       Copy this to info->print_error
 
102
      disable_rr_cache  Don't use rr_from_cache (used by sort-union
 
103
                        index-merge which produces rowid sequences that 
 
104
                        are already ordered)
 
105
 
 
106
  DESCRIPTION
 
107
    This function sets up reading data via one of the methods:
 
108
 
 
109
  The temporary file is also used when performing an update where a key is
 
110
  modified.
 
111
 
 
112
  Methods used when ref's are in memory (using rr_from_pointers):
 
113
    rr_unpack_from_buffer:
 
114
    ----------------------
 
115
      This method is used when table->sort.addon_field is allocated.
 
116
      This is allocated for most SELECT queries not involving any BLOB's.
 
117
      In this case the records are fetched from a memory buffer.
 
118
    rr_from_pointers:
 
119
    -----------------
 
120
      Used when the above is not true, UPDATE, DELETE and so forth and
 
121
      SELECT's involving BLOB's. It is also used when the addon_field
 
122
      buffer is not allocated due to that its size was bigger than the
 
123
      session variable max_length_for_sort_data.
 
124
      In this case the record data is fetched from the handler using the
 
125
      saved reference using the rnd_pos handler call.
 
126
 
 
127
  Methods used when ref's are in a temporary file (using rr_from_tempfile)
 
128
    rr_unpack_from_tempfile:
 
129
    ------------------------
 
130
      Same as rr_unpack_from_buffer except that references are fetched from
 
131
      temporary file. Should obviously not really happen other than in
 
132
      strange configurations.
 
133
 
 
134
    rr_from_tempfile:
 
135
    -----------------
 
136
      Same as rr_from_pointers except that references are fetched from
 
137
      temporary file instead of from 
 
138
    rr_from_cache:
 
139
    --------------
 
140
      This is a special variant of rr_from_tempfile that can be used for
 
141
      handlers that is not using the HA_FAST_KEY_READ table flag. Instead
 
142
      of reading the references one by one from the temporary file it reads
 
143
      a set of them, sorts them and reads all of them into a buffer which
 
144
      is then used for a number of subsequent calls to rr_from_cache.
 
145
      It is only used for SELECT queries and a number of other conditions
 
146
      on table size.
 
147
 
 
148
  All other accesses use either index access methods (rr_quick) or a full
 
149
  table scan (rr_sequential).
 
150
  rr_quick:
 
151
  ---------
 
152
    rr_quick uses one of the QUICK_SELECT classes in opt_range.cc to
 
153
    perform an index scan. There are loads of functionality hidden
 
154
    in these quick classes. It handles all index scans of various kinds.
 
155
  rr_sequential:
 
156
  --------------
 
157
    This is the most basic access method of a table using rnd_init,
 
158
    rnd_next and rnd_end. No indexes are used.
 
159
*/
 
160
void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
 
161
                      SQL_SELECT *select,
 
162
                      int use_record_cache, bool print_error, 
 
163
                      bool disable_rr_cache)
 
164
{
 
165
  IO_CACHE *tempfile;
 
166
  DBUG_ENTER("init_read_record");
 
167
 
 
168
  bzero((char*) info,sizeof(*info));
 
169
  info->thd=thd;
 
170
  info->table=table;
 
171
  info->file= table->file;
 
172
  info->forms= &info->table;            /* Only one table */
 
173
  
 
174
  if (table->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE &&
 
175
      !table->sort.addon_field)
 
176
    VOID(table->file->extra(HA_EXTRA_MMAP));
 
177
  
 
178
  if (table->sort.addon_field)
 
179
  {
 
180
    info->rec_buf= table->sort.addon_buf;
 
181
    info->ref_length= table->sort.addon_length;
 
182
  }
 
183
  else
 
184
  {
 
185
    empty_record(table);
 
186
    info->record= table->record[0];
 
187
    info->ref_length= table->file->ref_length;
 
188
  }
 
189
  info->select=select;
 
190
  info->print_error=print_error;
 
191
  info->unlock_row= rr_unlock_row;
 
192
  info->ignore_not_found_rows= 0;
 
193
  table->status=0;                      /* And it's always found */
 
194
 
 
195
  if (select && my_b_inited(&select->file))
 
196
    tempfile= &select->file;
 
197
  else
 
198
    tempfile= table->sort.io_cache;
 
199
  if (tempfile && my_b_inited(tempfile)) // Test if ref-records was used
 
200
  {
 
201
    DBUG_PRINT("info",("using rr_from_tempfile"));
 
202
    info->read_record= (table->sort.addon_field ?
 
203
                        rr_unpack_from_tempfile : rr_from_tempfile);
 
204
    info->io_cache=tempfile;
 
205
    reinit_io_cache(info->io_cache,READ_CACHE,0L,0,0);
 
206
    info->ref_pos=table->file->ref;
 
207
    if (!table->file->inited)
 
208
      table->file->ha_rnd_init(0);
 
209
 
 
210
    /*
 
211
      table->sort.addon_field is checked because if we use addon fields,
 
212
      it doesn't make sense to use cache - we don't read from the table
 
213
      and table->sort.io_cache is read sequentially
 
214
    */
 
215
    if (!disable_rr_cache &&
 
216
        !table->sort.addon_field &&
 
217
        ! (specialflag & SPECIAL_SAFE_MODE) &&
 
218
        thd->variables.read_rnd_buff_size &&
 
219
        !(table->file->ha_table_flags() & HA_FAST_KEY_READ) &&
 
220
        (table->db_stat & HA_READ_ONLY ||
 
221
         table->reginfo.lock_type <= TL_READ_NO_INSERT) &&
 
222
        (ulonglong) table->s->reclength* (table->file->stats.records+
 
223
                                          table->file->stats.deleted) >
 
224
        (ulonglong) MIN_FILE_LENGTH_TO_USE_ROW_CACHE &&
 
225
        info->io_cache->end_of_file/info->ref_length * table->s->reclength >
 
226
        (my_off_t) MIN_ROWS_TO_USE_TABLE_CACHE &&
 
227
        !table->s->blob_fields &&
 
228
        info->ref_length <= MAX_REFLENGTH)
 
229
    {
 
230
      if (! init_rr_cache(thd, info))
 
231
      {
 
232
        DBUG_PRINT("info",("using rr_from_cache"));
 
233
        info->read_record=rr_from_cache;
 
234
      }
 
235
    }
 
236
  }
 
237
  else if (select && select->quick)
 
238
  {
 
239
    DBUG_PRINT("info",("using rr_quick"));
 
240
    info->read_record=rr_quick;
 
241
  }
 
242
  else if (table->sort.record_pointers)
 
243
  {
 
244
    DBUG_PRINT("info",("using record_pointers"));
 
245
    table->file->ha_rnd_init(0);
 
246
    info->cache_pos=table->sort.record_pointers;
 
247
    info->cache_end=info->cache_pos+ 
 
248
                    table->sort.found_records*info->ref_length;
 
249
    info->read_record= (table->sort.addon_field ?
 
250
                        rr_unpack_from_buffer : rr_from_pointers);
 
251
  }
 
252
  else
 
253
  {
 
254
    DBUG_PRINT("info",("using rr_sequential"));
 
255
    info->read_record=rr_sequential;
 
256
    table->file->ha_rnd_init(1);
 
257
    /* We can use record cache if we don't update dynamic length tables */
 
258
    if (!table->no_cache &&
 
259
        (use_record_cache > 0 ||
 
260
         (int) table->reginfo.lock_type <= (int) TL_READ_HIGH_PRIORITY ||
 
261
         !(table->s->db_options_in_use & HA_OPTION_PACK_RECORD) ||
 
262
         (use_record_cache < 0 &&
 
263
          !(table->file->ha_table_flags() & HA_NOT_DELETE_WITH_CACHE))))
 
264
      VOID(table->file->extra_opt(HA_EXTRA_CACHE,
 
265
                                  thd->variables.read_buff_size));
 
266
  }
 
267
  /* Condition pushdown to storage engine */
 
268
  if (thd->variables.engine_condition_pushdown && 
 
269
      select && select->cond && 
 
270
      (select->cond->used_tables() & table->map) &&
 
271
      !table->file->pushed_cond)
 
272
    table->file->cond_push(select->cond);
 
273
 
 
274
  DBUG_VOID_RETURN;
 
275
} /* init_read_record */
 
276
 
 
277
 
 
278
 
 
279
void end_read_record(READ_RECORD *info)
 
280
{                   /* free cache if used */
 
281
  if (info->cache)
 
282
  {
 
283
    my_free_lock((char*) info->cache,MYF(0));
 
284
    info->cache=0;
 
285
  }
 
286
  if (info->table)
 
287
  {
 
288
    filesort_free_buffers(info->table,0);
 
289
    (void) info->file->extra(HA_EXTRA_NO_CACHE);
 
290
    if (info->read_record != rr_quick) // otherwise quick_range does it
 
291
      (void) info->file->ha_index_or_rnd_end();
 
292
    info->table=0;
 
293
  }
 
294
}
 
295
 
 
296
static int rr_handle_error(READ_RECORD *info, int error)
 
297
{
 
298
  if (info->thd->killed)
 
299
  {
 
300
    info->thd->send_kill_message();
 
301
    return 1;
 
302
  }
 
303
 
 
304
  if (error == HA_ERR_END_OF_FILE)
 
305
    error= -1;
 
306
  else
 
307
  {
 
308
    if (info->print_error)
 
309
      info->table->file->print_error(error, MYF(0));
 
310
    if (error < 0)                            // Fix negative BDB errno
 
311
      error= 1;
 
312
  }
 
313
  return error;
 
314
}
 
315
 
 
316
 
 
317
/** Read a record from head-database. */
 
318
 
 
319
static int rr_quick(READ_RECORD *info)
 
320
{
 
321
  int tmp;
 
322
  while ((tmp= info->select->quick->get_next()))
 
323
  {
 
324
    if (info->thd->killed || (tmp != HA_ERR_RECORD_DELETED))
 
325
    {
 
326
      tmp= rr_handle_error(info, tmp);
 
327
      break;
 
328
    }
 
329
  }
 
330
  return tmp;
 
331
}
 
332
 
 
333
 
 
334
/**
 
335
  Reads first row in an index scan.
 
336
 
 
337
  @param info   Scan info
 
338
 
 
339
  @retval
 
340
    0   Ok
 
341
  @retval
 
342
    -1   End of records
 
343
  @retval
 
344
    1   Error
 
345
*/
 
346
 
 
347
static int rr_index_first(READ_RECORD *info)
 
348
{
 
349
  int tmp= info->file->index_first(info->record);
 
350
  info->read_record= rr_index;
 
351
  if (tmp)
 
352
    tmp= rr_handle_error(info, tmp);
 
353
  return tmp;
 
354
}
 
355
 
 
356
 
 
357
/**
 
358
  Reads index sequentially after first row.
 
359
 
 
360
  Read the next index record (in forward direction) and translate return
 
361
  value.
 
362
 
 
363
  @param info  Scan info
 
364
 
 
365
  @retval
 
366
    0   Ok
 
367
  @retval
 
368
    -1   End of records
 
369
  @retval
 
370
    1   Error
 
371
*/
 
372
 
 
373
static int rr_index(READ_RECORD *info)
 
374
{
 
375
  int tmp= info->file->index_next(info->record);
 
376
  if (tmp)
 
377
    tmp= rr_handle_error(info, tmp);
 
378
  return tmp;
 
379
}
 
380
 
 
381
 
 
382
int rr_sequential(READ_RECORD *info)
 
383
{
 
384
  int tmp;
 
385
  while ((tmp=info->file->rnd_next(info->record)))
 
386
  {
 
387
    /*
 
388
      rnd_next can return RECORD_DELETED for MyISAM when one thread is
 
389
      reading and another deleting without locks.
 
390
    */
 
391
    if (info->thd->killed || (tmp != HA_ERR_RECORD_DELETED))
 
392
    {
 
393
      tmp= rr_handle_error(info, tmp);
 
394
      break;
 
395
    }
 
396
  }
 
397
  return tmp;
 
398
}
 
399
 
 
400
 
 
401
static int rr_from_tempfile(READ_RECORD *info)
 
402
{
 
403
  int tmp;
 
404
  for (;;)
 
405
  {
 
406
    if (my_b_read(info->io_cache,info->ref_pos,info->ref_length))
 
407
      return -1;                                        /* End of file */
 
408
    if (!(tmp=info->file->rnd_pos(info->record,info->ref_pos)))
 
409
      break;
 
410
    /* The following is extremely unlikely to happen */
 
411
    if (tmp == HA_ERR_RECORD_DELETED ||
 
412
        (tmp == HA_ERR_KEY_NOT_FOUND && info->ignore_not_found_rows))
 
413
      continue;
 
414
    tmp= rr_handle_error(info, tmp);
 
415
    break;
 
416
  }
 
417
  return tmp;
 
418
} /* rr_from_tempfile */
 
419
 
 
420
 
 
421
/**
 
422
  Read a result set record from a temporary file after sorting.
 
423
 
 
424
  The function first reads the next sorted record from the temporary file.
 
425
  into a buffer. If a success it calls a callback function that unpacks 
 
426
  the fields values use in the result set from this buffer into their
 
427
  positions in the regular record buffer.
 
428
 
 
429
  @param info          Reference to the context including record descriptors
 
430
 
 
431
  @retval
 
432
    0   Record successfully read.
 
433
  @retval
 
434
    -1   There is no record to be read anymore.
 
435
*/
 
436
 
 
437
static int rr_unpack_from_tempfile(READ_RECORD *info)
 
438
{
 
439
  if (my_b_read(info->io_cache, info->rec_buf, info->ref_length))
 
440
    return -1;
 
441
  TABLE *table= info->table;
 
442
  (*table->sort.unpack)(table->sort.addon_field, info->rec_buf);
 
443
 
 
444
  return 0;
 
445
}
 
446
 
 
447
static int rr_from_pointers(READ_RECORD *info)
 
448
{
 
449
  int tmp;
 
450
  uchar *cache_pos;
 
451
 
 
452
  for (;;)
 
453
  {
 
454
    if (info->cache_pos == info->cache_end)
 
455
      return -1;                                        /* End of file */
 
456
    cache_pos= info->cache_pos;
 
457
    info->cache_pos+= info->ref_length;
 
458
 
 
459
    if (!(tmp=info->file->rnd_pos(info->record,cache_pos)))
 
460
      break;
 
461
 
 
462
    /* The following is extremely unlikely to happen */
 
463
    if (tmp == HA_ERR_RECORD_DELETED ||
 
464
        (tmp == HA_ERR_KEY_NOT_FOUND && info->ignore_not_found_rows))
 
465
      continue;
 
466
    tmp= rr_handle_error(info, tmp);
 
467
    break;
 
468
  }
 
469
  return tmp;
 
470
}
 
471
 
 
472
/**
 
473
  Read a result set record from a buffer after sorting.
 
474
 
 
475
  The function first reads the next sorted record from the sort buffer.
 
476
  If a success it calls a callback function that unpacks 
 
477
  the fields values use in the result set from this buffer into their
 
478
  positions in the regular record buffer.
 
479
 
 
480
  @param info          Reference to the context including record descriptors
 
481
 
 
482
  @retval
 
483
    0   Record successfully read.
 
484
  @retval
 
485
    -1   There is no record to be read anymore.
 
486
*/
 
487
 
 
488
static int rr_unpack_from_buffer(READ_RECORD *info)
 
489
{
 
490
  if (info->cache_pos == info->cache_end)
 
491
    return -1;                      /* End of buffer */
 
492
  TABLE *table= info->table;
 
493
  (*table->sort.unpack)(table->sort.addon_field, info->cache_pos);
 
494
  info->cache_pos+= info->ref_length;
 
495
 
 
496
  return 0;
 
497
}
 
498
        /* cacheing of records from a database */
 
499
 
 
500
static int init_rr_cache(THD *thd, READ_RECORD *info)
 
501
{
 
502
  uint rec_cache_size;
 
503
  DBUG_ENTER("init_rr_cache");
 
504
 
 
505
  info->struct_length= 3+MAX_REFLENGTH;
 
506
  info->reclength= ALIGN_SIZE(info->table->s->reclength+1);
 
507
  if (info->reclength < info->struct_length)
 
508
    info->reclength= ALIGN_SIZE(info->struct_length);
 
509
 
 
510
  info->error_offset= info->table->s->reclength;
 
511
  info->cache_records= (thd->variables.read_rnd_buff_size /
 
512
                        (info->reclength+info->struct_length));
 
513
  rec_cache_size= info->cache_records*info->reclength;
 
514
  info->rec_cache_size= info->cache_records*info->ref_length;
 
515
 
 
516
  // We have to allocate one more byte to use uint3korr (see comments for it)
 
517
  if (info->cache_records <= 2 ||
 
518
      !(info->cache=(uchar*) my_malloc_lock(rec_cache_size+info->cache_records*
 
519
                                           info->struct_length+1,
 
520
                                           MYF(0))))
 
521
    DBUG_RETURN(1);
 
522
#ifdef HAVE_purify
 
523
  // Avoid warnings in qsort
 
524
  bzero(info->cache,rec_cache_size+info->cache_records* info->struct_length+1);
 
525
#endif
 
526
  DBUG_PRINT("info",("Allocated buffert for %d records",info->cache_records));
 
527
  info->read_positions=info->cache+rec_cache_size;
 
528
  info->cache_pos=info->cache_end=info->cache;
 
529
  DBUG_RETURN(0);
 
530
} /* init_rr_cache */
 
531
 
 
532
 
 
533
static int rr_from_cache(READ_RECORD *info)
 
534
{
 
535
  reg1 uint i;
 
536
  ulong length;
 
537
  my_off_t rest_of_file;
 
538
  int16 error;
 
539
  uchar *position,*ref_position,*record_pos;
 
540
  ulong record;
 
541
 
 
542
  for (;;)
 
543
  {
 
544
    if (info->cache_pos != info->cache_end)
 
545
    {
 
546
      if (info->cache_pos[info->error_offset])
 
547
      {
 
548
        shortget(error,info->cache_pos);
 
549
        if (info->print_error)
 
550
          info->table->file->print_error(error,MYF(0));
 
551
      }
 
552
      else
 
553
      {
 
554
        error=0;
 
555
        memcpy(info->record,info->cache_pos,
 
556
               (size_t) info->table->s->reclength);
 
557
      }
 
558
      info->cache_pos+=info->reclength;
 
559
      return ((int) error);
 
560
    }
 
561
    length=info->rec_cache_size;
 
562
    rest_of_file=info->io_cache->end_of_file - my_b_tell(info->io_cache);
 
563
    if ((my_off_t) length > rest_of_file)
 
564
      length= (ulong) rest_of_file;
 
565
    if (!length || my_b_read(info->io_cache,info->cache,length))
 
566
    {
 
567
      DBUG_PRINT("info",("Found end of file"));
 
568
      return -1;                        /* End of file */
 
569
    }
 
570
 
 
571
    length/=info->ref_length;
 
572
    position=info->cache;
 
573
    ref_position=info->read_positions;
 
574
    for (i=0 ; i < length ; i++,position+=info->ref_length)
 
575
    {
 
576
      memcpy(ref_position,position,(size_t) info->ref_length);
 
577
      ref_position+=MAX_REFLENGTH;
 
578
      int3store(ref_position,(long) i);
 
579
      ref_position+=3;
 
580
    }
 
581
    my_qsort(info->read_positions, length, info->struct_length,
 
582
             (qsort_cmp) rr_cmp);
 
583
 
 
584
    position=info->read_positions;
 
585
    for (i=0 ; i < length ; i++)
 
586
    {
 
587
      memcpy(info->ref_pos,position,(size_t) info->ref_length);
 
588
      position+=MAX_REFLENGTH;
 
589
      record=uint3korr(position);
 
590
      position+=3;
 
591
      record_pos=info->cache+record*info->reclength;
 
592
      if ((error=(int16) info->file->rnd_pos(record_pos,info->ref_pos)))
 
593
      {
 
594
        record_pos[info->error_offset]=1;
 
595
        shortstore(record_pos,error);
 
596
        DBUG_PRINT("error",("Got error: %d:%d when reading row",
 
597
                            my_errno, error));
 
598
      }
 
599
      else
 
600
        record_pos[info->error_offset]=0;
 
601
    }
 
602
    info->cache_end=(info->cache_pos=info->cache)+length*info->reclength;
 
603
  }
 
604
} /* rr_from_cache */
 
605
 
 
606
 
 
607
static int rr_cmp(uchar *a,uchar *b)
 
608
{
 
609
  if (a[0] != b[0])
 
610
    return (int) a[0] - (int) b[0];
 
611
  if (a[1] != b[1])
 
612
    return (int) a[1] - (int) b[1];
 
613
  if (a[2] != b[2])
 
614
    return (int) a[2] - (int) b[2];
 
615
#if MAX_REFLENGTH == 4
 
616
  return (int) a[3] - (int) b[3];
 
617
#else
 
618
  if (a[3] != b[3])
 
619
    return (int) a[3] - (int) b[3];
 
620
  if (a[4] != b[4])
 
621
    return (int) a[4] - (int) b[4];
 
622
  if (a[5] != b[5])
 
623
    return (int) a[1] - (int) b[5];
 
624
  if (a[6] != b[6])
 
625
    return (int) a[6] - (int) b[6];
 
626
  return (int) a[7] - (int) b[7];
 
627
#endif
 
628
}