~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/innobase/rem/rem0cmp.c

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***********************************************************************
 
2
Comparison services for records
 
3
 
 
4
(c) 1994-1996 Innobase Oy
 
5
 
 
6
Created 7/1/1994 Heikki Tuuri
 
7
************************************************************************/
 
8
 
 
9
#include "rem0cmp.h"
 
10
 
 
11
#ifdef UNIV_NONINL
 
12
#include "rem0cmp.ic"
 
13
#endif
 
14
 
 
15
#include "srv0srv.h"
 
16
 
 
17
/*              ALPHABETICAL ORDER
 
18
                ==================
 
19
 
 
20
The records are put into alphabetical order in the following
 
21
way: let F be the first field where two records disagree.
 
22
If there is a character in some position n where the the
 
23
records disagree, the order is determined by comparison of
 
24
the characters at position n, possibly after
 
25
collating transformation. If there is no such character,
 
26
but the corresponding fields have different lengths, then
 
27
if the data type of the fields is paddable,
 
28
shorter field is padded with a padding character. If the
 
29
data type is not paddable, longer field is considered greater.
 
30
Finally, the SQL null is bigger than any other value.
 
31
 
 
32
At the present, the comparison functions return 0 in the case,
 
33
where two records disagree only in the way that one
 
34
has more fields than the other. */
 
35
 
 
36
#ifdef UNIV_DEBUG
 
37
/*****************************************************************
 
38
Used in debug checking of cmp_dtuple_... .
 
39
This function is used to compare a data tuple to a physical record. If
 
40
dtuple has n fields then rec must have either m >= n fields, or it must
 
41
differ from dtuple in some of the m fields rec has. */
 
42
static
 
43
int
 
44
cmp_debug_dtuple_rec_with_match(
 
45
/*============================*/
 
46
                                /* out: 1, 0, -1, if dtuple is greater, equal,
 
47
                                less than rec, respectively, when only the
 
48
                                common first fields are compared */
 
49
        dtuple_t*       dtuple, /* in: data tuple */
 
50
        rec_t*          rec,    /* in: physical record which differs from
 
51
                                dtuple in some of the common fields, or which
 
52
                                has an equal number or more fields than
 
53
                                dtuple */
 
54
        const ulint*    offsets,/* in: array returned by rec_get_offsets() */
 
55
        ulint*          matched_fields);/* in/out: number of already
 
56
                                completely  matched fields; when function
 
57
                                returns, contains the value for current
 
58
                                comparison */
 
59
#endif /* UNIV_DEBUG */
 
60
#ifndef UNIV_HOTBACKUP
 
61
/*****************************************************************
 
62
This function is used to compare two data fields for which the data type
 
63
is such that we must use MySQL code to compare them. The prototype here
 
64
must be a copy of the the one in ha_innobase.cc! */
 
65
extern
 
66
int
 
67
innobase_mysql_cmp(
 
68
/*===============*/
 
69
                                        /* out: 1, 0, -1, if a is greater,
 
70
                                        equal, less than b, respectively */
 
71
        int             mysql_type,     /* in: MySQL type */
 
72
        uint            charset_number, /* in: number of the charset */
 
73
        unsigned char*  a,              /* in: data field */
 
74
        unsigned int    a_length,       /* in: data field length,
 
75
                                        not UNIV_SQL_NULL */
 
76
        unsigned char*  b,              /* in: data field */
 
77
        unsigned int    b_length);      /* in: data field length,
 
78
                                        not UNIV_SQL_NULL */
 
79
#endif /* !UNIV_HOTBACKUP */
 
80
/*************************************************************************
 
81
Transforms the character code so that it is ordered appropriately for the
 
82
language. This is only used for the latin1 char set. MySQL does the
 
83
comparisons for other char sets. */
 
84
UNIV_INLINE
 
85
ulint
 
86
cmp_collate(
 
87
/*========*/
 
88
                        /* out: collation order position */
 
89
        ulint   code)   /* in: code of a character stored in database record */
 
90
{
 
91
        return((ulint) srv_latin1_ordering[code]);
 
92
}
 
93
 
 
94
/*****************************************************************
 
95
Returns TRUE if two columns are equal for comparison purposes. */
 
96
 
 
97
ibool
 
98
cmp_cols_are_equal(
 
99
/*===============*/
 
100
                                        /* out: TRUE if the columns are
 
101
                                        considered equal in comparisons */
 
102
        const dict_col_t*       col1,   /* in: column 1 */
 
103
        const dict_col_t*       col2,   /* in: column 2 */
 
104
        ibool                   check_charsets)
 
105
                                        /* in: whether to check charsets */
 
106
{
 
107
        if (dtype_is_non_binary_string_type(col1->mtype, col1->prtype)
 
108
            && dtype_is_non_binary_string_type(col2->mtype, col2->prtype)) {
 
109
 
 
110
                /* Both are non-binary string types: they can be compared if
 
111
                and only if the charset-collation is the same */
 
112
 
 
113
                if (check_charsets) {
 
114
                        return(dtype_get_charset_coll(col1->prtype)
 
115
                               == dtype_get_charset_coll(col2->prtype));
 
116
                } else {
 
117
                        return(TRUE);
 
118
                }
 
119
        }
 
120
 
 
121
        if (dtype_is_binary_string_type(col1->mtype, col1->prtype)
 
122
            && dtype_is_binary_string_type(col2->mtype, col2->prtype)) {
 
123
 
 
124
                /* Both are binary string types: they can be compared */
 
125
 
 
126
                return(TRUE);
 
127
        }
 
128
 
 
129
        if (col1->mtype != col2->mtype) {
 
130
 
 
131
                return(FALSE);
 
132
        }
 
133
 
 
134
        if (col1->mtype == DATA_INT
 
135
            && (col1->prtype & DATA_UNSIGNED)
 
136
            != (col2->prtype & DATA_UNSIGNED)) {
 
137
 
 
138
                /* The storage format of an unsigned integer is different
 
139
                from a signed integer: in a signed integer we OR
 
140
                0x8000... to the value of positive integers. */
 
141
 
 
142
                return(FALSE);
 
143
        }
 
144
 
 
145
        return(col1->mtype != DATA_INT || col1->len == col2->len);
 
146
}
 
