~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
/* Functions to handle keys and fields in forms */
18
1241.9.36 by Monty Taylor
ZOMG. I deleted drizzled/server_includes.h.
19
#include "config.h"
934.2.21 by Jay Pipes
Move Key stuff into key.cc and out of session.cc
20
#include "drizzled/table.h"
21
#include "drizzled/key.h"
22
#include "drizzled/field/blob.h"
1 by brian
clean slate
23
656.1.1 by Monty Taylor
OOOh doggie. Got rid of my_alloca.
24
#include <string>
25
1067.4.4 by Nathan Williams
The rest of the files in the drizzled directory were purged of the cmin macro and replace with std::min (except for the definition in globals.h and 1 usage in stacktrace.cc).
26
#include <algorithm>
27
656.1.1 by Monty Taylor
OOOh doggie. Got rid of my_alloca.
28
using namespace std;
29
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
30
namespace drizzled
31
{
32
1 by brian
clean slate
33
/*
34
  Search after a key that starts with 'field'
35
36
  SYNOPSIS
37
    find_ref_key()
38
    key			First key to check
39
    key_count		How many keys to check
40
    record		Start of record
41
    field		Field to search after
42
    key_length		On partial match, contains length of fields before
43
			field
44
    keypart             key part # of a field
45
46
  NOTES
47
   Used when calculating key for NEXT_NUMBER
48
49
  IMPLEMENTATION
50
    If no key starts with field test if field is part of some key. If we find
51
    one, then return first key and set key_length to the number of bytes
52
    preceding 'field'.
53
54
  RETURN
55
   -1  field is not part of the key
56
   #   Key part for key matching key.
57
       key_length is set to length of key before (not including) field
58
*/
59
482 by Brian Aker
Remove uint.
60
int find_ref_key(KEY *key, uint32_t key_count, unsigned char *record, Field *field,
61
                 uint32_t *key_length, uint32_t *keypart)
1 by brian
clean slate
62
{
63
  register int i;
64
  register KEY *key_info;
482 by Brian Aker
Remove uint.
65
  uint32_t fieldpos;
1 by brian
clean slate
66
67
  fieldpos= field->offset(record);
68
69
  /* Test if some key starts as fieldpos */
70
  for (i= 0, key_info= key ;
71
       i < (int) key_count ;
72
       i++, key_info++)
73
  {
74
    if (key_info->key_part[0].offset == fieldpos)
75
    {                                  		/* Found key. Calc keylength */
76
      *key_length= *keypart= 0;
77
      return i;                                 /* Use this key */
78
    }
79
  }
80
81
  /* Test if some key contains fieldpos */
82
  for (i= 0, key_info= key;
83
       i < (int) key_count ;
84
       i++, key_info++)
85
  {
482 by Brian Aker
Remove uint.
86
    uint32_t j;
1 by brian
clean slate
87
    KEY_PART_INFO *key_part;
88
    *key_length=0;
89
    for (j=0, key_part=key_info->key_part ;
90
	 j < key_info->key_parts ;
91
	 j++, key_part++)
92
    {
93
      if (key_part->offset == fieldpos)
94
      {
95
        *keypart= j;
96
        return i;                               /* Use this key */
97
      }
98
      *key_length+= key_part->store_length;
99
    }
100
  }
101
  return(-1);					/* No key is ok */
102
}
103
104
481 by Brian Aker
Remove all of uchar.
105
void key_copy(unsigned char *to_key, unsigned char *from_record, KEY *key_info,
287.3.8 by Monty Taylor
Oy. Replaced max and min macros with std::max and std::min so that we get
106
              unsigned int key_length)
1 by brian
clean slate
107
{
482 by Brian Aker
Remove uint.
108
  uint32_t length;
1 by brian
clean slate
109
  KEY_PART_INFO *key_part;
110
111
  if (key_length == 0)
112
    key_length= key_info->key_length;
113
  for (key_part= key_info->key_part; (int) key_length > 0; key_part++)
114
  {
115
    if (key_part->null_bit)
116
    {
117
      *to_key++= test(from_record[key_part->null_offset] &
118
		   key_part->null_bit);
119
      key_length--;
120
    }
121
    if (key_part->key_part_flag & HA_BLOB_PART ||
122
        key_part->key_part_flag & HA_VAR_LENGTH_PART)
123
    {
124
      key_length-= HA_KEY_BLOB_LENGTH;
1067.4.4 by Nathan Williams
The rest of the files in the drizzled directory were purged of the cmin macro and replace with std::min (except for the definition in globals.h and 1 usage in stacktrace.cc).
125
      length= min((uint16_t)key_length, key_part->length);
1055.2.5 by Jay Pipes
Removal of dead Field::image_type and st_key_part::image_type member variables. Legacy from geometry MyISAM types...
126
      key_part->field->get_key_image(to_key, length);
1 by brian
clean slate
127
      to_key+= HA_KEY_BLOB_LENGTH;
128
    }
129
    else
130
    {
1067.4.4 by Nathan Williams
The rest of the files in the drizzled directory were purged of the cmin macro and replace with std::min (except for the definition in globals.h and 1 usage in stacktrace.cc).
131
      length= min((uint16_t)key_length, key_part->length);
1 by brian
clean slate
132
      Field *field= key_part->field;
264.2.6 by Andrey Hristov
Constify the usage of CHARSET_INFO almost to the last place in the code.
133
      const CHARSET_INFO * const cs= field->charset();
1055.2.5 by Jay Pipes
Removal of dead Field::image_type and st_key_part::image_type member variables. Legacy from geometry MyISAM types...
134
      uint32_t bytes= field->get_key_image(to_key, length);
1 by brian
clean slate
135
      if (bytes < length)
136
        cs->cset->fill(cs, (char*) to_key + bytes, length - bytes, ' ');
137
    }
138
    to_key+= length;
139
    key_length-= length;
140
  }
141
}
142
143
144
/**
145
  Zero the null components of key tuple.
146
*/
147
481 by Brian Aker
Remove all of uchar.
148
void key_zero_nulls(unsigned char *tuple, KEY *key_info)
1 by brian
clean slate
149
{
150
  KEY_PART_INFO *key_part= key_info->key_part;
151
  KEY_PART_INFO *key_part_end= key_part + key_info->key_parts;
152
  for (; key_part != key_part_end; key_part++)
153
  {
154
    if (key_part->null_bit && *tuple)
212.6.1 by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file.
155
      memset(tuple+1, 0, key_part->store_length-1);
1 by brian
clean slate
156
    tuple+= key_part->store_length;
157
  }
158
}
159
160
161
/*
162
  Restore a key from some buffer to record.
163
164
    This function converts a key into record format. It can be used in cases
165
    when we want to return a key as a result row.
166
167
  @param to_record   record buffer where the key will be restored to
168
  @param from_key    buffer that contains a key
169
  @param key_info    descriptor of the index
170
  @param key_length  specifies length of all keyparts that will be restored
171
*/
172
481 by Brian Aker
Remove all of uchar.
173
void key_restore(unsigned char *to_record, unsigned char *from_key, KEY *key_info,
287.3.8 by Monty Taylor
Oy. Replaced max and min macros with std::max and std::min so that we get
174
                 uint16_t key_length)
1 by brian
clean slate
175
{
482 by Brian Aker
Remove uint.
176
  uint32_t length;
1 by brian
clean slate
177
  KEY_PART_INFO *key_part;
178
179
  if (key_length == 0)
180
  {
181
    key_length= key_info->key_length;
182
  }
183
  for (key_part= key_info->key_part ; (int) key_length > 0 ; key_part++)
184
  {
481 by Brian Aker
Remove all of uchar.
185
    unsigned char used_uneven_bits= 0;
1 by brian
clean slate
186
    if (key_part->null_bit)
187
    {
188
      if (*from_key++)
189
	to_record[key_part->null_offset]|= key_part->null_bit;
190
      else
191
	to_record[key_part->null_offset]&= ~key_part->null_bit;
192
      key_length--;
193
    }
194
    if (key_part->key_part_flag & HA_BLOB_PART)
195
    {
196
      /*
197
        This in fact never happens, as we have only partial BLOB
198
        keys yet anyway, so it's difficult to find any sence to
199
        restore the part of a record.
200
        Maybe this branch is to be removed, but now we
201
        have to ignore GCov compaining.
1089.1.3 by Brian Aker
Fix protobuf to release memory. Add in assert() for wrong column usage. Fix
202
203
        This may make more sense once we push down block lengths to the engine (aka partial retrieval).
1 by brian
clean slate
204
      */
482 by Brian Aker
Remove uint.
205
      uint32_t blob_length= uint2korr(from_key);
1 by brian
clean slate
206
      Field_blob *field= (Field_blob*) key_part->field;
1089.1.3 by Brian Aker
Fix protobuf to release memory. Add in assert() for wrong column usage. Fix
207
208
      field->setReadSet();
1 by brian
clean slate
209
      from_key+= HA_KEY_BLOB_LENGTH;
210
      key_length-= HA_KEY_BLOB_LENGTH;
211
      field->set_ptr_offset(to_record - field->table->record[0],
212
                            (ulong) blob_length, from_key);
213
      length= key_part->length;
214
    }
215
    else if (key_part->key_part_flag & HA_VAR_LENGTH_PART)
216
    {
217
      Field *field= key_part->field;
1122.2.12 by Monty Taylor
Removed the silly my_ptrdiff_t typedef.
218
      ptrdiff_t ptrdiff= to_record - field->table->record[0];
1089.1.3 by Brian Aker
Fix protobuf to release memory. Add in assert() for wrong column usage. Fix
219
220
      field->setReadSet();
221
      field->setWriteSet();
1 by brian
clean slate
222
      field->move_field_offset(ptrdiff);
223
      key_length-= HA_KEY_BLOB_LENGTH;
1067.4.4 by Nathan Williams
The rest of the files in the drizzled directory were purged of the cmin macro and replace with std::min (except for the definition in globals.h and 1 usage in stacktrace.cc).
224
      length= min(key_length, key_part->length);
1 by brian
clean slate
225
      field->set_key_image(from_key, length);
226
      from_key+= HA_KEY_BLOB_LENGTH;
227
      field->move_field_offset(-ptrdiff);
228
    }
229
    else
230
    {
1067.4.4 by Nathan Williams
The rest of the files in the drizzled directory were purged of the cmin macro and replace with std::min (except for the definition in globals.h and 1 usage in stacktrace.cc).
231
      length= min(key_length, key_part->length);
1 by brian
clean slate
232
      /* skip the byte with 'uneven' bits, if used */
233
      memcpy(to_record + key_part->offset, from_key + used_uneven_bits
234
             , (size_t) length - used_uneven_bits);
235
    }
236
    from_key+= length;
237
    key_length-= length;
238
  }
239
}
240
241
242
/**
243
  Compare if a key has changed.
244
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
245
  @param table		Table
1 by brian
clean slate
246
  @param key		key to compare to row
247
  @param idx		Index used
248
  @param key_length	Length of key
249
250
  @note
251
    In theory we could just call field->cmp() for all field types,
252
    but as we are only interested if a key has changed (not if the key is
253
    larger or smaller than the previous value) we can do things a bit
254
    faster by using memcmp() instead.
255
256
  @retval
257
    0	If key is equal
258
  @retval
259
    1	Key has changed
260
*/
261
482 by Brian Aker
Remove uint.
262
bool key_cmp_if_same(Table *table,const unsigned char *key,uint32_t idx,uint32_t key_length)
1 by brian
clean slate
263
{
482 by Brian Aker
Remove uint.
264
  uint32_t store_length;
1 by brian
clean slate
265
  KEY_PART_INFO *key_part;
481 by Brian Aker
Remove all of uchar.
266
  const unsigned char *key_end= key + key_length;;
1 by brian
clean slate
267
268
  for (key_part=table->key_info[idx].key_part;
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
269
       key < key_end ;
1 by brian
clean slate
270
       key_part++, key+= store_length)
271
  {
482 by Brian Aker
Remove uint.
272
    uint32_t length;
1 by brian
clean slate
273
    store_length= key_part->store_length;
274
275
    if (key_part->null_bit)
276
    {
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
277
      if (*key != test(table->record[0][key_part->null_offset] &
1 by brian
clean slate
278
		       key_part->null_bit))
279
	return 1;
280
      if (*key)
281
	continue;
282
      key++;
283
      store_length--;
284
    }
285
    if (key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART |
286
                                   HA_BIT_PART))
287
    {
288
      if (key_part->field->key_cmp(key, key_part->length))
289
	return 1;
290
      continue;
291
    }
1067.4.4 by Nathan Williams
The rest of the files in the drizzled directory were purged of the cmin macro and replace with std::min (except for the definition in globals.h and 1 usage in stacktrace.cc).
292
    length= min((uint32_t) (key_end-key), store_length);
1119.9.5 by Jay Pipes
Removes FIELDFLAG_NUMBER, f_is_num() and f_is_alpha() macros. Buh bye.
293
    if (key_part->field->type() == DRIZZLE_TYPE_VARCHAR)
1 by brian
clean slate
294
    {
264.2.6 by Andrey Hristov
Constify the usage of CHARSET_INFO almost to the last place in the code.
295
      const CHARSET_INFO * const cs= key_part->field->charset();
482 by Brian Aker
Remove uint.
296
      uint32_t char_length= key_part->length / cs->mbmaxlen;
481 by Brian Aker
Remove all of uchar.
297
      const unsigned char *pos= table->record[0] + key_part->offset;
1 by brian
clean slate
298
      if (length > char_length)
299
      {
300
        char_length= my_charpos(cs, pos, pos + length, char_length);
301
        set_if_smaller(char_length, length);
302
      }
303
      if (cs->coll->strnncollsp(cs,
481 by Brian Aker
Remove all of uchar.
304
                                (const unsigned char*) key, length,
305
                                (const unsigned char*) pos, char_length, 0))
1 by brian
clean slate
306
        return 1;
307
      continue;
308
    }
309
    if (memcmp(key,table->record[0]+key_part->offset,length))
310
      return 1;
311
  }
312
  return 0;
313
}
314
315
/*
316
  unpack key-fields from record to some buffer.
317
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
318
  This is used mainly to get a good error message.  We temporary
1 by brian
clean slate
319
  change the column bitmap so that all columns are readable.
320
321
  @param
322
     to		Store value here in an easy to read form
323
  @param
324
     table	Table to use
325
  @param
326
     idx	Key number
327
*/
328
1216.1.1 by Brian Aker
Move print_error up to Engine.
329
void key_unpack(String *to, Table *table, uint32_t idx)
1 by brian
clean slate
330
{
331
  KEY_PART_INFO *key_part,*key_part_end;
332
  Field *field;
333
  String tmp;
334
335
  to->length(0);
336
  for (key_part=table->key_info[idx].key_part,key_part_end=key_part+
337
	 table->key_info[idx].key_parts ;
338
       key_part < key_part_end;
339
       key_part++)
340
  {
341
    if (to->length())
342
      to->append('-');
343
    if (key_part->null_bit)
344
    {
345
      if (table->record[0][key_part->null_offset] & key_part->null_bit)
346
      {
347
	to->append(STRING_WITH_LEN("NULL"));
348
	continue;
349
      }
350
    }
1089.1.3 by Brian Aker
Fix protobuf to release memory. Add in assert() for wrong column usage. Fix
351
    if ((field= key_part->field))
1 by brian
clean slate
352
    {
264.2.6 by Andrey Hristov
Constify the usage of CHARSET_INFO almost to the last place in the code.
353
      const CHARSET_INFO * const cs= field->charset();
1089.1.3 by Brian Aker
Fix protobuf to release memory. Add in assert() for wrong column usage. Fix
354
      field->setReadSet();
1 by brian
clean slate
355
      field->val_str(&tmp);
356
      if (cs->mbmaxlen > 1 &&
357
          table->field[key_part->fieldnr - 1]->field_length !=
358
          key_part->length)
359
      {
360
        /*
361
          Prefix key, multi-byte charset.
362
          For the columns of type CHAR(N), the above val_str()
363
          call will return exactly "key_part->length" bytes,
364
          which can break a multi-byte characters in the middle.
365
          Align, returning not more than "char_length" characters.
366
        */
482 by Brian Aker
Remove uint.
367
        uint32_t charpos, char_length= key_part->length / cs->mbmaxlen;
813.1.3 by Jay Pipes
Incorrectly passing str.ptr() instead of str.c_ptr() to my_charpos() in key.cc:key_unpack(). This resulted in duplicate key error messages containing random characters due to a bad offset, and would show up as random failure in the myisam.test case when running make test but not ./dtr myisam.
368
        if ((charpos= my_charpos(cs, tmp.c_ptr(),
369
                                 tmp.c_ptr() + tmp.length(),
1 by brian
clean slate
370
                                 char_length)) < key_part->length)
371
          tmp.length(charpos);
372
      }
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
373
1 by brian
clean slate
374
      if (key_part->length < field->pack_length())
1067.4.4 by Nathan Williams
The rest of the files in the drizzled directory were purged of the cmin macro and replace with std::min (except for the definition in globals.h and 1 usage in stacktrace.cc).
375
        tmp.length(min(tmp.length(),(uint32_t)key_part->length));
1 by brian
clean slate
376
      to->append(tmp);
377
    }
378
    else
379
      to->append(STRING_WITH_LEN("???"));
380
  }
381
}
382
383
384
/*
385
  Check if key uses field that is marked in passed field bitmap.
386
387
  SYNOPSIS
388
    is_key_used()
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
389
      table   Table object with which keys and fields are associated.
1 by brian
clean slate
390
      idx     Key to be checked.
391
      fields  Bitmap of fields to be checked.
392
393
  NOTE
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
394
    This function uses Table::tmp_set bitmap so the caller should care
1 by brian
clean slate
395
    about saving/restoring its state if it also uses this bitmap.
396
397
  RETURN VALUE
398
    TRUE   Key uses field from bitmap
399
    FALSE  Otherwise
400
*/
401
1103.6.2 by Padraig O'Sullivan
Removing references to MY_BITMAP throughout the code base and updating calls
402
bool is_key_used(Table *table, uint32_t idx, const MyBitmap *fields)
1 by brian
clean slate
403
{
1103.6.2 by Padraig O'Sullivan
Removing references to MY_BITMAP throughout the code base and updating calls
404
  table->tmp_set.clearAll();
1 by brian
clean slate
405
  table->mark_columns_used_by_index_no_reset(idx, &table->tmp_set);
1005.2.3 by Monty Taylor
Further reversion of P.
406
  if (bitmap_is_overlapping(&table->tmp_set, fields))
1 by brian
clean slate
407
    return 1;
408
409
  /*
410
    If table handler has primary key as part of the index, check that primary
411
    key is not updated
412
  */
413
  if (idx != table->s->primary_key && table->s->primary_key < MAX_KEY &&
1233.1.4 by Brian Aker
Added:
414
      (table->cursor->getEngine()->check_flag(HTON_BIT_PRIMARY_KEY_IN_READ_INDEX)))
1 by brian
clean slate
415
    return is_key_used(table, table->s->primary_key, fields);
416
  return 0;
417
}
418
419
420
/**
421
  Compare key in row to a given key.
422
423
  @param key_part		Key part handler
424
  @param key			Key to compare to value in table->record[0]
425
  @param key_length		length of 'key'
426
427
  @return
428
    The return value is SIGN(key_in_row - range_key):
429
    -   0		Key is equal to range or 'range' == 0 (no range)
430
    -  -1		Key is less than range
431
    -   1		Key is larger than range
432
*/
433
482 by Brian Aker
Remove uint.
434
int key_cmp(KEY_PART_INFO *key_part, const unsigned char *key, uint32_t key_length)
1 by brian
clean slate
435
{
482 by Brian Aker
Remove uint.
436
  uint32_t store_length;
1 by brian
clean slate
437
481 by Brian Aker
Remove all of uchar.
438
  for (const unsigned char *end=key + key_length;
1 by brian
clean slate
439
       key < end;
440
       key+= store_length, key_part++)
441
  {
442
    int cmp;
443
    store_length= key_part->store_length;
444
    if (key_part->null_bit)
445
    {
446
      /* This key part allows null values; NULL is lower than everything */
447
      register bool field_is_null= key_part->field->is_null();
448
      if (*key)                                 // If range key is null
449
      {
450
	/* the range is expecting a null value */
451
	if (!field_is_null)
452
	  return 1;                             // Found key is > range
453
        /* null -- exact match, go to next key part */
454
	continue;
455
      }
456
      else if (field_is_null)
457
	return -1;                              // NULL is less than any value
458
      key++;					// Skip null byte
459
      store_length--;
460
    }
461
    if ((cmp=key_part->field->key_cmp(key, key_part->length)) < 0)
462
      return -1;
463
    if (cmp > 0)
464
      return 1;
465
  }
466
  return 0;                                     // Keys are equal
467
}
468
469
470
/*
471
  Compare two records in index order
472
  SYNOPSIS
473
    key_rec_cmp()
474
    key                         Index information
475
    rec0                        Pointer to table->record[0]
476
    first_rec                   Pointer to record compare with
477
    second_rec                  Pointer to record compare against first_rec
478
479
  DESCRIPTION
480
    This method is set-up such that it can be called directly from the
481
    priority queue and it is attempted to be optimised as much as possible
482
    since this will be called O(N * log N) times while performing a merge
483
    sort in various places in the code.
484
485
    We retrieve the pointer to table->record[0] using the fact that key_parts
486
    have an offset making it possible to calculate the start of the record.
487
    We need to get the diff to the compared record since none of the records
488
    being compared are stored in table->record[0].
489
490
    We first check for NULL values, if there are no NULL values we use
491
    a compare method that gets two field pointers and a max length
492
    and return the result of the comparison.
493
*/
494
481 by Brian Aker
Remove all of uchar.
495
int key_rec_cmp(void *key, unsigned char *first_rec, unsigned char *second_rec)
1 by brian
clean slate
496
{
497
  KEY *key_info= (KEY*)key;
482 by Brian Aker
Remove uint.
498
  uint32_t key_parts= key_info->key_parts, i= 0;
1 by brian
clean slate
499
  KEY_PART_INFO *key_part= key_info->key_part;
481 by Brian Aker
Remove all of uchar.
500
  unsigned char *rec0= key_part->field->ptr - key_part->offset;
1122.2.12 by Monty Taylor
Removed the silly my_ptrdiff_t typedef.
501
  ptrdiff_t first_diff= first_rec - rec0, sec_diff= second_rec - rec0;
1 by brian
clean slate
502
  int result= 0;
503
504
  do
505
  {
506
    Field *field= key_part->field;
507
508
    if (key_part->null_bit)
509
    {
510
      /* The key_part can contain NULL values */
511
      bool first_is_null= field->is_null_in_record_with_offset(first_diff);
512
      bool sec_is_null= field->is_null_in_record_with_offset(sec_diff);
513
      /*
514
        NULL is smaller then everything so if first is NULL and the other
515
        not then we know that we should return -1 and for the opposite
516
        we should return +1. If both are NULL then we call it equality
517
        although it is a strange form of equality, we have equally little
518
        information of the real value.
519
      */
520
      if (!first_is_null)
521
      {
522
        if (!sec_is_null)
523
          ; /* Fall through, no NULL fields */
524
        else
525
        {
51.1.6 by Jay Pipes
Final removal of DBUG_ statements. Build/tests pass.
526
          return(1);
1 by brian
clean slate
527
        }
528
      }
529
      else if (!sec_is_null)
530
      {
51.1.6 by Jay Pipes
Final removal of DBUG_ statements. Build/tests pass.
531
        return(-1);
1 by brian
clean slate
532
      }
533
      else
534
        goto next_loop; /* Both were NULL */
535
    }
536
    /*
537
      No null values in the fields
538
      We use the virtual method cmp_max with a max length parameter.
539
      For most field types this translates into a cmp without
540
      max length. The exceptions are the BLOB and VARCHAR field types
541
      that take the max length into account.
542
    */
543
    result= field->cmp_max(field->ptr+first_diff, field->ptr+sec_diff,
544
                           key_part->length);
545
next_loop:
546
    key_part++;
547
  } while (!result && ++i < key_parts);
51.1.6 by Jay Pipes
Final removal of DBUG_ statements. Build/tests pass.
548
  return(result);
1 by brian
clean slate
549
}
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
550
551
} /* namespace drizzled */