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