147
 
 
148
#ifndef UNIV_HOTBACKUP
 
149
/*****************************************************************
 
150
Innobase uses this function to compare two data fields for which the data type
 
151
is such that we must compare whole fields or call MySQL to do the comparison */
 
152
static
 
153
int
 
154
cmp_whole_field(
 
155
/*============*/
 
156
                                        /* out: 1, 0, -1, if a is greater,
 
157
                                        equal, less than b, respectively */
 
158
        ulint           mtype,          /* in: main type */
 
159
        ulint           prtype,         /* in: precise type */
 
160
        unsigned char*  a,              /* in: data field */
 
161
        unsigned int    a_length,       /* in: data field length,
 
162
                                        not UNIV_SQL_NULL */
 
163
        unsigned char*  b,              /* in: data field */
 
164
        unsigned int    b_length)       /* in: data field length,
 
165
                                        not UNIV_SQL_NULL */
 
166
{
 
167
        float           f_1;
 
168
        float           f_2;
 
169
        double          d_1;
 
170
        double          d_2;
 
171
        int             swap_flag       = 1;
 
172
 
 
173
        switch (mtype) {
 
174
 
 
175
        case DATA_DECIMAL:
 
176
                /* Remove preceding spaces */
 
177
                for (; a_length && *a == ' '; a++, a_length--);
 
178
                for (; b_length && *b == ' '; b++, b_length--);
 
179
 
 
180
                if (*a == '-') {
 
181
                        if (*b != '-') {
 
182
                                return(-1);
 
183
                        }
 
184
 
 
185
                        a++; b++;
 
186
                        a_length--;
 
187
                        b_length--;
 
188
 
 
189
                        swap_flag = -1;
 
190
 
 
191
                } else if (*b == '-') {
 
192
 
 
193
                        return(1);
 
194
                }
 
195
 
 
196
                while (a_length > 0 && (*a == '+' || *a == '0')) {
 
197
                        a++; a_length--;
 
198
                }
 
199
 
 
200
                while (b_length > 0 && (*b == '+' || *b == '0')) {
 
201
                        b++; b_length--;
 
202
                }
 
203
 
 
204
                if (a_length != b_length) {
 
205
                        if (a_length < b_length) {
 
206
                                return(-swap_flag);
 
207
                        }
 
208
 
 
209
                        return(swap_flag);
 
210
                }
 
211
 
 
212
                while (a_length > 0 && *a == *b) {
 
213
 
 
214
                        a++; b++; a_length--;
 
215
                }
 
216
 
 
217
                if (a_length == 0) {
 
218
 
 
219
                        return(0);
 
220
                }
 
221
 
 
222
                if (*a > *b) {
 
223
                        return(swap_flag);
 
224
                }
 
225
 
 
226
                return(-swap_flag);
 
227
        case DATA_DOUBLE:
 
228
                d_1 = mach_double_read(a);
 
229
                d_2 = mach_double_read(b);
 
230
 
 
231
                if (d_1 > d_2) {
 
232
                        return(1);
 
233
                } else if (d_2 > d_1) {
 
234
                        return(-1);
 
235
                }
 
236
 
 
237
                return(0);
 
238
 
 
239
        case DATA_FLOAT:
 
240
                f_1 = mach_float_read(a);
 
241
                f_2 = mach_float_read(b);
 
242
 
 
243
                if (f_1 > f_2) {
 
244
                        return(1);
 
245
                } else if (f_2 > f_1) {
 
246
                        return(-1);
 
247
                }
 
248
 
 
249
                return(0);
 
250
        case DATA_BLOB:
 
251
                if (prtype & DATA_BINARY_TYPE) {
 
252
 
 
253
                        ut_print_timestamp(stderr);
 
254
                        fprintf(stderr,
 
255
                                "  InnoDB: Error: comparing a binary BLOB"
 
256
                                " with a character set sensitive\n"
 
257
                                "InnoDB: comparison!\n");
 
258
                }
 
259
                /* fall through */
 
260
        case DATA_VARMYSQL:
 
261
        case DATA_MYSQL:
 
262
                return(innobase_mysql_cmp(
 
263
                               (int)(prtype & DATA_MYSQL_TYPE_MASK),
 
264
                               (uint)dtype_get_charset_coll(prtype),
 
265
                               a, a_length, b, b_length));
 
266
        default:
 
267
                fprintf(stderr,
 
268
                        "InnoDB: unknown type number %lu\n",
 
269
                        (ulong) mtype);
 
270
                ut_error;
 
271
        }
 
272
 
 
273
        return(0);
 
274
}
 
275
#endif /* !UNIV_HOTBACKUP */
 
276
 
 
277
/*****************************************************************
 
278
This function is used to compare two data fields for which we know the
 
279
data type. */
 
280
 
 
281
int
 
