~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2002-2006 MySQL AB
2
   
3
   This library is free software; you can redistribute it and/or
4
   modify it under the terms of the GNU Library General Public
5
   License as published by the Free Software Foundation; version 2
6
   of the License.
7
   
8
   This library is distributed in the hope that it will be useful,
9
   but WITHOUT ANY WARRANTY; without even the implied warranty of
10
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
   Library General Public License for more details.
12
13
   You should have received a copy of the GNU Library General Public
14
   License along with this library; if not, write to the Free
15
   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
16
   MA 02111-1307, USA */
17
18
#include <my_global.h>
19
#include <m_ctype.h>
20
#include <my_base.h>
21
#include <my_handler.h>
22
#include <my_sys.h>
23
24
#include "my_handler_errors.h"
25
26
int ha_compare_text(CHARSET_INFO *charset_info, uchar *a, uint a_length,
27
		    uchar *b, uint b_length, my_bool part_key,
28
		    my_bool skip_end_space)
29
{
30
  if (!part_key)
31
    return charset_info->coll->strnncollsp(charset_info, a, a_length,
32
                                           b, b_length, (my_bool)!skip_end_space);
33
  return charset_info->coll->strnncoll(charset_info, a, a_length,
34
                                       b, b_length, part_key);
35
}
36
37
38
static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length,
39
                       my_bool part_key, my_bool skip_end_space)
40
{
41
  uint length= min(a_length,b_length);
42
  uchar *end= a+ length;
43
  int flag;
44
45
  while (a < end)
46
    if ((flag= (int) *a++ - (int) *b++))
47
      return flag;
48
  if (part_key && b_length < a_length)
49
    return 0;
50
  if (skip_end_space && a_length != b_length)
51
  {
52
    int swap= 1;
53
    /*
54
      We are using space compression. We have to check if longer key
55
      has next character < ' ', in which case it's less than the shorter
56
      key that has an implicite space afterwards.
57
58
      This code is identical to the one in
59
      strings/ctype-simple.c:my_strnncollsp_simple
60
    */
61
    if (a_length < b_length)
62
    {
63
      /* put shorter key in a */
64
      a_length= b_length;
65
      a= b;
66
      swap= -1;					/* swap sign of result */
67
    }
68
    for (end= a + a_length-length; a < end ; a++)
69
    {
70
      if (*a != ' ')
71
	return (*a < ' ') ? -swap : swap;
72
    }
73
    return 0;
74
  }
75
  return (int) (a_length-b_length);
76
}
77
78
79
/*
80
  Compare two keys
81
82
  SYNOPSIS
83
    ha_key_cmp()
84
    keyseg	Array of key segments of key to compare
85
    a		First key to compare, in format from _mi_pack_key()
86
		This is normally key specified by user
87
    b		Second key to compare.  This is always from a row
88
    key_length	Length of key to compare.  This can be shorter than
89
		a to just compare sub keys
90
    next_flag	How keys should be compared
91
		If bit SEARCH_FIND is not set the keys includes the row
92
		position and this should also be compared
93
    diff_pos    OUT Number of first keypart where values differ, counting 
94
                from one.
95
    diff_pos[1] OUT  (b + diff_pos[1]) points to first value in tuple b
96
                      that is different from corresponding value in tuple a.
97
  
98
  EXAMPLES 
99
   Example1: if the function is called for tuples
100
     ('aaa','bbb') and ('eee','fff'), then
101
     diff_pos[0] = 1 (as 'aaa' != 'eee')
102
     diff_pos[1] = 0 (offset from beggining of tuple b to 'eee' keypart).
103
104
   Example2: if the index function is called for tuples
105
     ('aaa','bbb') and ('aaa','fff'),
106
     diff_pos[0] = 2 (as 'aaa' != 'eee')
107
     diff_pos[1] = 3 (offset from beggining of tuple b to 'fff' keypart,
108
                      here we assume that first key part is CHAR(3) NOT NULL)
109
110
  NOTES
111
    Number-keys can't be splited
112
113
  RETURN VALUES
114
    <0	If a < b
115
    0	If a == b
116
    >0	If a > b
117
*/
118
119
#define FCMP(A,B) ((int) (A) - (int) (B))
120
121
int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
122
	       register uchar *b, uint key_length, uint nextflag,
123
	       uint *diff_pos)
