~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Padraig O'Sullivan
  • Date: 2009-09-13 01:03:01 UTC
  • mto: (1126.9.2 captain-20090915-01)
  • mto: This revision was merged to the branch mainline in revision 1133.
  • Revision ID: osullivan.padraig@gmail.com-20090913010301-tcvvezipx1124acy
Added calls to the dtrace delete begin/end probes.

Show diffs side-by-side

added added

removed removed

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