282
cmp_data_data_slow(
 
283
/*===============*/
 
284
                                /* out: 1, 0, -1, if data1 is greater, equal,
 
285
                                less than data2, respectively */
 
286
        ulint           mtype,  /* in: main type */
 
287
        ulint           prtype, /* in: precise type */
 
288
        byte*           data1,  /* in: data field (== a pointer to a memory
 
289
                                buffer) */
 
290
        ulint           len1,   /* in: data field length or UNIV_SQL_NULL */
 
291
        byte*           data2,  /* in: data field (== a pointer to a memory
 
292
                                buffer) */
 
293
        ulint           len2)   /* in: data field length or UNIV_SQL_NULL */
 
294
{
 
295
#ifndef UNIV_HOTBACKUP
 
296
        ulint   data1_byte;
 
297
        ulint   data2_byte;
 
298
        ulint   cur_bytes;
 
299
 
 
300
        if (len1 == UNIV_SQL_NULL || len2 == UNIV_SQL_NULL) {
 
301
 
 
302
                if (len1 == len2) {
 
303
 
 
304
                        return(0);
 
305
                }
 
306
 
 
307
                if (len1 == UNIV_SQL_NULL) {
 
308
                        /* We define the SQL null to be the smallest possible
 
309
                        value of a field in the alphabetical order */
 
310
 
 
311
                        return(-1);
 
312
                }
 
313
 
 
314
                return(1);
 
315
        }
 
316
 
 
317
        if (mtype >= DATA_FLOAT
 
318
            || (mtype == DATA_BLOB
 
319
                && 0 == (prtype & DATA_BINARY_TYPE)
 
320
                && dtype_get_charset_coll(prtype)
 
321
                != DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL)) {
 
322
 
 
323
                return(cmp_whole_field(mtype, prtype,
 
324
                                       data1, (unsigned) len1,
 
325
                                       data2, (unsigned) len2));
 
326
        }
 
327
 
 
328
        /* Compare then the fields */
 
329
 
 
330
        cur_bytes = 0;
 
331
 
 
332
        for (;;) {
 
333
                if (len1 <= cur_bytes) {
 
334
                        if (len2 <= cur_bytes) {
 
335
 
 
336
                                return(0);
 
337
                        }
 
338
 
 
339
                        data1_byte = dtype_get_pad_char(mtype, prtype);
 
340
 
 
341
                        if (data1_byte == ULINT_UNDEFINED) {
 
342
 
 
343
                                return(-1);
 
344
                        }
 
345
                } else {
 
346
                        data1_byte = *data1;
 
347
                }
 
348
 
 
349
                if (len2 <= cur_bytes) {
 
350
                        data2_byte = dtype_get_pad_char(mtype, prtype);
 
351
 
 
352
                        if (data2_byte == ULINT_UNDEFINED) {
 
353
 
 
354
                                return(1);
 
355
                        }
 
356
                } else {
 
357
                        data2_byte = *data2;
 
358
                }
 
359
 
 
360
                if (data1_byte == data2_byte) {
 
361
                        /* If the bytes are equal, they will remain such even
 
362
                        after the collation transformation below */
 
363
 
 
364
                        goto next_byte;
 
365
                }
 
366
 
 
367
                if (mtype <= DATA_CHAR
 
368
                    || (mtype == DATA_BLOB
 
369
                        && 0 == (prtype & DATA_BINARY_TYPE))) {
 
370
 
 
371
                        data1_byte = cmp_collate(data1_byte);
 
372
                        data2_byte = cmp_collate(data2_byte);
 
373
                }
 
374
 
 
375
                if (data1_byte > data2_byte) {
 
376
 
 
377
                        return(1);
 
378
                } else if (data1_byte < data2_byte) {
 
379
 
 
380
                        return(-1);
 
381
                }
 
382
next_byte:
 
383
                /* Next byte */
 
384
                cur_bytes++;
 
385
                data1++;
 
386
                data2++;
 
387
        }
 
388
#else /* !UNIV_HOTBACKUP */
 
389
        /* This function depends on MySQL code that is not included in
 
390
        InnoDB Hot Backup builds.  Besides, this function should never
 
391
        be called in InnoDB Hot Backup. */
 
392
        ut_error;
 
393
#endif /* !UNIV_HOTBACKUP */
 
394
 
 
395
        return(0);              /* Not reached */
 
396
}
 
397
 
 
398
/*****************************************************************
 
399
This function is used to compare a data tuple to a physical record.
 
400
Only dtuple->n_fields_cmp first fields are taken into account for
 
401
the the data tuple! If we denote by n = n_fields_cmp, then rec must
 
402
have either m >= n fields, or it must differ from dtuple in some of
 
403
the m fields rec has. If rec has an externally stored field we do not
 
404
compare it but return with value 0 if such a comparison should be
 
405
made. */
 
406
 
 
407
int
 
408
cmp_dtuple_rec_with_match(
 
409
/*======================*/
 
410
                                /* out: 1, 0, -1, if dtuple is greater, equal,
 
411
                                less than rec, respectively, when only the
 
412
                                common first fields are compared, or
 
413
                                until the first externally stored field in
 
414
                                rec */
 
415
        dtuple_t*       dtuple, /* in: data tuple */
 
416
        rec_t*          rec,    /* in: physical record which differs from
 
417
                                dtuple in some of the common fields, or which
 
418
                                has an equal number or more fields than
 
419
                                dtuple */
 
420
        const ulint*    offsets,/* in: array returned by rec_get_offsets() */
 
421
        ulint*          matched_fields, /* in/out: number of already completely
 
422
                                matched fields; when function returns,
 
423
                                contains the value for current comparison */
 
424
        ulint*          matched_bytes) /* in/out: number of already matched
 
425
                                bytes within the first field not completely
 
426
                                matched; when function returns, contains the
 
427
                                value for current comparison */
 