124
{
125
  int flag;
126
  int16 s_1,s_2;
127
  int32 l_1,l_2;
128
  uint32 u_1,u_2;
129
  float f_1,f_2;
130
  double d_1,d_2;
131
  uint next_key_length;
132
  uchar *orig_b= b;
133
134
  *diff_pos=0;
135
  for ( ; (int) key_length >0 ; key_length=next_key_length, keyseg++)
136
  {
137
    uchar *end;
138
    uint piks=! (keyseg->flag & HA_NO_SORT);
139
    (*diff_pos)++;
140
    diff_pos[1]= (uint)(b - orig_b);
141
142
    /* Handle NULL part */
143
    if (keyseg->null_bit)
144
    {
145
      key_length--;
146
      if (*a != *b && piks)
147
      {
148
        flag = (int) *a - (int) *b;
149
        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
150
      }
151
      b++;
152
      if (!*a++)                                /* If key was NULL */
153
      {
154
        if (nextflag == (SEARCH_FIND | SEARCH_UPDATE))
155
          nextflag=SEARCH_SAME;                 /* Allow duplicate keys */
156
  	else if (nextflag & SEARCH_NULL_ARE_NOT_EQUAL)
157
	{
158
	  /*
159
	    This is only used from mi_check() to calculate cardinality.
160
	    It can't be used when searching for a key as this would cause
161
	    compare of (a,b) and (b,a) to return the same value.
162
	  */
163
	  return -1;
164
	}
165
        next_key_length=key_length;
166
        continue;                               /* To next key part */
167
      }
168
    }
169
    end= a+ min(keyseg->length,key_length);
170
    next_key_length=key_length-keyseg->length;
171
172
    switch ((enum ha_base_keytype) keyseg->type) {
173
    case HA_KEYTYPE_TEXT:                       /* Ascii; Key is converted */
174
      if (keyseg->flag & HA_SPACE_PACK)
175
      {
176
        int a_length,b_length,pack_length;
177
        get_key_length(a_length,a);
178
        get_key_pack_length(b_length,pack_length,b);
179
        next_key_length=key_length-b_length-pack_length;
180
181
        if (piks &&
182
            (flag=ha_compare_text(keyseg->charset,a,a_length,b,b_length,
183
				  (my_bool) ((nextflag & SEARCH_PREFIX) &&
184
					     next_key_length <= 0),
185
				  (my_bool)!(nextflag & SEARCH_PREFIX))))
186
          return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
187
        a+=a_length;
188
        b+=b_length;
189
        break;
190
      }
191
      else
192
      {
193
	uint length=(uint) (end-a), a_length=length, b_length=length;
194
        if (piks &&
195
            (flag= ha_compare_text(keyseg->charset, a, a_length, b, b_length,
196
				   (my_bool) ((nextflag & SEARCH_PREFIX) &&
197
					      next_key_length <= 0),
198
				   (my_bool)!(nextflag & SEARCH_PREFIX))))
199
          return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
200
        a=end;
201
        b+=length;
202
      }
203
      break;
204
    case HA_KEYTYPE_BINARY:
205
    case HA_KEYTYPE_BIT:
206
      if (keyseg->flag & HA_SPACE_PACK)
207
      {
208
        int a_length,b_length,pack_length;
209
        get_key_length(a_length,a);
210
        get_key_pack_length(b_length,pack_length,b);
211
        next_key_length=key_length-b_length-pack_length;
212
213
        if (piks &&
214
	    (flag=compare_bin(a,a_length,b,b_length,
215
                              (my_bool) ((nextflag & SEARCH_PREFIX) &&
216
                                         next_key_length <= 0),1)))
217
          return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
218
        a+=a_length;
219
        b+=b_length;
220
        break;
221
      }
222
      else
223
      {
224
        uint length=keyseg->length;
225
        if (piks &&
226
	    (flag=compare_bin(a,length,b,length,
227
                              (my_bool) ((nextflag & SEARCH_PREFIX) &&
228
                                         next_key_length <= 0),0)))
229
          return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
230
        a+=length;
231
        b+=length;
232
      }
233
      break;
234
    case HA_KEYTYPE_VARTEXT1:
235
    case HA_KEYTYPE_VARTEXT2:
236
      {
237
        int a_length,b_length,pack_length;
238
        get_key_length(a_length,a);
239
        get_key_pack_length(b_length,pack_length,b);
240
        next_key_length=key_length-b_length-pack_length;
241
242
        if (piks &&
243
	    (flag= ha_compare_text(keyseg->charset,a,a_length,b,b_length,
244
                                   (my_bool) ((nextflag & SEARCH_PREFIX) &&
245
                                              next_key_length <= 0),
246
				   (my_bool) ((nextflag & (SEARCH_FIND |
247
							   SEARCH_UPDATE)) ==
248
					      SEARCH_FIND &&
249
                                              ! (keyseg->flag &
250
                                                 HA_END_SPACE_ARE_EQUAL)))))
251
          return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
252
        a+= a_length;
253
        b+= b_length;
254
        break;
255
      }
256
      break;
257
    case HA_KEYTYPE_VARBINARY1:
258
    case HA_KEYTYPE_VARBINARY2:
259
      {
260
        int a_length,b_length,pack_length;
261
        get_key_length(a_length,a);
262
        get_key_pack_length(b_length,pack_length,b);
263
        next_key_length=key_length-b_length-pack_length;
264
265
        if (piks &&
266
	    (flag=compare_bin(a,a_length,b,b_length,
267
                              (my_bool) ((nextflag & SEARCH_PREFIX) &&
268
                                         next_key_length <= 0), 0)))
269
          return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
270
        a+=a_length;
271
        b+=b_length;
272
        break;
273
      }
274
      break;
275
    case HA_KEYTYPE_INT8:
276
    {
277
      int i_1= (int) *((signed char*) a);
278
      int i_2= (int) *((signed char*) b);
279
      if (piks && (flag = CMP_NUM(i_1,i_2)))
280
        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
281
      a= end;
282
      b++;
283
      break;
284
    }
285
    case HA_KEYTYPE_SHORT_INT:
286
      s_1= mi_sint2korr(a);
287
      s_2= mi_sint2korr(b);
288
      if (piks && (flag = CMP_NUM(s_1,s_2)))
289
        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
290
      a=  end;
291
      b+= 2; /* sizeof(short int); */
292
      break;
293
    case HA_KEYTYPE_USHORT_INT:
294
      {
295
        uint16 us_1,us_2;
296
        us_1= mi_sint2korr(a);
297
        us_2= mi_sint2korr(b);
298
        if (piks && (flag = CMP_NUM(us_1,us_2)))
299
          return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
300
        a=  end;
301
        b+=2; /* sizeof(short int); */
302
        break;
303
      }
304
    case HA_KEYTYPE_LONG_INT:
305
      l_1= mi_sint4korr(a);
306
      l_2= mi_sint4korr(b);
307
      if (piks && (flag = CMP_NUM(l_1,l_2)))
308
        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
309
      a=  end;
310
      b+= 4; /* sizeof(long int); */
311
      break;
312
    case HA_KEYTYPE_ULONG_INT:
313
      u_1= mi_sint4korr(a);
314
      u_2= mi_sint4korr(b);
315
      if (piks && (flag = CMP_NUM(u_1,u_2)))
316
        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
317
      a=  end;
318
      b+= 4; /* sizeof(long int); */
319
      break;
320
    case HA_KEYTYPE_INT24:
321
      l_1=mi_sint3korr(a);
322
      l_2=mi_sint3korr(b);
323
      if (piks && (flag = CMP_NUM(l_1,l_2)))
324
        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
325
      a=  end;
326
      b+= 3;
327
      break;
328
    case HA_KEYTYPE_UINT24:
329
      l_1=mi_uint3korr(a);
330
      l_2=mi_uint3korr(b);
331
      if (piks && (flag = CMP_NUM(l_1,l_2)))
332
        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
333
      a=  end;
334
      b+= 3;
335
      break;
336
    case HA_KEYTYPE_FLOAT:
337
      mi_float4get(f_1,a);
338
      mi_float4get(f_2,b);
339
      /*
340
        The following may give a compiler warning about floating point
341
        comparison not being safe, but this is ok in this context as
342
        we are bascily doing sorting
343
      */
344
      if (piks && (flag = CMP_NUM(f_1,f_2)))
345
        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
346
      a=  end;
347
      b+= 4; /* sizeof(float); */
348
      break;
349
    case HA_KEYTYPE_DOUBLE:
350
      mi_float8get(d_1,a);
351
      mi_float8get(d_2,b);
352
      /*
353
        The following may give a compiler warning about floating point
354
        comparison not being safe, but this is ok in this context as
355
        we are bascily doing sorting
356
      */
357
      if (piks && (flag = CMP_NUM(d_1,d_2)))
358
        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
359
      a=  end;
360
      b+= 8;  /* sizeof(double); */
361
      break;
362
    case HA_KEYTYPE_NUM:                                /* Numeric key */
363
    {
364
      int swap_flag= 0;
365
      int alength,blength;
366
367
      if (keyseg->flag & HA_REVERSE_SORT)
368
      {
369
        swap_variables(uchar*, a, b);
370
        swap_flag=1;                            /* Remember swap of a & b */
371
        end= a+ (int) (end-b);
372
      }
373
      if (keyseg->flag & HA_SPACE_PACK)
374
      {
375
        alength= *a++; blength= *b++;
376
        end=a+alength;
377
        next_key_length=key_length-blength-1;
378
      }
379
      else
380
      {
381
        alength= (int) (end-a);
382
        blength=keyseg->length;
383
        /* remove pre space from keys */
384
        for ( ; alength && *a == ' ' ; a++, alength--) ;
385
        for ( ; blength && *b == ' ' ; b++, blength--) ;
386
      }
387
      if (piks)
388
      {
389
	if (*a == '-')
390
	{
391
	  if (*b != '-')
392
	    return -1;
393
	  a++; b++;
394
	  swap_variables(uchar*, a, b);
395
	  swap_variables(int, alength, blength);
396
	  swap_flag=1-swap_flag;
397
	  alength--; blength--;
398
	  end=a+alength;
399
	}
400
	else if (*b == '-')
401
	  return 1;
402
	while (alength && (*a == '+' || *a == '0'))
403
	{
404
	  a++; alength--;
405
	}
406
	while (blength && (*b == '+' || *b == '0'))
407
	{
408
	  b++; blength--;
409
	}
410
	if (alength != blength)
411
	  return (alength < blength) ? -1 : 1;
412
	while (a < end)
413
	  if (*a++ !=  *b++)
414
	    return ((int) a[-1] - (int) b[-1]);
415
      }
416
      else
417
      {
418
        b+=(end-a);
419
        a=end;
420
      }
421
422
      if (swap_flag)                            /* Restore pointers */
423
        swap_variables(uchar*, a, b);
424
      break;
425
    }
426
#ifdef HAVE_LONG_LONG
427
    case HA_KEYTYPE_LONGLONG:
428
    {
429
      longlong ll_a,ll_b;
430
      ll_a= mi_sint8korr(a);
431
      ll_b= mi_sint8korr(b);
432
      if (piks && (flag = CMP_NUM(ll_a,ll_b)))
433
        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
434
      a=  end;
435
      b+= 8;
436
      break;
437
    }
438
    case HA_KEYTYPE_ULONGLONG:
439
    {
440
      ulonglong ll_a,ll_b;
441
      ll_a= mi_uint8korr(a);
442
      ll_b= mi_uint8korr(b);
443
      if (piks && (flag = CMP_NUM(ll_a,ll_b)))
444
        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
445
      a=  end;
446
      b+= 8;
447
      break;
448
    }
449
#endif
450
    case HA_KEYTYPE_END:                        /* Ready */
451
      goto end;                                 /* diff_pos is incremented */
452
    }
453
  }
454
  (*diff_pos)++;
455
end:
456
  if (!(nextflag & SEARCH_FIND))
457
  {
458
    uint i;
459
    if (nextflag & (SEARCH_NO_FIND | SEARCH_LAST)) /* Find record after key */
460
      return (nextflag & (SEARCH_BIGGER | SEARCH_LAST)) ? -1 : 1;
461
    flag=0;
462
    for (i=keyseg->length ; i-- > 0 ; )
463
    {
464
      if (*a++ != *b++)
465
      {
466
        flag= FCMP(a[-1],b[-1]);
467
        break;
468
      }
469
    }
470
    if (nextflag & SEARCH_SAME)
471
      return (flag);                            /* read same */
472
    if (nextflag & SEARCH_BIGGER)
473
      return (flag <= 0 ? -1 : 1);              /* read next */
474
    return (flag < 0 ? -1 : 1);                 /* read previous */
475
  }
476
  return 0;
477
} /* ha_key_cmp */
478
479
480
/*
481
  Find the first NULL value in index-suffix values tuple
482
483
  SYNOPSIS
484
    ha_find_null()
485
      keyseg     Array of keyparts for key suffix
486
      a          Key suffix value tuple
487
488
  DESCRIPTION
489
    Find the first NULL value in index-suffix values tuple.
490
491
  TODO
492
    Consider optimizing this function or its use so we don't search for
493
    NULL values in completely NOT NULL index suffixes.
494
495
  RETURN
496
    First key part that has NULL as value in values tuple, or the last key
497
    part (with keyseg->type==HA_TYPE_END) if values tuple doesn't contain
498
    NULLs.
499
*/
500
501
HA_KEYSEG *ha_find_null(HA_KEYSEG *keyseg, uchar *a)
502
{
503
  for (; (enum ha_base_keytype) keyseg->type != HA_KEYTYPE_END; keyseg++)
504
  {
505
    uchar *end;
506
    if (keyseg->null_bit)
507
    {
508
      if (!*a++)
509
        return keyseg;
510
    }
511
    end= a+ keyseg->length;
512
513
    switch ((enum ha_base_keytype) keyseg->type) {
514
    case HA_KEYTYPE_TEXT:
515
    case HA_KEYTYPE_BINARY:
516
    case HA_KEYTYPE_BIT:
517
      if (keyseg->flag & HA_SPACE_PACK)
518
      {
519
        int a_length;
520
        get_key_length(a_length, a);
521
        a += a_length;
522
        break;
523
      }
524
      else
525
        a= end;
526
      break;
527
    case HA_KEYTYPE_VARTEXT1:
528
    case HA_KEYTYPE_VARTEXT2:
529
    case HA_KEYTYPE_VARBINARY1:
530
    case HA_KEYTYPE_VARBINARY2:
531
      {
532
        int a_length;
533
        get_key_length(a_length, a);
534
        a+= a_length;
535
        break;
536
      }
537
    case HA_KEYTYPE_NUM:
538
      if (keyseg->flag & HA_SPACE_PACK)
539
      {
540
        int alength= *a++;
541
        end= a+alength;
542
      }
543
      a= end;
544
      break;
545
    case HA_KEYTYPE_INT8:
546
    case HA_KEYTYPE_SHORT_INT:
547
    case HA_KEYTYPE_USHORT_INT:
548
    case HA_KEYTYPE_LONG_INT:
549
    case HA_KEYTYPE_ULONG_INT:
550
    case HA_KEYTYPE_INT24:
551
    case HA_KEYTYPE_UINT24:
552
#ifdef HAVE_LONG_LONG
553
    case HA_KEYTYPE_LONGLONG:
554
    case HA_KEYTYPE_ULONGLONG:
555
#endif
556
    case HA_KEYTYPE_FLOAT:
557
    case HA_KEYTYPE_DOUBLE:
558
      a= end;
559
      break;
560
    case HA_KEYTYPE_END:                        /* purecov: inspected */
561
      /* keep compiler happy */
562
      DBUG_ASSERT(0);
563
      break;
564
    }
565
  }
566
  return keyseg;
567
}
568
569
570
571
/*
572
  Register handler error messages for usage with my_error()
573
574
  NOTES
575
    This is safe to call multiple times as my_error_register()
576
    will ignore calls to register already registered error numbers.
577
*/
578
579
580
void my_handler_error_register(void)
581
{
582
  /*
583
    If you got compilation error here about compile_time_assert array, check
584
    that every HA_ERR_xxx constant has a corresponding error message in
585
    handler_error_messages[] list (check mysys/ma_handler_errors.h and
586
    include/my_base.h).
587
  */
588
  compile_time_assert(HA_ERR_FIRST + array_elements(handler_error_messages) ==
589
                      HA_ERR_LAST + 1);
590
  my_error_register(handler_error_messages, HA_ERR_FIRST,
591
                    HA_ERR_FIRST+ array_elements(handler_error_messages)-1);
592
}
593
594
595
void my_handler_error_unregister(void)
596
{
597
  my_error_unregister(HA_ERR_FIRST,
598
                      HA_ERR_FIRST+ array_elements(handler_error_messages)-1);
599
}