mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / storage / innobase / rem / rem0cmp.c
blob2939c119e2ec5d3f73a1e39d3a5e04db3e1f876d
1 /***********************************************************************
2 Comparison services for records
4 (c) 1994-1996 Innobase Oy
6 Created 7/1/1994 Heikki Tuuri
7 ************************************************************************/
9 #include "rem0cmp.h"
11 #ifdef UNIV_NONINL
12 #include "rem0cmp.ic"
13 #endif
15 #include "srv0srv.h"
17 /* ALPHABETICAL ORDER
18 ==================
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.
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. */
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 */
91 return((ulint) srv_latin1_ordering[code]);
94 /*****************************************************************
95 Returns TRUE if two columns are equal for comparison purposes. */
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 */
107 if (dtype_is_non_binary_string_type(col1->mtype, col1->prtype)
108 && dtype_is_non_binary_string_type(col2->mtype, col2->prtype)) {
110 /* Both are non-binary string types: they can be compared if
111 and only if the charset-collation is the same */
113 if (check_charsets) {
114 return(dtype_get_charset_coll(col1->prtype)
115 == dtype_get_charset_coll(col2->prtype));
116 } else {
117 return(TRUE);
121 if (dtype_is_binary_string_type(col1->mtype, col1->prtype)
122 && dtype_is_binary_string_type(col2->mtype, col2->prtype)) {
124 /* Both are binary string types: they can be compared */
126 return(TRUE);
129 if (col1->mtype != col2->mtype) {
131 return(FALSE);
134 if (col1->mtype == DATA_INT
135 && (col1->prtype & DATA_UNSIGNED)
136 != (col2->prtype & DATA_UNSIGNED)) {
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. */
142 return(FALSE);
145 return(col1->mtype != DATA_INT || col1->len == col2->len);
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
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 */
167 float f_1;
168 float f_2;
169 double d_1;
170 double d_2;
171 int swap_flag = 1;
173 switch (mtype) {
175 case DATA_DECIMAL:
176 /* Remove preceding spaces */
177 for (; a_length && *a == ' '; a++, a_length--);
178 for (; b_length && *b == ' '; b++, b_length--);
180 if (*a == '-') {
181 if (*b != '-') {
182 return(-1);
185 a++; b++;
186 a_length--;
187 b_length--;
189 swap_flag = -1;
191 } else if (*b == '-') {
193 return(1);
196 while (a_length > 0 && (*a == '+' || *a == '0')) {
197 a++; a_length--;
200 while (b_length > 0 && (*b == '+' || *b == '0')) {
201 b++; b_length--;
204 if (a_length != b_length) {
205 if (a_length < b_length) {
206 return(-swap_flag);
209 return(swap_flag);
212 while (a_length > 0 && *a == *b) {
214 a++; b++; a_length--;
217 if (a_length == 0) {
219 return(0);
222 if (*a > *b) {
223 return(swap_flag);
226 return(-swap_flag);
227 case DATA_DOUBLE:
228 d_1 = mach_double_read(a);
229 d_2 = mach_double_read(b);
231 if (d_1 > d_2) {
232 return(1);
233 } else if (d_2 > d_1) {
234 return(-1);
237 return(0);
239 case DATA_FLOAT:
240 f_1 = mach_float_read(a);
241 f_2 = mach_float_read(b);
243 if (f_1 > f_2) {
244 return(1);
245 } else if (f_2 > f_1) {
246 return(-1);
249 return(0);
250 case DATA_BLOB:
251 if (prtype & DATA_BINARY_TYPE) {
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");
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;
273 return(0);
275 #endif /* !UNIV_HOTBACKUP */
277 /*****************************************************************
278 This function is used to compare two data fields for which we know the
279 data type. */
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 */
295 #ifndef UNIV_HOTBACKUP
296 ulint data1_byte;
297 ulint data2_byte;
298 ulint cur_bytes;
300 if (len1 == UNIV_SQL_NULL || len2 == UNIV_SQL_NULL) {
302 if (len1 == len2) {
304 return(0);
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 */
311 return(-1);
314 return(1);
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)) {
323 return(cmp_whole_field(mtype, prtype,
324 data1, (unsigned) len1,
325 data2, (unsigned) len2));
328 /* Compare then the fields */
330 cur_bytes = 0;
332 for (;;) {
333 if (len1 <= cur_bytes) {
334 if (len2 <= cur_bytes) {
336 return(0);
339 data1_byte = dtype_get_pad_char(mtype, prtype);
341 if (data1_byte == ULINT_UNDEFINED) {
343 return(-1);
345 } else {
346 data1_byte = *data1;
349 if (len2 <= cur_bytes) {
350 data2_byte = dtype_get_pad_char(mtype, prtype);
352 if (data2_byte == ULINT_UNDEFINED) {
354 return(1);
356 } else {
357 data2_byte = *data2;
360 if (data1_byte == data2_byte) {
361 /* If the bytes are equal, they will remain such even
362 after the collation transformation below */
364 goto next_byte;
367 if (mtype <= DATA_CHAR
368 || (mtype == DATA_BLOB
369 && 0 == (prtype & DATA_BINARY_TYPE))) {
371 data1_byte = cmp_collate(data1_byte);
372 data2_byte = cmp_collate(data2_byte);
375 if (data1_byte > data2_byte) {
377 return(1);
378 } else if (data1_byte < data2_byte) {
380 return(-1);
382 next_byte:
383 /* Next byte */
384 cur_bytes++;
385 data1++;
386 data2++;
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 */
395 return(0); /* Not reached */
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. */
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 */
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 */
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));
451 cur_field = *matched_fields;
452 cur_bytes = *matched_bytes;
454 ut_ad(cur_field <= dtuple_get_n_fields_cmp(dtuple));
455 ut_ad(cur_field <= rec_offs_n_fields(offsets));
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);
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;
471 /* Match fields in a loop; stop if we run out of fields in dtuple
472 or find an externally stored field */
474 while (cur_field < dtuple_get_n_fields_cmp(dtuple)) {
476 ulint mtype;
477 ulint prtype;
479 dtuple_field = dtuple_get_nth_field(dtuple, cur_field);
481 const dtype_t* type
482 = dfield_get_type(dtuple_field);
484 mtype = type->mtype;
485 prtype = type->prtype;
488 dtuple_f_len = dfield_get_len(dtuple_field);
490 rec_b_ptr = rec_get_nth_field(rec, offsets,
491 cur_field, &rec_f_len);
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 */
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 */
503 ret = 0;
505 goto order_resolved;
508 if (dtuple_f_len == UNIV_SQL_NULL) {
509 if (rec_f_len == UNIV_SQL_NULL) {
511 goto next_field;
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 */
521 ret = 1;
522 goto order_resolved;
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)) {
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);
537 if (ret != 0) {
538 cur_bytes = 0;
540 goto order_resolved;
541 } else {
542 goto next_field;
546 /* Set the pointers at the current byte */
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 */
553 for (;;) {
554 if (UNIV_UNLIKELY(rec_f_len <= cur_bytes)) {
555 if (dtuple_f_len <= cur_bytes) {
557 goto next_field;
560 rec_byte = dtype_get_pad_char(mtype, prtype);
562 if (rec_byte == ULINT_UNDEFINED) {
563 ret = 1;
565 goto order_resolved;
567 } else {
568 rec_byte = *rec_b_ptr;
571 if (UNIV_UNLIKELY(dtuple_f_len <= cur_bytes)) {
572 dtuple_byte = dtype_get_pad_char(mtype,
573 prtype);
575 if (dtuple_byte == ULINT_UNDEFINED) {
576 ret = -1;
578 goto order_resolved;
580 } else {
581 dtuple_byte = *dtuple_b_ptr;
584 if (dtuple_byte == rec_byte) {
585 /* If the bytes are equal, they will
586 remain such even after the collation
587 transformation below */
589 goto next_byte;
592 if (mtype <= DATA_CHAR
593 || (mtype == DATA_BLOB
594 && !(prtype & DATA_BINARY_TYPE))) {
596 rec_byte = cmp_collate(rec_byte);
597 dtuple_byte = cmp_collate(dtuple_byte);
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;
610 next_byte:
611 /* Next byte */
612 cur_bytes++;
613 rec_b_ptr++;
614 dtuple_b_ptr++;
617 next_field:
618 cur_field++;
619 cur_bytes = 0;
622 ut_ad(cur_bytes == 0);
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;
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 */
646 /******************************************************************
647 Compares a data tuple to a physical record. */
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() */
659 ulint matched_fields = 0;
660 ulint matched_bytes = 0;
662 ut_ad(rec_offs_validate(rec, NULL, offsets));
663 return(cmp_dtuple_rec_with_match(dtuple, rec, offsets,
664 &matched_fields, &matched_bytes));
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. */
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() */
679 ulint n_fields;
680 ulint matched_fields = 0;
681 ulint matched_bytes = 0;
683 ut_ad(rec_offs_validate(rec, NULL, offsets));
684 n_fields = dtuple_get_n_fields(dtuple);
686 if (n_fields > rec_offs_n_fields(offsets)) {
688 return(FALSE);
691 cmp_dtuple_rec_with_match(dtuple, rec, offsets,
692 &matched_fields, &matched_bytes);
693 if (matched_fields == n_fields) {
695 return(TRUE);
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);
704 return(FALSE);
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. */
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 ibool nulls_unequal,
724 /* in: TRUE if this is for index statistics
725 cardinality estimation, and innodb_stats_method
726 is "nulls_unequal" or "nulls_ignored" */
727 ulint* matched_fields, /* in/out: number of already completely
728 matched fields; when the function returns,
729 contains the value the for current
730 comparison */
731 ulint* matched_bytes) /* in/out: number of already matched
732 bytes within the first field not completely
733 matched; when the function returns, contains
734 the value for the current comparison */
736 #ifndef UNIV_HOTBACKUP
737 ulint rec1_n_fields; /* the number of fields in rec */
738 ulint rec1_f_len; /* length of current field in rec */
739 byte* rec1_b_ptr; /* pointer to the current byte in rec field */
740 ulint rec1_byte; /* value of current byte to be compared in
741 rec */
742 ulint rec2_n_fields; /* the number of fields in rec */
743 ulint rec2_f_len; /* length of current field in rec */
744 byte* rec2_b_ptr; /* pointer to the current byte in rec field */
745 ulint rec2_byte; /* value of current byte to be compared in
746 rec */
747 ulint cur_field; /* current field number */
748 ulint cur_bytes; /* number of already matched bytes in current
749 field */
750 int ret = 3333; /* return value */
751 ulint comp;
753 ut_ad(rec1 && rec2 && index);
754 ut_ad(rec_offs_validate(rec1, index, offsets1));
755 ut_ad(rec_offs_validate(rec2, index, offsets2));
756 ut_ad(rec_offs_comp(offsets1) == rec_offs_comp(offsets2));
758 comp = rec_offs_comp(offsets1);
759 rec1_n_fields = rec_offs_n_fields(offsets1);
760 rec2_n_fields = rec_offs_n_fields(offsets2);
762 cur_field = *matched_fields;
763 cur_bytes = *matched_bytes;
765 /* Match fields in a loop */
767 while ((cur_field < rec1_n_fields) && (cur_field < rec2_n_fields)) {
769 ulint mtype;
770 ulint prtype;
772 if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
773 /* This is for the insert buffer B-tree. */
774 mtype = DATA_BINARY;
775 prtype = 0;
776 } else {
777 const dict_col_t* col
778 = dict_index_get_nth_col(index, cur_field);
780 mtype = col->mtype;
781 prtype = col->prtype;
784 rec1_b_ptr = rec_get_nth_field(rec1, offsets1,
785 cur_field, &rec1_f_len);
786 rec2_b_ptr = rec_get_nth_field(rec2, offsets2,
787 cur_field, &rec2_f_len);
789 if (cur_bytes == 0) {
790 if (cur_field == 0) {
791 /* Test if rec is the predefined minimum
792 record */
793 if (rec_get_info_bits(rec1, comp)
794 & REC_INFO_MIN_REC_FLAG) {
796 if (rec_get_info_bits(rec2, comp)
797 & REC_INFO_MIN_REC_FLAG) {
798 ret = 0;
799 } else {
800 ret = -1;
803 goto order_resolved;
805 } else if (rec_get_info_bits(rec2, comp)
806 & REC_INFO_MIN_REC_FLAG) {
808 ret = 1;
810 goto order_resolved;
814 if (rec_offs_nth_extern(offsets1, cur_field)
815 || rec_offs_nth_extern(offsets2, cur_field)) {
816 /* We do not compare to an externally
817 stored field */
819 ret = 0;
821 goto order_resolved;
824 if (rec1_f_len == UNIV_SQL_NULL
825 || rec2_f_len == UNIV_SQL_NULL) {
827 if (rec1_f_len == rec2_f_len) {
828 /* This is limited to stats collection,
829 cannot use it for regular search */
830 if (nulls_unequal) {
831 ret = -1;
832 } else {
833 goto next_field;
835 } else if (rec2_f_len == UNIV_SQL_NULL) {
837 /* We define the SQL null to be the
838 smallest possible value of a field
839 in the alphabetical order */
841 ret = 1;
842 } else {
843 ret = -1;
846 goto order_resolved;
850 if (mtype >= DATA_FLOAT
851 || (mtype == DATA_BLOB
852 && 0 == (prtype & DATA_BINARY_TYPE)
853 && dtype_get_charset_coll(prtype)
854 != DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL)) {
856 ret = cmp_whole_field(mtype, prtype,
857 rec1_b_ptr,
858 (unsigned) rec1_f_len,
859 rec2_b_ptr,
860 (unsigned) rec2_f_len);
861 if (ret != 0) {
862 cur_bytes = 0;
864 goto order_resolved;
865 } else {
866 goto next_field;
870 /* Set the pointers at the current byte */
871 rec1_b_ptr = rec1_b_ptr + cur_bytes;
872 rec2_b_ptr = rec2_b_ptr + cur_bytes;
874 /* Compare then the fields */
875 for (;;) {
876 if (rec2_f_len <= cur_bytes) {
878 if (rec1_f_len <= cur_bytes) {
880 goto next_field;
883 rec2_byte = dtype_get_pad_char(mtype, prtype);
885 if (rec2_byte == ULINT_UNDEFINED) {
886 ret = 1;
888 goto order_resolved;
890 } else {
891 rec2_byte = *rec2_b_ptr;
894 if (rec1_f_len <= cur_bytes) {
895 rec1_byte = dtype_get_pad_char(mtype, prtype);
897 if (rec1_byte == ULINT_UNDEFINED) {
898 ret = -1;
900 goto order_resolved;
902 } else {
903 rec1_byte = *rec1_b_ptr;
906 if (rec1_byte == rec2_byte) {
907 /* If the bytes are equal, they will remain
908 such even after the collation transformation
909 below */
911 goto next_byte;
914 if (mtype <= DATA_CHAR
915 || (mtype == DATA_BLOB
916 && !(prtype & DATA_BINARY_TYPE))) {
918 rec1_byte = cmp_collate(rec1_byte);
919 rec2_byte = cmp_collate(rec2_byte);
922 if (rec1_byte < rec2_byte) {
923 ret = -1;
924 goto order_resolved;
925 } else if (rec1_byte > rec2_byte) {
926 ret = 1;
927 goto order_resolved;
929 next_byte:
930 /* Next byte */
932 cur_bytes++;
933 rec1_b_ptr++;
934 rec2_b_ptr++;
937 next_field:
938 cur_field++;
939 cur_bytes = 0;
942 ut_ad(cur_bytes == 0);
944 ret = 0; /* If we ran out of fields, rec1 was equal to rec2 up
945 to the common fields */
946 order_resolved:
948 ut_ad((ret >= - 1) && (ret <= 1));
950 *matched_fields = cur_field;
951 *matched_bytes = cur_bytes;
953 return(ret);
954 #else /* !UNIV_HOTBACKUP */
955 /* This function depends on MySQL code that is not included in
956 InnoDB Hot Backup builds. Besides, this function should never
957 be called in InnoDB Hot Backup. */
958 ut_error;
959 return(0);
960 #endif /* !UNIV_HOTBACKUP */
963 #ifdef UNIV_DEBUG
964 /*****************************************************************
965 Used in debug checking of cmp_dtuple_... .
966 This function is used to compare a data tuple to a physical record. If
967 dtuple has n fields then rec must have either m >= n fields, or it must
968 differ from dtuple in some of the m fields rec has. If encounters an
969 externally stored field, returns 0. */
970 static
972 cmp_debug_dtuple_rec_with_match(
973 /*============================*/
974 /* out: 1, 0, -1, if dtuple is greater, equal,
975 less than rec, respectively, when only the
976 common first fields are compared */
977 dtuple_t* dtuple, /* in: data tuple */
978 rec_t* rec, /* in: physical record which differs from
979 dtuple in some of the common fields, or which
980 has an equal number or more fields than
981 dtuple */
982 const ulint* offsets,/* in: array returned by rec_get_offsets() */
983 ulint* matched_fields) /* in/out: number of already
984 completely matched fields; when function
985 returns, contains the value for current
986 comparison */
988 dfield_t* dtuple_field; /* current field in logical record */
989 ulint dtuple_f_len; /* the length of the current field
990 in the logical record */
991 byte* dtuple_f_data; /* pointer to the current logical
992 field data */
993 ulint rec_f_len; /* length of current field in rec */
994 byte* rec_f_data; /* pointer to the current rec field */
995 int ret = 3333; /* return value */
996 ulint cur_field; /* current field number */
998 ut_ad(dtuple && rec && matched_fields);
999 ut_ad(dtuple_check_typed(dtuple));
1000 ut_ad(rec_offs_validate(rec, NULL, offsets));
1002 ut_ad(*matched_fields <= dtuple_get_n_fields_cmp(dtuple));
1003 ut_ad(*matched_fields <= rec_offs_n_fields(offsets));
1005 cur_field = *matched_fields;
1007 if (cur_field == 0) {
1008 if (rec_get_info_bits(rec, rec_offs_comp(offsets))
1009 & REC_INFO_MIN_REC_FLAG) {
1011 ret = !(dtuple_get_info_bits(dtuple)
1012 & REC_INFO_MIN_REC_FLAG);
1014 goto order_resolved;
1017 if (dtuple_get_info_bits(dtuple) & REC_INFO_MIN_REC_FLAG) {
1018 ret = -1;
1020 goto order_resolved;
1024 /* Match fields in a loop; stop if we run out of fields in dtuple */
1026 while (cur_field < dtuple_get_n_fields_cmp(dtuple)) {
1028 ulint mtype;
1029 ulint prtype;
1031 dtuple_field = dtuple_get_nth_field(dtuple, cur_field);
1033 const dtype_t* type
1034 = dfield_get_type(dtuple_field);
1036 mtype = type->mtype;
1037 prtype = type->prtype;
1040 dtuple_f_data = dfield_get_data(dtuple_field);
1041 dtuple_f_len = dfield_get_len(dtuple_field);
1043 rec_f_data = rec_get_nth_field(rec, offsets,
1044 cur_field, &rec_f_len);
1046 if (rec_offs_nth_extern(offsets, cur_field)) {
1047 /* We do not compare to an externally stored field */
1049 ret = 0;
1051 goto order_resolved;
1054 ret = cmp_data_data(mtype, prtype, dtuple_f_data, dtuple_f_len,
1055 rec_f_data, rec_f_len);
1056 if (ret != 0) {
1057 goto order_resolved;
1060 cur_field++;
1063 ret = 0; /* If we ran out of fields, dtuple was equal to rec
1064 up to the common fields */
1065 order_resolved:
1066 ut_ad((ret >= - 1) && (ret <= 1));
1068 *matched_fields = cur_field;
1070 return(ret);
1072 #endif /* UNIV_DEBUG */