428
{
 
429
#ifndef UNIV_HOTBACKUP
 
430
        dfield_t*       dtuple_field;   /* current field in logical record */
 
431
        ulint           dtuple_f_len;   /* the length of the current field
 
432
                                        in the logical record */
 
433
        byte*           dtuple_b_ptr;   /* pointer to the current byte in
 
434
                                        logical field data */
 
435
        ulint           dtuple_byte;    /* value of current byte to be compared
 
436
                                        in dtuple*/
 
437
        ulint           rec_f_len;      /* length of current field in rec */
 
438
        byte*           rec_b_ptr;      /* pointer to the current byte in
 
439
                                        rec field */
 
440
        ulint           rec_byte;       /* value of current byte to be
 
441
                                        compared in rec */
 
442
        ulint           cur_field;      /* current field number */
 
443
        ulint           cur_bytes;      /* number of already matched bytes
 
444
                                        in current field */
 
445
        int             ret = 3333;     /* return value */
 
446
 
 
447
        ut_ad(dtuple && rec && matched_fields && matched_bytes);
 
448
        ut_ad(dtuple_check_typed(dtuple));
 
449
        ut_ad(rec_offs_validate(rec, NULL, offsets));
 
450
 
 
451
        cur_field = *matched_fields;
 
452
        cur_bytes = *matched_bytes;
 
453
 
 
454
        ut_ad(cur_field <= dtuple_get_n_fields_cmp(dtuple));
 
455
        ut_ad(cur_field <= rec_offs_n_fields(offsets));
 
456
 
 
457
        if (cur_bytes == 0 && cur_field == 0) {
 
458
                ulint   rec_info = rec_get_info_bits(rec,
 
459
                                                     rec_offs_comp(offsets));
 
460
                ulint   tup_info = dtuple_get_info_bits(dtuple);
 
461
 
 
462
                if (rec_info & REC_INFO_MIN_REC_FLAG) {
 
463
                        ret = !(tup_info & REC_INFO_MIN_REC_FLAG);
 
464
                        goto order_resolved;
 
465
                } else if (tup_info & REC_INFO_MIN_REC_FLAG) {
 
466
                        ret = -1;
 
467
                        goto order_resolved;
 
468
                }
 
469
        }
 
470
 
 
471
        /* Match fields in a loop; stop if we run out of fields in dtuple
 
472
        or find an externally stored field */
 
473
 
 
474
        while (cur_field < dtuple_get_n_fields_cmp(dtuple)) {
 
475
 
 
476
                ulint   mtype;
 
477
                ulint   prtype;
 
478
 
 
479
                dtuple_field = dtuple_get_nth_field(dtuple, cur_field);
 
480
                {
 
481
                        const dtype_t*  type
 
482
                                = dfield_get_type(dtuple_field);
 
483
 
 
484
                        mtype = type->mtype;
 
485
                        prtype = type->prtype;
 
486
                }
 
487
 
 
488
                dtuple_f_len = dfield_get_len(dtuple_field);
 
489
 
 
490
                rec_b_ptr = rec_get_nth_field(rec, offsets,
 
491
                                              cur_field, &rec_f_len);
 
492
 
 
493
                /* If we have matched yet 0 bytes, it may be that one or
 
494
                both the fields are SQL null, or the record or dtuple may be
 
495
                the predefined minimum record, or the field is externally
 
496
                stored */
 
497
 
 
498
                if (UNIV_LIKELY(cur_bytes == 0)) {
 
499
                        if (rec_offs_nth_extern(offsets, cur_field)) {
 
500
                                /* We do not compare to an externally
 
501
                                stored field */
 
502
 
 
503
                                ret = 0;
 
504
 
 
505
                                goto order_resolved;
 
506
                        }
 
507
 
 
508
                        if (dtuple_f_len == UNIV_SQL_NULL) {
 
509
                                if (rec_f_len == UNIV_SQL_NULL) {
 
510
 
 
511
                                        goto next_field;
 
512
                                }
 
513
 
 
514
                                ret = -1;
 
515
                                goto order_resolved;
 
516
                        } else if (rec_f_len == UNIV_SQL_NULL) {
 
517
                                /* We define the SQL null to be the
 
518
                                smallest possible value of a field
 
519
                                in the alphabetical order */
 
520
 
 
521
                                ret = 1;
 
522
                                goto order_resolved;
 
523
                        }
 
524
                }
 
525
 
 
526
                if (mtype >= DATA_FLOAT
 
527
                    || (mtype == DATA_BLOB
 
528
                        && 0 == (prtype & DATA_BINARY_TYPE)
 
529
                        && dtype_get_charset_coll(prtype)
 
530
                        != DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL)) {
 
531
 
 
532
                        ret = cmp_whole_field(mtype, prtype,
 
533
                                              dfield_get_data(dtuple_field),
 
534
                                              (unsigned) dtuple_f_len,
 
535
                                              rec_b_ptr, (unsigned) rec_f_len);
 
536
 
 
537
                        if (ret != 0) {
 
538
                                cur_bytes = 0;
 
539
 
 
540
                                goto order_resolved;
 
541
                        } else {
 
542
                                goto next_field;
 
543
                        }
 
544
                }
 
545
 
 
546
                /* Set the pointers at the current byte */
 
547
 
 
548
                rec_b_ptr = rec_b_ptr + cur_bytes;
 
549
                dtuple_b_ptr = (byte*)dfield_get_data(dtuple_field)
 
550
                        + cur_bytes;
 
551
                /* Compare then the fields */
 
552
 
 
553
                for (;;) {
 
554
                        if (UNIV_UNLIKELY(rec_f_len <= cur_bytes)) {
 
555
                                if (dtuple_f_len <= cur_bytes) {
 
556
 
 
557
                                        goto next_field;
 
558
                                }
 
559
 
 
560
                                rec_byte = dtype_get_pad_char(mtype, prtype);
 
561
 
 
562
                                if (rec_byte == ULINT_UNDEFINED) {
 
563
                                        ret = 1;
 
564
 
 
565
                                        goto order_resolved;
 
566
                                }
 
567
                        } else {
 
568
                                rec_byte = *rec_b_ptr;
 
569
                        }
 
570
 
 
571
                        if (UNIV_UNLIKELY(dtuple_f_len <= cur_bytes)) {
 
572
                                dtuple_byte = dtype_get_pad_char(mtype,
 
573
                                                                 prtype);
 
574
 
 
575
                                if (dtuple_byte == ULINT_UNDEFINED) {
 
576
                                        ret = -1;
 
577
 
 
578
                                        goto order_resolved;
 
579
                                }
 
580
                        } else {
 
581
                                dtuple_byte = *dtuple_b_ptr;
 
582
                        }
 
583
 
 
584
                        if (dtuple_byte == rec_byte) {
 
585
                                /* If the bytes are equal, they will
 
586
                                remain such even after the collation
 
587
                                transformation below */
 
588
 
 
589
                                goto next_byte;
 
590
                        }
 
591
 
 
592
                        if (mtype <= DATA_CHAR
 
593
                            || (mtype == DATA_BLOB
 
594
                                && !(prtype & DATA_BINARY_TYPE))) {
 
595
 
 
596
                                rec_byte = cmp_collate(rec_byte);
 
597
                                dtuple_byte = cmp_collate(dtuple_byte);
 
598
                        }
 
599
 
 
600
                        ret = (int) (dtuple_byte - rec_byte);
 
601
                        if (UNIV_UNLIKELY(ret)) {
 
602
                                if (ret < 0) {
 
603
                                        ret = -1;
 
604
                                        goto order_resolved;
 
605
                                } else {
 
606
                                        ret = 1;
 
607
                                        goto order_resolved;
 
608
                                }
 
609
                        }
 
610
next_byte:
 
611
                        /* Next byte */
 
612
                        cur_bytes++;
 
613
                        rec_b_ptr++;
 
614
                        dtuple_b_ptr++;
 
615
                }
 
616
 
 
617
next_field:
 
618
                cur_field++;
 
619
                cur_bytes = 0;
 
620
        }
 
621
 
 
622
        ut_ad(cur_bytes == 0);
 
623
 
 
624
        ret = 0;        /* If we ran out of fields, dtuple was equal to rec
 
625
                        up to the common fields */
 
626
order_resolved:
 
627
        ut_ad((ret >= - 1) && (ret <= 1));
 
628
        ut_ad(ret == cmp_debug_dtuple_rec_with_match(dtuple, rec, offsets,
 
629
                                                     matched_fields));
 
630
        ut_ad(*matched_fields == cur_field); /* In the debug version, the
 
631
                                             above cmp_debug_... sets
 
632
                                             *matched_fields to a value */
 
633
        *matched_fields = cur_field;
 
634
        *matched_bytes = cur_bytes;
 
635
 
 
636
        return(ret);
 
637
#else /* !UNIV_HOTBACKUP */
 
638
        /* This function depends on MySQL code that is not included in
 
639
        InnoDB Hot Backup builds.  Besides, this function should never
 
640
        be called in InnoDB Hot Backup. */
 
641
        ut_error;
 
642
        return(0);
 
643
#endif /* !UNIV_HOTBACKUP */
 
644
}
 
