~drizzle-trunk/drizzle/development

1 by brian
clean slate
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
  @file
18
19
  @brief
20
  Functions for easy reading of records, possible through a cache
21
*/
243.1.17 by Jay Pipes
FINAL PHASE removal of mysql_priv.h (Bye, bye my friend.)
22
#include <drizzled/server_includes.h>
550 by Monty Taylor
Moved error.h into just the files that need it.
23
#include <drizzled/error.h>
584.1.15 by Monty Taylor
The mega-patch from hell. Renamed sql_class to session (since that's what it is) and removed it and field and table from common_includes.
24
#include <drizzled/table.h>
25
#include <drizzled/session.h>
1 by brian
clean slate
26
1039.2.8 by Jay Pipes
Yet more indentation and style cleanup
27
int rr_sequential(READ_RECORD *info);
1 by brian
clean slate
28
static int rr_quick(READ_RECORD *info);
29
static int rr_from_tempfile(READ_RECORD *info);
30
static int rr_unpack_from_tempfile(READ_RECORD *info);
31
static int rr_unpack_from_buffer(READ_RECORD *info);
32
static int rr_from_pointers(READ_RECORD *info);
33
static int rr_from_cache(READ_RECORD *info);
520.1.22 by Brian Aker
Second pass of thd cleanup
34
static int init_rr_cache(Session *session, READ_RECORD *info);
481 by Brian Aker
Remove all of uchar.
35
static int rr_cmp(unsigned char *a,unsigned char *b);
1 by brian
clean slate
36
static int rr_index_first(READ_RECORD *info);
37
static int rr_index(READ_RECORD *info);
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.
520.1.22 by Brian Aker
Second pass of thd cleanup
48
  @param session          Thread handle
1 by brian
clean slate
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
*/
1039.2.8 by Jay Pipes
Yet more indentation and style cleanup
54
void init_read_record_idx(READ_RECORD *info, 
55
                          Session *, 
56
                          Table *table,
57
                          bool print_error, 
58
                          uint32_t idx)
1 by brian
clean slate
59
{
997.5.1 by chris
Replace macros around unireg.h, store_record,restore_record,cmp_record,empty_record
60
  table->emptyRecord();
212.6.6 by Mats Kindahl
Removing redundant use of casts in drizzled/ for memcmp(), memcpy(), memset(), and memmove().
61
  memset(info, 0, sizeof(*info));
1 by brian
clean slate
62
  info->table= table;
63
  info->file=  table->file;
64
  info->record= table->record[0];
65
  info->print_error= print_error;
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
  init_read_record is used to scan by using a number of different methods.
76
  Which method to use is set-up in this call so that later calls to
77
  the info->read_record will call the appropriate method using a function
78
  pointer.
79
80
  There are five methods that relate completely to the sort function
81
  filesort. The result of a filesort is retrieved using read_record
82
  calls. The other two methods are used for normal table access.
83
84
  The filesort will produce references to the records sorted, these
85
  references can be stored in memory or in a temporary file.
86
87
  The temporary file is normally used when the references doesn't fit into
88
  a properly sized memory buffer. For most small queries the references
89
  are stored in the memory buffer.
90
91
  The temporary file is also used when performing an update where a key is
92
  modified.
93
94
  Methods used when ref's are in memory (using rr_from_pointers):
95
    rr_unpack_from_buffer:
96
    ----------------------
97
      This method is used when table->sort.addon_field is allocated.
98
      This is allocated for most SELECT queries not involving any BLOB's.
99
      In this case the records are fetched from a memory buffer.
100
    rr_from_pointers:
101
    -----------------
102
      Used when the above is not true, UPDATE, DELETE and so forth and
103
      SELECT's involving BLOB's. It is also used when the addon_field
104
      buffer is not allocated due to that its size was bigger than the
105
      session variable max_length_for_sort_data.
106
      In this case the record data is fetched from the handler using the
107
      saved reference using the rnd_pos handler call.
108
109
  Methods used when ref's are in a temporary file (using rr_from_tempfile)
110
    rr_unpack_from_tempfile:
111
    ------------------------
112
      Same as rr_unpack_from_buffer except that references are fetched from
113
      temporary file. Should obviously not really happen other than in
114
      strange configurations.
115
116
    rr_from_tempfile:
117
    -----------------
118
      Same as rr_from_pointers except that references are fetched from
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
119
      temporary file instead of from
1 by brian
clean slate
120
    rr_from_cache:
121
    --------------
122
      This is a special variant of rr_from_tempfile that can be used for
123
      handlers that is not using the HA_FAST_KEY_READ table flag. Instead
124
      of reading the references one by one from the temporary file it reads
125
      a set of them, sorts them and reads all of them into a buffer which
126
      is then used for a number of subsequent calls to rr_from_cache.
127
      It is only used for SELECT queries and a number of other conditions
128
      on table size.
129
130
  All other accesses use either index access methods (rr_quick) or a full
131
  table scan (rr_sequential).
132
  rr_quick:
133
  ---------
134
    rr_quick uses one of the QUICK_SELECT classes in opt_range.cc to
135
    perform an index scan. There are loads of functionality hidden
136
    in these quick classes. It handles all index scans of various kinds.
137
  rr_sequential:
138
  --------------
139
    This is the most basic access method of a table using rnd_init,
140
    rnd_next and rnd_end. No indexes are used.
141
*/
1039.2.8 by Jay Pipes
Yet more indentation and style cleanup
142
void init_read_record(READ_RECORD *info,
143
                      Session *session, 
144
                      Table *table,
145
		                  SQL_SELECT *select,
146
		                  int use_record_cache, 
147
                      bool print_error)
1 by brian
clean slate
148
{
149
  IO_CACHE *tempfile;
150
212.6.6 by Mats Kindahl
Removing redundant use of casts in drizzled/ for memcmp(), memcpy(), memset(), and memmove().
151
  memset(info, 0, sizeof(*info));
520.1.22 by Brian Aker
Second pass of thd cleanup
152
  info->session=session;
1 by brian
clean slate
153
  info->table=table;
154
  info->file= table->file;
155
  info->forms= &info->table;		/* Only one table */
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
156
1 by brian
clean slate
157
  if (table->sort.addon_field)
158
  {
159
    info->rec_buf= table->sort.addon_buf;
160
    info->ref_length= table->sort.addon_length;
161
  }
162
  else
163
  {
997.5.1 by chris
Replace macros around unireg.h, store_record,restore_record,cmp_record,empty_record
164
    table->emptyRecord();
1 by brian
clean slate
165
    info->record= table->record[0];
166
    info->ref_length= table->file->ref_length;
167
  }
168
  info->select=select;
169
  info->print_error=print_error;
170
  info->ignore_not_found_rows= 0;
171
  table->status=0;			/* And it's always found */
172
173
  if (select && my_b_inited(&select->file))
174
    tempfile= &select->file;
175
  else
176
    tempfile= table->sort.io_cache;
177
  if (tempfile && my_b_inited(tempfile)) // Test if ref-records was used
178
  {
179
    info->read_record= (table->sort.addon_field ?
180
                        rr_unpack_from_tempfile : rr_from_tempfile);
181
    info->io_cache=tempfile;
182
    reinit_io_cache(info->io_cache,READ_CACHE,0L,0,0);
183
    info->ref_pos=table->file->ref;
184
    if (!table->file->inited)
185
      table->file->ha_rnd_init(0);
186
187
    /*
188
      table->sort.addon_field is checked because if we use addon fields,
189
      it doesn't make sense to use cache - we don't read from the table
190
      and table->sort.io_cache is read sequentially
191
    */
192
    if (!table->sort.addon_field &&
1039.2.8 by Jay Pipes
Yet more indentation and style cleanup
193
        session->variables.read_rnd_buff_size &&
194
        !(table->file->ha_table_flags() & HA_FAST_KEY_READ) &&
195
        (table->db_stat & HA_READ_ONLY ||
196
        table->reginfo.lock_type <= TL_READ_NO_INSERT) &&
197
        (uint64_t) table->s->reclength* (table->file->stats.records+
198
                                                table->file->stats.deleted) >
199
        (uint64_t) MIN_FILE_LENGTH_TO_USE_ROW_CACHE &&
200
        info->io_cache->end_of_file/info->ref_length * table->s->reclength >
201
        (my_off_t) MIN_ROWS_TO_USE_TABLE_CACHE &&
202
        !table->s->blob_fields &&
1 by brian
clean slate
203
        info->ref_length <= MAX_REFLENGTH)
204
    {
520.1.22 by Brian Aker
Second pass of thd cleanup
205
      if (! init_rr_cache(session, info))
1 by brian
clean slate
206
      {
1039.2.8 by Jay Pipes
Yet more indentation and style cleanup
207
        info->read_record=rr_from_cache;
1 by brian
clean slate
208
      }
209
    }
210
  }
211
  else if (select && select->quick)
212
  {
213
    info->read_record=rr_quick;
214
  }
215
  else if (table->sort.record_pointers)
216
  {
217
    table->file->ha_rnd_init(0);
218
    info->cache_pos=table->sort.record_pointers;
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
219
    info->cache_end=info->cache_pos+
1 by brian
clean slate
220
                    table->sort.found_records*info->ref_length;
221
    info->read_record= (table->sort.addon_field ?
222
                        rr_unpack_from_buffer : rr_from_pointers);
223
  }
224
  else
225
  {
226
    info->read_record=rr_sequential;
227
    table->file->ha_rnd_init(1);
228
    /* We can use record cache if we don't update dynamic length tables */
229
    if (!table->no_cache &&
1039.2.8 by Jay Pipes
Yet more indentation and style cleanup
230
        (use_record_cache > 0 ||
231
        (int) table->reginfo.lock_type <= (int) TL_READ_WITH_SHARED_LOCKS ||
232
        !(table->s->db_options_in_use & HA_OPTION_PACK_RECORD) ||
233
        (use_record_cache < 0 &&
234
          !(table->file->ha_table_flags() & HA_NOT_DELETE_WITH_CACHE))))
520.1.22 by Brian Aker
Second pass of thd cleanup
235
      table->file->extra_opt(HA_EXTRA_CACHE, session->variables.read_buff_size);
1 by brian
clean slate
236
  }
237
51.1.4 by Jay Pipes
Removed all DBUG_XXX content from records.cc. Builds/tests run fine. On to next file...
238
  return;
1 by brian
clean slate
239
} /* init_read_record */
240
241
void end_read_record(READ_RECORD *info)
242
{                   /* free cache if used */
243
  if (info->cache)
244
  {
477 by Monty Taylor
Removed my_free(). It turns out that it had been def'd to ignore the flags passed to it in the second arg anyway. Gotta love that.
245
    free((char*) info->cache);
1 by brian
clean slate
246
    info->cache=0;
247
  }
248
  if (info->table)
249
  {
1109.1.4 by Brian Aker
More Table refactor
250
    info->table->filesort_free_buffers();
1 by brian
clean slate
251
    (void) info->file->extra(HA_EXTRA_NO_CACHE);
252
    if (info->read_record != rr_quick) // otherwise quick_range does it
253
      (void) info->file->ha_index_or_rnd_end();
254
    info->table=0;
255
  }
256
}
257
258
static int rr_handle_error(READ_RECORD *info, int error)
259
{
260
  if (error == HA_ERR_END_OF_FILE)
261
    error= -1;
262
  else
263
  {
264
    if (info->print_error)
265
      info->table->file->print_error(error, MYF(0));
266
    if (error < 0)                            // Fix negative BDB errno
267
      error= 1;
268
  }
269
  return error;
270
}
271
272
/** Read a record from head-database. */
273
static int rr_quick(READ_RECORD *info)
274
{
275
  int tmp;
276
  while ((tmp= info->select->quick->get_next()))
277
  {
520.1.22 by Brian Aker
Second pass of thd cleanup
278
    if (info->session->killed)
1 by brian
clean slate
279
    {
280
      my_error(ER_SERVER_SHUTDOWN, MYF(0));
281
      return 1;
282
    }
283
    if (tmp != HA_ERR_RECORD_DELETED)
284
    {
285
      tmp= rr_handle_error(info, tmp);
286
      break;
287
    }
288
  }
998.1.2 by Brian Aker
First pass on removing virt columns
289
1 by brian
clean slate
290
  return tmp;
291
}
292
293
/**
294
  Reads first row in an index scan.
295
296
  @param info  	Scan info
297
298
  @retval
299
    0   Ok
300
  @retval
301
    -1   End of records
302
  @retval
303
    1   Error
304
*/
305
static int rr_index_first(READ_RECORD *info)
306
{
307
  int tmp= info->file->index_first(info->record);
308
  info->read_record= rr_index;
309
  if (tmp)
310
    tmp= rr_handle_error(info, tmp);
311
  return tmp;
312
}
313
314
/**
315
  Reads index sequentially after first row.
316
317
  Read the next index record (in forward direction) and translate return
318
  value.
319
320
  @param info  Scan info
321
322
  @retval
323
    0   Ok
324
  @retval
325
    -1   End of records
326
  @retval
327
    1   Error
328
*/
329
static int rr_index(READ_RECORD *info)
330
{
331
  int tmp= info->file->index_next(info->record);
332
  if (tmp)
333
    tmp= rr_handle_error(info, tmp);
334
  return tmp;
335
}
336
337
int rr_sequential(READ_RECORD *info)
338
{
339
  int tmp;
822 by Brian Aker
Merge from Stewart.
340
  while ((tmp= info->file->rnd_next(info->record)))
1 by brian
clean slate
341
  {
520.1.22 by Brian Aker
Second pass of thd cleanup
342
    if (info->session->killed)
1 by brian
clean slate
343
    {
520.1.22 by Brian Aker
Second pass of thd cleanup
344
      info->session->send_kill_message();
1 by brian
clean slate
345
      return 1;
346
    }
347
    /*
822 by Brian Aker
Merge from Stewart.
348
      TODO> Fix this so that engine knows how to behave on its own.
1 by brian
clean slate
349
      rnd_next can return RECORD_DELETED for MyISAM when one thread is
350
      reading and another deleting without locks.
351
    */
352
    if (tmp != HA_ERR_RECORD_DELETED)
353
    {
354
      tmp= rr_handle_error(info, tmp);
355
      break;
356
    }
357
  }
998.1.2 by Brian Aker
First pass on removing virt columns
358
1 by brian
clean slate
359
  return tmp;
360
}
361
362
static int rr_from_tempfile(READ_RECORD *info)
363
{
364
  int tmp;
365
  for (;;)
366
  {
367
    if (my_b_read(info->io_cache,info->ref_pos,info->ref_length))
368
      return -1;					/* End of file */
369
    if (!(tmp=info->file->rnd_pos(info->record,info->ref_pos)))
370
      break;
371
    /* The following is extremely unlikely to happen */
372
    if (tmp == HA_ERR_RECORD_DELETED ||
373
        (tmp == HA_ERR_KEY_NOT_FOUND && info->ignore_not_found_rows))
374
      continue;
375
    tmp= rr_handle_error(info, tmp);
376
    break;
377
  }
378
  return tmp;
379
} /* rr_from_tempfile */
380
381
/**
382
  Read a result set record from a temporary file after sorting.
383
384
  The function first reads the next sorted record from the temporary file.
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
385
  into a buffer. If a success it calls a callback function that unpacks
1 by brian
clean slate
386
  the fields values use in the result set from this buffer into their
387
  positions in the regular record buffer.
388
389
  @param info          Reference to the context including record descriptors
390
391
  @retval
392
    0   Record successfully read.
393
  @retval
394
    -1   There is no record to be read anymore.
395
*/
396
static int rr_unpack_from_tempfile(READ_RECORD *info)
397
{
398
  if (my_b_read(info->io_cache, info->rec_buf, info->ref_length))
399
    return -1;
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
400
  Table *table= info->table;
1 by brian
clean slate
401
  (*table->sort.unpack)(table->sort.addon_field, info->rec_buf);
402
403
  return 0;
404
}
405
406
static int rr_from_pointers(READ_RECORD *info)
407
{
408
  int tmp;
481 by Brian Aker
Remove all of uchar.
409
  unsigned char *cache_pos;
1 by brian
clean slate
410
411
  for (;;)
412
  {
413
    if (info->cache_pos == info->cache_end)
414
      return -1;					/* End of file */
415
    cache_pos= info->cache_pos;
416
    info->cache_pos+= info->ref_length;
417
418
    if (!(tmp=info->file->rnd_pos(info->record,cache_pos)))
419
      break;
420
421
    /* The following is extremely unlikely to happen */
422
    if (tmp == HA_ERR_RECORD_DELETED ||
423
        (tmp == HA_ERR_KEY_NOT_FOUND && info->ignore_not_found_rows))
424
      continue;
425
    tmp= rr_handle_error(info, tmp);
426
    break;
427
  }
428
  return tmp;
429
}
430
431
/**
432
  Read a result set record from a buffer after sorting.
433
434
  The function first reads the next sorted record from the sort buffer.
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
435
  If a success it calls a callback function that unpacks
1 by brian
clean slate
436
  the fields values use in the result set from this buffer into their
437
  positions in the regular record buffer.
438
439
  @param info          Reference to the context including record descriptors
440
441
  @retval
442
    0   Record successfully read.
443
  @retval
444
    -1   There is no record to be read anymore.
445
*/
446
static int rr_unpack_from_buffer(READ_RECORD *info)
447
{
448
  if (info->cache_pos == info->cache_end)
449
    return -1;                      /* End of buffer */
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
450
  Table *table= info->table;
1 by brian
clean slate
451
  (*table->sort.unpack)(table->sort.addon_field, info->cache_pos);
452
  info->cache_pos+= info->ref_length;
453
454
  return 0;
455
}
456
1039.2.8 by Jay Pipes
Yet more indentation and style cleanup
457
/* cacheing of records from a database */
520.1.22 by Brian Aker
Second pass of thd cleanup
458
static int init_rr_cache(Session *session, READ_RECORD *info)
1 by brian
clean slate
459
{
482 by Brian Aker
Remove uint.
460
  uint32_t rec_cache_size;
1 by brian
clean slate
461
462
  info->struct_length= 3+MAX_REFLENGTH;
463
  info->reclength= ALIGN_SIZE(info->table->s->reclength+1);
464
  if (info->reclength < info->struct_length)
465
    info->reclength= ALIGN_SIZE(info->struct_length);
466
467
  info->error_offset= info->table->s->reclength;
520.1.22 by Brian Aker
Second pass of thd cleanup
468
  info->cache_records= (session->variables.read_rnd_buff_size /
1 by brian
clean slate
469
                        (info->reclength+info->struct_length));
470
  rec_cache_size= info->cache_records*info->reclength;
471
  info->rec_cache_size= info->cache_records*info->ref_length;
472
473
  // We have to allocate one more byte to use uint3korr (see comments for it)
474
  if (info->cache_records <= 2 ||
641.3.7 by Monty Taylor
More my_malloc removal.
475
      !(info->cache=(unsigned char*) malloc(rec_cache_size+info->cache_records*
476
					    info->struct_length+1)))
51.1.4 by Jay Pipes
Removed all DBUG_XXX content from records.cc. Builds/tests run fine. On to next file...
477
    return(1);
1 by brian
clean slate
478
#ifdef HAVE_purify
479
  // Avoid warnings in qsort
212.6.1 by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file.
480
  memset(info->cache, 0,
481
         rec_cache_size+info->cache_records* info->struct_length+1);
1 by brian
clean slate
482
#endif
483
  info->read_positions=info->cache+rec_cache_size;
484
  info->cache_pos=info->cache_end=info->cache;
51.1.4 by Jay Pipes
Removed all DBUG_XXX content from records.cc. Builds/tests run fine. On to next file...
485
  return(0);
1 by brian
clean slate
486
} /* init_rr_cache */
487
488
static int rr_from_cache(READ_RECORD *info)
489
{
482 by Brian Aker
Remove uint.
490
  register uint32_t i;
308 by Brian Aker
ulong conversion
491
  uint32_t length;
1 by brian
clean slate
492
  my_off_t rest_of_file;
206 by Brian Aker
Removed final uint dead types.
493
  int16_t error;
481 by Brian Aker
Remove all of uchar.
494
  unsigned char *position,*ref_position,*record_pos;
308 by Brian Aker
ulong conversion
495
  uint32_t record;
1 by brian
clean slate
496
497
  for (;;)
498
  {
499
    if (info->cache_pos != info->cache_end)
500
    {
501
      if (info->cache_pos[info->error_offset])
502
      {
1039.2.8 by Jay Pipes
Yet more indentation and style cleanup
503
        shortget(error,info->cache_pos);
504
        if (info->print_error)
505
          info->table->file->print_error(error,MYF(0));
1 by brian
clean slate
506
      }
507
      else
508
      {
1039.2.8 by Jay Pipes
Yet more indentation and style cleanup
509
        error=0;
510
        memcpy(info->record,info->cache_pos, (size_t) info->table->s->reclength);
1 by brian
clean slate
511
      }
512
      info->cache_pos+=info->reclength;
513
      return ((int) error);
514
    }
515
    length=info->rec_cache_size;
516
    rest_of_file=info->io_cache->end_of_file - my_b_tell(info->io_cache);
517
    if ((my_off_t) length > rest_of_file)
308 by Brian Aker
ulong conversion
518
      length= (uint32_t) rest_of_file;
1 by brian
clean slate
519
    if (!length || my_b_read(info->io_cache,info->cache,length))
520
    {
521
      return -1;			/* End of file */
522
    }
523
524
    length/=info->ref_length;
525
    position=info->cache;
526
    ref_position=info->read_positions;
527
    for (i=0 ; i < length ; i++,position+=info->ref_length)
528
    {
529
      memcpy(ref_position,position,(size_t) info->ref_length);
530
      ref_position+=MAX_REFLENGTH;
531
      int3store(ref_position,(long) i);
532
      ref_position+=3;
533
    }
534
    my_qsort(info->read_positions, length, info->struct_length,
535
             (qsort_cmp) rr_cmp);
536
537
    position=info->read_positions;
538
    for (i=0 ; i < length ; i++)
539
    {
540
      memcpy(info->ref_pos,position,(size_t) info->ref_length);
541
      position+=MAX_REFLENGTH;
542
      record=uint3korr(position);
543
      position+=3;
544
      record_pos=info->cache+record*info->reclength;
206 by Brian Aker
Removed final uint dead types.
545
      if ((error=(int16_t) info->file->rnd_pos(record_pos,info->ref_pos)))
1 by brian
clean slate
546
      {
1039.2.8 by Jay Pipes
Yet more indentation and style cleanup
547
        record_pos[info->error_offset]=1;
548
        shortstore(record_pos,error);
1 by brian
clean slate
549
      }
550
      else
1039.2.8 by Jay Pipes
Yet more indentation and style cleanup
551
        record_pos[info->error_offset]=0;
1 by brian
clean slate
552
    }
553
    info->cache_end=(info->cache_pos=info->cache)+length*info->reclength;
554
  }
555
} /* rr_from_cache */
556
481 by Brian Aker
Remove all of uchar.
557
static int rr_cmp(unsigned char *a,unsigned char *b)
1 by brian
clean slate
558
{
559
  if (a[0] != b[0])
560
    return (int) a[0] - (int) b[0];
561
  if (a[1] != b[1])
562
    return (int) a[1] - (int) b[1];
563
  if (a[2] != b[2])
564
    return (int) a[2] - (int) b[2];
565
#if MAX_REFLENGTH == 4
566
  return (int) a[3] - (int) b[3];
567
#else
568
  if (a[3] != b[3])
569
    return (int) a[3] - (int) b[3];
570
  if (a[4] != b[4])
571
    return (int) a[4] - (int) b[4];
572
  if (a[5] != b[5])
573
    return (int) a[1] - (int) b[5];
574
  if (a[6] != b[6])
575
    return (int) a[6] - (int) b[6];
576
  return (int) a[7] - (int) b[7];
577
#endif
578
}