645
 
 
646
/******************************************************************
 
647
Compares a data tuple to a physical record. */
 
648
 
 
649
int
 
650
cmp_dtuple_rec(
 
651
/*===========*/
 
652
                                /* out: 1, 0, -1, if dtuple is greater, equal,
 
653
                                less than rec, respectively; see the comments
 
654
                                for cmp_dtuple_rec_with_match */
 
655
        dtuple_t*       dtuple, /* in: data tuple */
 
656
        rec_t*          rec,    /* in: physical record */
 
657
        const ulint*    offsets)/* in: array returned by rec_get_offsets() */
 
658
{
 
659
        ulint   matched_fields  = 0;
 
660
        ulint   matched_bytes   = 0;
 
661
 
 
662
        ut_ad(rec_offs_validate(rec, NULL, offsets));
 
663
        return(cmp_dtuple_rec_with_match(dtuple, rec, offsets,
 
664
                                         &matched_fields, &matched_bytes));
 
665
}
 
666
 
 
667
/******************************************************************
 
668
Checks if a dtuple is a prefix of a record. The last field in dtuple
 
669
is allowed to be a prefix of the corresponding field in the record. */
 
670
 
 
671
ibool
 
672
cmp_dtuple_is_prefix_of_rec(
 
673
/*========================*/
 
674
                                /* out: TRUE if prefix */
 
675
        dtuple_t*       dtuple, /* in: data tuple */
 
676
        rec_t*          rec,    /* in: physical record */
 
677
        const ulint*    offsets)/* in: array returned by rec_get_offsets() */
 
678
{
 
679
        ulint   n_fields;
 
680
        ulint   matched_fields  = 0;
 
681
        ulint   matched_bytes   = 0;
 
682
 
 
683
        ut_ad(rec_offs_validate(rec, NULL, offsets));
 
684
        n_fields = dtuple_get_n_fields(dtuple);
 
685
 
 
686
        if (n_fields > rec_offs_n_fields(offsets)) {
 
687
 
 
688
                return(FALSE);
 
689
        }
 
690
 
 
691
        cmp_dtuple_rec_with_match(dtuple, rec, offsets,
 
692
                                  &matched_fields, &matched_bytes);
 
693
        if (matched_fields == n_fields) {
 
694
 
 
695
                return(TRUE);
 
696
        }
 
697
 
 
698
        if (matched_fields == n_fields - 1
 
699
            && matched_bytes == dfield_get_len(
 
700
                    dtuple_get_nth_field(dtuple, n_fields - 1))) {
 
701
                return(TRUE);
 
702
        }
 
703
 
 
704
        return(FALSE);
 
705
}
 
706
 
 
707
/*****************************************************************
 
708
This function is used to compare two physical records. Only the common
 
709
first fields are compared, and if an externally stored field is
 
710
encountered, then 0 is returned. */
 
711
 
 
712
int
 
713
cmp_rec_rec_with_match(
 
714
/*===================*/
 
715
                                /* out: 1, 0 , -1 if rec1 is greater, equal,
 
716
                                less, respectively, than rec2; only the common
 
717
                                first fields are compared */
 
718
        rec_t*          rec1,   /* in: physical record */
 
719
        rec_t*          rec2,   /* in: physical record */
 
720
        const ulint*    offsets1,/* in: rec_get_offsets(rec1, index) */
 
721
        const ulint*    offsets2,/* in: rec_get_offsets(rec2, index) */
 
722
        dict_index_t*   index,  /* in: data dictionary index */
 
723
        ulint*          matched_fields, /* in/out: number of already completely
 
724
                                matched fields; when the function returns,
 
725
                                contains the value the for current
 
726
                                comparison */
 
727
        ulint*          matched_bytes) /* in/out: number of already matched
 
728
                                bytes within the first field not completely
 
729
                                matched; when the function returns, contains
 
730
                                the value for the current comparison */
 
731
{
 
732
#ifndef UNIV_HOTBACKUP
 
733
        ulint   rec1_n_fields;  /* the number of fields in rec */
 
734
        ulint   rec1_f_len;     /* length of current field in rec */
 
735
        byte*   rec1_b_ptr;     /* pointer to the current byte in rec field */
 
736
        ulint   rec1_byte;      /* value of current byte to be compared in
 
737
                                rec */
 
738
        ulint   rec2_n_fields;  /* the number of fields in rec */
 
739
        ulint   rec2_f_len;     /* length of current field in rec */
 
740
        byte*   rec2_b_ptr;     /* pointer to the current byte in rec field */
 
741
        ulint   rec2_byte;      /* value of current byte to be compared in
 
742
                                rec */
 
743
        ulint   cur_field;      /* current field number */
 
744
        ulint   cur_bytes;      /* number of already matched bytes in current
 
745
                                field */
 
746
        int     ret = 3333;     /* return value */
 
747
        ulint   comp;
 
748
 
 
749
        ut_ad(rec1 && rec2 && index);
 
750
        ut_ad(rec_offs_validate(rec1, index, offsets1));
 
751
        ut_ad(rec_offs_validate(rec2, index, offsets2));
 
752
        ut_ad(rec_offs_comp(offsets1) == rec_offs_comp(offsets2));
 
753
 
 
754
        comp = rec_offs_comp(offsets1);
 
755
        rec1_n_fields = rec_offs_n_fields(offsets1);
 
756
        rec2_n_fields = rec_offs_n_fields(offsets2);
 
757
 
 
758
        cur_field = *matched_fields;
 
759
        cur_bytes = *matched_bytes;
 
760
 
 
761
        /* Match fields in a loop */
 
762
 
 
763
        while ((cur_field < rec1_n_fields) && (cur_field < rec2_n_fields)) {
 
764
 
 
765
                ulint   mtype;
 
766
                ulint   prtype;
 
767
 
 
768
                if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
 
769
                        /* This is for the insert buffer B-tree. */
 
770
                        mtype = DATA_BINARY;
 
771
                        prtype = 0;
 
772
                } else {
 
773
                        const dict_col_t*       col
 
774
                                = dict_index_get_nth_col(index, cur_field);
 
775
 
 
776
                        mtype = col->mtype;
 
777
                        prtype = col->prtype;
 
778
                }
 
779
 
 
780
                rec1_b_ptr = rec_get_nth_field(rec1, offsets1,
 
781
                                               cur_field, &rec1_f_len);
 
782
                rec2_b_ptr = rec_get_nth_field(rec2, offsets2,
 
783
                                               cur_field, &rec2_f_len);
 
784
 
 
785
                if (cur_bytes == 0) {
 
786
                        if (cur_field == 0) {
 
787
                                /* Test if rec is the predefined minimum
 
788
                                record */
 
789
                                if (rec_get_info_bits(rec1, comp)
 
790
                                    & REC_INFO_MIN_REC_FLAG) {
 
791
 
 
792
                                        if (rec_get_info_bits(rec2, comp)
 
793
                                            & REC_INFO_MIN_REC_FLAG) {
 
794
                                                ret = 0;
 
795
                                        } else {
 
796
                                                ret = -1;
 
797
                                        }
 
798
 
 
799
                                        goto order_resolved;
 
800
 
 
801
                                } else if (rec_get_info_bits(rec2, comp)
 
802
                                           & REC_INFO_MIN_REC_FLAG) {
 
803
 
 
804
                                        ret = 1;
 
805
 
 
806
                                        goto order_resolved;
 
807
                                }
 
808
                        }
 
809
 
 
810
                        if (rec_offs_nth_extern(offsets1, cur_field)
 
811
                            || rec_offs_nth_extern(offsets2, cur_field)) {
 
812
                                /* We do not compare to an externally
 
813
                                stored field */
 
814
 
 
815
                                ret = 0;
 
816
 
 
817
                                goto order_resolved;
 
818
                        }
 
819
 
 
820
                        if (rec1_f_len == UNIV_SQL_NULL
 
821
                            || rec2_f_len == UNIV_SQL_NULL) {
 
822
 
 
823
                                if (rec1_f_len == rec2_f_len) {
 
824
 
 
825
                                        goto next_field;
 
826
 
 
827
                                } else if (rec2_f_len == UNIV_SQL_NULL) {
 
828
 
 
829
                                        /* We define the SQL null to be the
 
830
                                        smallest possible value of a field
 
831
                                        in the alphabetical order */
 
832
 
 
833
                                        ret = 1;
 
834
                                } else {
 
835
                                        ret = -1;
 
836
                                }
 
837
 
 
838
                                goto order_resolved;
 
839
                        }
 
840
                }
 
841
 
 
842
                if (mtype >= DATA_FLOAT
 
843
                    || (mtype == DATA_BLOB
 
844
                        && 0 == (prtype & DATA_BINARY_TYPE)
 
845
                        && dtype_get_charset_coll(prtype)
 
846
                        != DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL)) {
 
847
 
 
848
                        ret = cmp_whole_field(mtype, prtype,
 
849
                                              rec1_b_ptr,
 
850
                                              (unsigned) rec1_f_len,
 
851
                                              rec2_b_ptr,
 
852
                                              (unsigned) rec2_f_len);
 
853
                        if (ret != 0) {
 
854
                                cur_bytes = 0;
 
855
 
 
856
                                goto order_resolved;
 
857
                        } else {
 
858
                                goto next_field;
 
859
                        }
 
860
                }
 
861
 
 
862
                /* Set the pointers at the current byte */
 
863
                rec1_b_ptr = rec1_b_ptr + cur_bytes;
 
864
                rec2_b_ptr = rec2_b_ptr + cur_bytes;
 
865
 
 
866
                /* Compare then the fields */
 
867
                for (;;) {
 
868
                        if (rec2_f_len <= cur_bytes) {
 
869
 
 
870
                                if (rec1_f_len <= cur_bytes) {
 
871
 
 
872
                                        goto next_field;
 
873
                                }
 
874
 
 
875
                                rec2_byte = dtype_get_pad_char(mtype, prtype);
 
876
 
 
877
                                if (rec2_byte == ULINT_UNDEFINED) {
 
878
                                        ret = 1;
 
879
 
 
880
                                        goto order_resolved;
 
881
                                }
 
882
                        } else {
 
883
                                rec2_byte = *rec2_b_ptr;
 
884
                        }
 
885
 
 
886
                        if (rec1_f_len <= cur_bytes) {
 
887
                                rec1_byte = dtype_get_pad_char(mtype, prtype);
 
888
 
 
889
                                if (rec1_byte == ULINT_UNDEFINED) {
 
890
                                        ret = -1;
 
891
 
 
892
                                        goto order_resolved;
 
893
                                }
 
894
                        } else {
 
895
                                rec1_byte = *rec1_b_ptr;
 
896
                        }
 
897
 
 
898
                        if (rec1_byte == rec2_byte) {
 
899
                                /* If the bytes are equal, they will remain
 
900
                                such even after the collation transformation
 
901
                                below */
 
902
 
 
903
                                goto next_byte;
 
904
                        }
 
905
 
 
906
                        if (mtype <= DATA_CHAR
 
907
                            || (mtype == DATA_BLOB
 
908
                                && !(prtype & DATA_BINARY_TYPE))) {
 
909
 
 
910
                                rec1_byte = cmp_collate(rec1_byte);
 
911
                                rec2_byte = cmp_collate(rec2_byte);
 
912
                        }
 
913
 
 
914
                        if (rec1_byte < rec2_byte) {
 
915
                                ret = -1;
 
916
                                goto order_resolved;
 
917
                        } else if (rec1_byte > rec2_byte) {
 
918
                                ret = 1;
 
919
                                goto order_resolved;
 
920
                        }
 
921
next_byte:
 
922
                        /* Next byte */
 
923
 
 
924
                        cur_bytes++;
 
925
                        rec1_b_ptr++;
 
926
                        rec2_b_ptr++;
 
927
                }
 
928
 
 
929
next_field:
 
930
                cur_field++;
 
931
                cur_bytes = 0;
 
932
        }
 
933
 
 
934
        ut_ad(cur_bytes == 0);
 
935
 
 
936
        ret = 0;        /* If we ran out of fields, rec1 was equal to rec2 up
 
937
                        to the common fields */
 
938
order_resolved:
 
939
 
 
940
        ut_ad((ret >= - 1) && (ret <= 1));
 
941
 
 
942
        *matched_fields = cur_field;
 
943
        *matched_bytes = cur_bytes;
 
944
 
 
945
        return(ret);
 
946
#else /* !UNIV_HOTBACKUP */
 
947
        /* This function depends on MySQL code that is not included in
 
948
        InnoDB Hot Backup builds.  Besides, this function should never
 
949
        be called in InnoDB Hot Backup. */
 
950
        ut_error;
 
951
        return(0);
 
952
#endif /* !UNIV_HOTBACKUP */
 
953
}
 
954
 
 
955
#ifdef UNIV_DEBUG
 
956
/*****************************************************************
 
957
Used in debug checking of cmp_dtuple_... .
 
958
This function is used to compare a data tuple to a physical record. If
 
959
dtuple has n fields then rec must have either m >= n fields, or it must
 
960
differ from dtuple in some of the m fields rec has. If encounters an
 
961
externally stored field, returns 0. */
 
962
static
 
963
int
 
964
cmp_debug_dtuple_rec_with_match(
 
965
/*============================*/
 
966
                                /* out: 1, 0, -1, if dtuple is greater, equal,
 
967
                                less than rec, respectively, when only the
 
968
                                common first fields are compared */
 
969
        dtuple_t*       dtuple, /* in: data tuple */
 
970
        rec_t*          rec,    /* in: physical record which differs from
 
971
                                dtuple in some of the common fields, or which
 
972
                                has an equal number or more fields than
 
973
                                dtuple */
 
974
        const ulint*    offsets,/* in: array returned by rec_get_offsets() */
 
975
        ulint*          matched_fields) /* in/out: number of already
 
976
                                completely matched fields; when function
 
977
                                returns, contains the value for current
 
978
                                comparison */
 
979
{
 
980
        dfield_t*       dtuple_field;   /* current field in logical record */
 
981
        ulint           dtuple_f_len;   /* the length of the current field
 
982
                                        in the logical record */
 
983
        byte*           dtuple_f_data;  /* pointer to the current logical
 
984
                                        field data */
 
985
        ulint           rec_f_len;      /* length of current field in rec */
 
986
        byte*           rec_f_data;     /* pointer to the current rec field */
 
987
        int             ret = 3333;     /* return value */
 
988
        ulint           cur_field;      /* current field number */
 
989
 
 
990
        ut_ad(dtuple && rec && matched_fields);
 
991
        ut_ad(dtuple_check_typed(dtuple));
 
992
        ut_ad(rec_offs_validate(rec, NULL, offsets));
 
993
 
 
994
        ut_ad(*matched_fields <= dtuple_get_n_fields_cmp(dtuple));
 
995
        ut_ad(*matched_fields <= rec_offs_n_fields(offsets));
 
996
 
 
997
        cur_field = *matched_fields;
 
998
 
 
999
        if (cur_field == 0) {
 
1000
                if (rec_get_info_bits(rec, rec_offs_comp(offsets))
 
1001
                    & REC_INFO_MIN_REC_FLAG) {
 
1002
 
 
1003
                        ret = !(dtuple_get_info_bits(dtuple)
 
1004
                                & REC_INFO_MIN_REC_FLAG);
 
1005
 
 
1006
                        goto order_resolved;
 
1007
                }
 
1008
 
 
1009
                if (dtuple_get_info_bits(dtuple) & REC_INFO_MIN_REC_FLAG) {
 
1010
                        ret = -1;
 
1011
 
 
1012
                        goto order_resolved;
 
1013
                }
 
1014
        }
 
1015
 
 
1016
        /* Match fields in a loop; stop if we run out of fields in dtuple */
 
1017
 
 
1018
        while (cur_field < dtuple_get_n_fields_cmp(dtuple)) {
 
1019
 
 
1020
                ulint   mtype;
 
1021
                ulint   prtype;
 
1022
 
 
1023
                dtuple_field = dtuple_get_nth_field(dtuple, cur_field);
 
1024
                {
 
1025
                        const dtype_t*  type
 
1026
                                = dfield_get_type(dtuple_field);
 
1027
 
 
1028
                        mtype = type->mtype;
 
1029
                        prtype = type->prtype;
 
1030
                }
 
1031
 
 
1032
                dtuple_f_data = dfield_get_data(dtuple_field);
 
1033
                dtuple_f_len = dfield_get_len(dtuple_field);
 
1034
 
 
1035
                rec_f_data = rec_get_nth_field(rec, offsets,
 
1036
                                               cur_field, &rec_f_len);
 
1037
 
 
1038
                if (rec_offs_nth_extern(offsets, cur_field)) {
 
1039
                        /* We do not compare to an externally stored field */
 
1040
 
 
1041
                        ret = 0;
 
1042
 
 
1043
                        goto order_resolved;
 
1044
                }
 
1045
 
 
1046
                ret = cmp_data_data(mtype, prtype, dtuple_f_data, dtuple_f_len,
 
1047
                                    rec_f_data, rec_f_len);
 
1048
                if (ret != 0) {
 
1049
                        goto order_resolved;
 
1050
                }
 
1051
 
 
1052
                cur_field++;
 
1053
        }
 
1054
 
 
1055
        ret = 0;        /* If we ran out of fields, dtuple was equal to rec
 
1056
                        up to the common fields */
 
1057
order_resolved:
 
1058
        ut_ad((ret >= - 1) && (ret <= 1));
 
1059
 
 
1060
        *matched_fields = cur_field;
 
1061
 
 
1062
        return(ret);
 
1063
}
 
1064
#endif /* UNIV_DEBUG */