1 /*****************************************************************************
3 Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved.
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.
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.
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.,
15 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 *****************************************************************************/
19 /*******************************************************************//**
21 Comparison services for records
23 Created 7/1/1994 Heikki Tuuri
24 ************************************************************************/
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
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.
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. */
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 */
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
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
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 one in ha_innobase.cc!
80 @return 1, 0, -1, if a is greater, equal, less than b, respectively */
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,
90 const unsigned char* b
, /*!< in: data field */
91 unsigned int b_length
); /*!< in: data field length,
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 */
102 ulint code
) /*!< in: code of a character stored in database record */
104 return((ulint
) srv_latin1_ordering
[code
]);
107 /*************************************************************//**
108 Returns TRUE if two columns are equal for comparison purposes.
109 @return TRUE if the columns are considered equal in comparisons */
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 */
119 if (dtype_is_non_binary_string_type(col1
->mtype
, col1
->prtype
)
120 && dtype_is_non_binary_string_type(col2
->mtype
, col2
->prtype
)) {
122 /* Both are non-binary string types: they can be compared if
123 and only if the charset-collation is the same */
125 if (check_charsets
) {
126 return(dtype_get_charset_coll(col1
->prtype
)
127 == dtype_get_charset_coll(col2
->prtype
));
133 if (dtype_is_binary_string_type(col1
->mtype
, col1
->prtype
)
134 && dtype_is_binary_string_type(col2
->mtype
, col2
->prtype
)) {
136 /* Both are binary string types: they can be compared */
141 if (col1
->mtype
!= col2
->mtype
) {
146 if (col1
->mtype
== DATA_INT
147 && (col1
->prtype
& DATA_UNSIGNED
)
148 != (col2
->prtype
& DATA_UNSIGNED
)) {
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. */
157 return(col1
->mtype
!= DATA_INT
|| col1
->len
== col2
->len
);
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 */
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,
173 const byte
* b
, /*!< in: data field */
174 unsigned int b_length
) /*!< in: data field length,
186 /* Remove preceding spaces */
187 for (; a_length
&& *a
== ' '; a
++, a_length
--);
188 for (; b_length
&& *b
== ' '; b
++, b_length
--);
201 } else if (*b
== '-') {
206 while (a_length
> 0 && (*a
== '+' || *a
== '0')) {
210 while (b_length
> 0 && (*b
== '+' || *b
== '0')) {
214 if (a_length
!= b_length
) {
215 if (a_length
< b_length
) {
222 while (a_length
> 0 && *a
== *b
) {
224 a
++; b
++; a_length
--;
238 d_1
= mach_double_read(a
);
239 d_2
= mach_double_read(b
);
243 } else if (d_2
> d_1
) {
250 f_1
= mach_float_read(a
);
251 f_2
= mach_float_read(b
);
255 } else if (f_2
> f_1
) {
261 if (prtype
& DATA_BINARY_TYPE
) {
263 ut_print_timestamp(stderr
);
265 " InnoDB: Error: comparing a binary BLOB"
266 " with a character set sensitive\n"
267 "InnoDB: comparison!\n");
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
));
278 "InnoDB: unknown type number %lu\n",
286 /*************************************************************//**
287 This function is used to compare two data fields for which we know the
289 @return 1, 0, -1, if data1 is greater, equal, less than data2, respectively */
294 ulint mtype
, /*!< in: main type */
295 ulint prtype
, /*!< in: precise type */
296 const byte
* data1
, /*!< in: data field (== a pointer to a memory
298 ulint len1
, /*!< in: data field length or UNIV_SQL_NULL */
299 const byte
* data2
, /*!< in: data field (== a pointer to a memory
301 ulint len2
) /*!< in: data field length or UNIV_SQL_NULL */
307 if (len1
== UNIV_SQL_NULL
|| len2
== UNIV_SQL_NULL
) {
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 */
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
)) {
330 return(cmp_whole_field(mtype
, prtype
,
331 data1
, (unsigned) len1
,
332 data2
, (unsigned) len2
));
335 /* Compare then the fields */
340 if (len1
<= cur_bytes
) {
341 if (len2
<= cur_bytes
) {
346 data1_byte
= dtype_get_pad_char(mtype
, prtype
);
348 if (data1_byte
== ULINT_UNDEFINED
) {
356 if (len2
<= cur_bytes
) {
357 data2_byte
= dtype_get_pad_char(mtype
, prtype
);
359 if (data2_byte
== ULINT_UNDEFINED
) {
367 if (data1_byte
== data2_byte
) {
368 /* If the bytes are equal, they will remain such even
369 after the collation transformation below */
374 if (mtype
<= DATA_CHAR
375 || (mtype
== DATA_BLOB
376 && 0 == (prtype
& DATA_BINARY_TYPE
))) {
378 data1_byte
= cmp_collate(data1_byte
);
379 data2_byte
= cmp_collate(data2_byte
);
382 if (data1_byte
> data2_byte
) {
385 } else if (data1_byte
< data2_byte
) {
396 return(0); /* Not reached */
399 /*************************************************************//**
400 This function is used to compare a data tuple to a physical record.
401 Only dtuple->n_fields_cmp first fields are taken into account for
402 the data tuple! If we denote by n = n_fields_cmp, then rec must
403 have either m >= n fields, or it must differ from dtuple in some of
404 the m fields rec has. If rec has an externally stored field we do not
405 compare it but return with value 0 if such a comparison should be
407 @return 1, 0, -1, if dtuple is greater, equal, less than rec,
408 respectively, when only the common first fields are compared, or until
409 the first externally stored field in rec */
412 cmp_dtuple_rec_with_match(
413 /*======================*/
414 const dtuple_t
* dtuple
, /*!< in: data tuple */
415 const rec_t
* rec
, /*!< in: physical record which differs from
416 dtuple in some of the common fields, or which
417 has an equal number or more fields than
419 const ulint
* offsets
,/*!< in: array returned by rec_get_offsets() */
420 ulint
* matched_fields
, /*!< in/out: number of already completely
421 matched fields; when function returns,
422 contains the value for current comparison */
423 ulint
* matched_bytes
) /*!< in/out: number of already matched
424 bytes within the first field not completely
425 matched; when function returns, contains the
426 value for current comparison */
428 const dfield_t
* dtuple_field
; /* current field in logical record */
429 ulint dtuple_f_len
; /* the length of the current field
430 in the logical record */
431 const byte
* dtuple_b_ptr
; /* pointer to the current byte in
432 logical field data */
433 ulint dtuple_byte
; /* value of current byte to be compared
435 ulint rec_f_len
; /* length of current field in rec */
436 const byte
* rec_b_ptr
; /* pointer to the current byte in
438 ulint rec_byte
; /* value of current byte to be
440 ulint cur_field
; /* current field number */
441 ulint cur_bytes
; /* number of already matched bytes
443 int ret
= 3333; /* return value */
445 ut_ad(dtuple
&& rec
&& matched_fields
&& matched_bytes
);
446 ut_ad(dtuple_check_typed(dtuple
));
447 ut_ad(rec_offs_validate(rec
, NULL
, offsets
));
449 cur_field
= *matched_fields
;
450 cur_bytes
= *matched_bytes
;
452 ut_ad(cur_field
<= dtuple_get_n_fields_cmp(dtuple
));
453 ut_ad(cur_field
<= rec_offs_n_fields(offsets
));
455 if (cur_bytes
== 0 && cur_field
== 0) {
456 ulint rec_info
= rec_get_info_bits(rec
,
457 rec_offs_comp(offsets
));
458 ulint tup_info
= dtuple_get_info_bits(dtuple
);
460 if (UNIV_UNLIKELY(rec_info
& REC_INFO_MIN_REC_FLAG
)) {
461 ret
= !(tup_info
& REC_INFO_MIN_REC_FLAG
);
463 } else if (UNIV_UNLIKELY(tup_info
& REC_INFO_MIN_REC_FLAG
)) {
469 /* Match fields in a loop; stop if we run out of fields in dtuple
470 or find an externally stored field */
472 while (cur_field
< dtuple_get_n_fields_cmp(dtuple
)) {
477 dtuple_field
= dtuple_get_nth_field(dtuple
, cur_field
);
480 = dfield_get_type(dtuple_field
);
483 prtype
= type
->prtype
;
486 dtuple_f_len
= dfield_get_len(dtuple_field
);
488 rec_b_ptr
= rec_get_nth_field(rec
, offsets
,
489 cur_field
, &rec_f_len
);
491 /* If we have matched yet 0 bytes, it may be that one or
492 both the fields are SQL null, or the record or dtuple may be
493 the predefined minimum record, or the field is externally
496 if (UNIV_LIKELY(cur_bytes
== 0)) {
497 if (rec_offs_nth_extern(offsets
, cur_field
)) {
498 /* We do not compare to an externally
506 if (dtuple_f_len
== UNIV_SQL_NULL
) {
507 if (rec_f_len
== UNIV_SQL_NULL
) {
514 } else if (rec_f_len
== UNIV_SQL_NULL
) {
515 /* We define the SQL null to be the
516 smallest possible value of a field
517 in the alphabetical order */
524 if (mtype
>= DATA_FLOAT
525 || (mtype
== DATA_BLOB
526 && 0 == (prtype
& DATA_BINARY_TYPE
)
527 && dtype_get_charset_coll(prtype
)
528 != DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL
)) {
530 ret
= cmp_whole_field(mtype
, prtype
,
531 dfield_get_data(dtuple_field
),
532 (unsigned) dtuple_f_len
,
533 rec_b_ptr
, (unsigned) rec_f_len
);
544 /* Set the pointers at the current byte */
546 rec_b_ptr
= rec_b_ptr
+ cur_bytes
;
547 dtuple_b_ptr
= (byte
*)dfield_get_data(dtuple_field
)
549 /* Compare then the fields */
552 if (UNIV_UNLIKELY(rec_f_len
<= cur_bytes
)) {
553 if (dtuple_f_len
<= cur_bytes
) {
558 rec_byte
= dtype_get_pad_char(mtype
, prtype
);
560 if (rec_byte
== ULINT_UNDEFINED
) {
566 rec_byte
= *rec_b_ptr
;
569 if (UNIV_UNLIKELY(dtuple_f_len
<= cur_bytes
)) {
570 dtuple_byte
= dtype_get_pad_char(mtype
,
573 if (dtuple_byte
== ULINT_UNDEFINED
) {
579 dtuple_byte
= *dtuple_b_ptr
;
582 if (dtuple_byte
== rec_byte
) {
583 /* If the bytes are equal, they will
584 remain such even after the collation
585 transformation below */
590 if (mtype
<= DATA_CHAR
591 || (mtype
== DATA_BLOB
592 && !(prtype
& DATA_BINARY_TYPE
))) {
594 rec_byte
= cmp_collate(rec_byte
);
595 dtuple_byte
= cmp_collate(dtuple_byte
);
598 ret
= (int) (dtuple_byte
- rec_byte
);
599 if (UNIV_LIKELY(ret
)) {
620 ut_ad(cur_bytes
== 0);
622 ret
= 0; /* If we ran out of fields, dtuple was equal to rec
623 up to the common fields */
625 ut_ad((ret
>= - 1) && (ret
<= 1));
626 ut_ad(ret
== cmp_debug_dtuple_rec_with_match(dtuple
, rec
, offsets
,
628 ut_ad(*matched_fields
== cur_field
); /* In the debug version, the
629 above cmp_debug_... sets
630 *matched_fields to a value */
631 *matched_fields
= cur_field
;
632 *matched_bytes
= cur_bytes
;
637 /**************************************************************//**
638 Compares a data tuple to a physical record.
639 @see cmp_dtuple_rec_with_match
640 @return 1, 0, -1, if dtuple is greater, equal, less than rec, respectively */
645 const dtuple_t
* dtuple
, /*!< in: data tuple */
646 const rec_t
* rec
, /*!< in: physical record */
647 const ulint
* offsets
)/*!< in: array returned by rec_get_offsets() */
649 ulint matched_fields
= 0;
650 ulint matched_bytes
= 0;
652 ut_ad(rec_offs_validate(rec
, NULL
, offsets
));
653 return(cmp_dtuple_rec_with_match(dtuple
, rec
, offsets
,
654 &matched_fields
, &matched_bytes
));
657 /**************************************************************//**
658 Checks if a dtuple is a prefix of a record. The last field in dtuple
659 is allowed to be a prefix of the corresponding field in the record.
660 @return TRUE if prefix */
663 cmp_dtuple_is_prefix_of_rec(
664 /*========================*/
665 const dtuple_t
* dtuple
, /*!< in: data tuple */
666 const rec_t
* rec
, /*!< in: physical record */
667 const ulint
* offsets
)/*!< in: array returned by rec_get_offsets() */
670 ulint matched_fields
= 0;
671 ulint matched_bytes
= 0;
673 ut_ad(rec_offs_validate(rec
, NULL
, offsets
));
674 n_fields
= dtuple_get_n_fields(dtuple
);
676 if (n_fields
> rec_offs_n_fields(offsets
)) {
681 cmp_dtuple_rec_with_match(dtuple
, rec
, offsets
,
682 &matched_fields
, &matched_bytes
);
683 if (matched_fields
== n_fields
) {
688 if (matched_fields
== n_fields
- 1
689 && matched_bytes
== dfield_get_len(
690 dtuple_get_nth_field(dtuple
, n_fields
- 1))) {
697 /*************************************************************//**
698 Compare two physical records that contain the same number of columns,
699 none of which are stored externally.
700 @return 1, 0, -1 if rec1 is greater, equal, less, respectively, than rec2 */
705 const rec_t
* rec1
, /*!< in: physical record */
706 const rec_t
* rec2
, /*!< in: physical record */
707 const ulint
* offsets1
,/*!< in: rec_get_offsets(rec1, ...) */
708 const ulint
* offsets2
,/*!< in: rec_get_offsets(rec2, ...) */
709 const dict_index_t
* index
, /*!< in: data dictionary index */
710 ibool
* null_eq
)/*!< out: set to TRUE if
711 found matching null values */
713 ulint rec1_f_len
; /*!< length of current field in rec1 */
714 const byte
* rec1_b_ptr
; /*!< pointer to the current byte
716 ulint rec1_byte
; /*!< value of current byte to be
718 ulint rec2_f_len
; /*!< length of current field in rec2 */
719 const byte
* rec2_b_ptr
; /*!< pointer to the current byte
721 ulint rec2_byte
; /*!< value of current byte to be
723 ulint cur_field
; /*!< current field number */
726 n_uniq
= dict_index_get_n_unique(index
);
727 ut_ad(rec_offs_n_fields(offsets1
) >= n_uniq
);
728 ut_ad(rec_offs_n_fields(offsets2
) >= n_uniq
);
730 ut_ad(rec_offs_comp(offsets1
) == rec_offs_comp(offsets2
));
732 for (cur_field
= 0; cur_field
< n_uniq
; cur_field
++) {
739 const dict_col_t
* col
740 = dict_index_get_nth_col(index
, cur_field
);
743 prtype
= col
->prtype
;
746 ut_ad(!rec_offs_nth_extern(offsets1
, cur_field
));
747 ut_ad(!rec_offs_nth_extern(offsets2
, cur_field
));
749 rec1_b_ptr
= rec_get_nth_field(rec1
, offsets1
,
750 cur_field
, &rec1_f_len
);
751 rec2_b_ptr
= rec_get_nth_field(rec2
, offsets2
,
752 cur_field
, &rec2_f_len
);
754 if (rec1_f_len
== UNIV_SQL_NULL
755 || rec2_f_len
== UNIV_SQL_NULL
) {
757 if (rec1_f_len
== rec2_f_len
) {
764 } else if (rec2_f_len
== UNIV_SQL_NULL
) {
766 /* We define the SQL null to be the
767 smallest possible value of a field
768 in the alphabetical order */
776 if (mtype
>= DATA_FLOAT
777 || (mtype
== DATA_BLOB
778 && 0 == (prtype
& DATA_BINARY_TYPE
)
779 && dtype_get_charset_coll(prtype
)
780 != DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL
)) {
781 int ret
= cmp_whole_field(mtype
, prtype
,
783 (unsigned) rec1_f_len
,
785 (unsigned) rec2_f_len
);
793 /* Compare the fields */
794 for (cur_bytes
= 0;; cur_bytes
++, rec1_b_ptr
++, rec2_b_ptr
++) {
795 if (rec2_f_len
<= cur_bytes
) {
797 if (rec1_f_len
<= cur_bytes
) {
802 rec2_byte
= dtype_get_pad_char(mtype
, prtype
);
804 if (rec2_byte
== ULINT_UNDEFINED
) {
808 rec2_byte
= *rec2_b_ptr
;
811 if (rec1_f_len
<= cur_bytes
) {
812 rec1_byte
= dtype_get_pad_char(mtype
, prtype
);
814 if (rec1_byte
== ULINT_UNDEFINED
) {
818 rec1_byte
= *rec1_b_ptr
;
821 if (rec1_byte
== rec2_byte
) {
822 /* If the bytes are equal, they will remain
823 such even after the collation transformation
829 if (mtype
<= DATA_CHAR
830 || (mtype
== DATA_BLOB
831 && !(prtype
& DATA_BINARY_TYPE
))) {
833 rec1_byte
= cmp_collate(rec1_byte
);
834 rec2_byte
= cmp_collate(rec2_byte
);
837 if (rec1_byte
< rec2_byte
) {
839 } else if (rec1_byte
> rec2_byte
) {
847 /* If we ran out of fields, rec1 was equal to rec2. */
851 /*************************************************************//**
852 This function is used to compare two physical records. Only the common
853 first fields are compared, and if an externally stored field is
854 encountered, then 0 is returned.
855 @return 1, 0, -1 if rec1 is greater, equal, less, respectively */
858 cmp_rec_rec_with_match(
859 /*===================*/
860 const rec_t
* rec1
, /*!< in: physical record */
861 const rec_t
* rec2
, /*!< in: physical record */
862 const ulint
* offsets1
,/*!< in: rec_get_offsets(rec1, index) */
863 const ulint
* offsets2
,/*!< in: rec_get_offsets(rec2, index) */
864 dict_index_t
* index
, /*!< in: data dictionary index */
866 /* in: TRUE if this is for index statistics
867 cardinality estimation, and innodb_stats_method
868 is "nulls_unequal" or "nulls_ignored" */
869 ulint
* matched_fields
, /*!< in/out: number of already completely
870 matched fields; when the function returns,
871 contains the value the for current
873 ulint
* matched_bytes
) /*!< in/out: number of already matched
874 bytes within the first field not completely
875 matched; when the function returns, contains
876 the value for the current comparison */
878 ulint rec1_n_fields
; /* the number of fields in rec */
879 ulint rec1_f_len
; /* length of current field in rec */
880 const byte
* rec1_b_ptr
; /* pointer to the current byte
882 ulint rec1_byte
; /* value of current byte to be
884 ulint rec2_n_fields
; /* the number of fields in rec */
885 ulint rec2_f_len
; /* length of current field in rec */
886 const byte
* rec2_b_ptr
; /* pointer to the current byte
888 ulint rec2_byte
; /* value of current byte to be
890 ulint cur_field
; /* current field number */
891 ulint cur_bytes
; /* number of already matched
892 bytes in current field */
893 int ret
= 0; /* return value */
896 ut_ad(rec1
&& rec2
&& index
);
897 ut_ad(rec_offs_validate(rec1
, index
, offsets1
));
898 ut_ad(rec_offs_validate(rec2
, index
, offsets2
));
899 ut_ad(rec_offs_comp(offsets1
) == rec_offs_comp(offsets2
));
901 comp
= rec_offs_comp(offsets1
);
902 rec1_n_fields
= rec_offs_n_fields(offsets1
);
903 rec2_n_fields
= rec_offs_n_fields(offsets2
);
905 cur_field
= *matched_fields
;
906 cur_bytes
= *matched_bytes
;
908 /* Match fields in a loop */
910 while ((cur_field
< rec1_n_fields
) && (cur_field
< rec2_n_fields
)) {
915 if (UNIV_UNLIKELY(index
->type
& DICT_UNIVERSAL
)) {
916 /* This is for the insert buffer B-tree. */
920 const dict_col_t
* col
921 = dict_index_get_nth_col(index
, cur_field
);
924 prtype
= col
->prtype
;
927 rec1_b_ptr
= rec_get_nth_field(rec1
, offsets1
,
928 cur_field
, &rec1_f_len
);
929 rec2_b_ptr
= rec_get_nth_field(rec2
, offsets2
,
930 cur_field
, &rec2_f_len
);
932 if (cur_bytes
== 0) {
933 if (cur_field
== 0) {
934 /* Test if rec is the predefined minimum
936 if (UNIV_UNLIKELY(rec_get_info_bits(rec1
, comp
)
937 & REC_INFO_MIN_REC_FLAG
)) {
939 if (!(rec_get_info_bits(rec2
, comp
)
940 & REC_INFO_MIN_REC_FLAG
)) {
946 } else if (UNIV_UNLIKELY
947 (rec_get_info_bits(rec2
, comp
)
948 & REC_INFO_MIN_REC_FLAG
)) {
956 if (rec_offs_nth_extern(offsets1
, cur_field
)
957 || rec_offs_nth_extern(offsets2
, cur_field
)) {
958 /* We do not compare to an externally
964 if (rec1_f_len
== UNIV_SQL_NULL
965 || rec2_f_len
== UNIV_SQL_NULL
) {
967 if (rec1_f_len
== rec2_f_len
) {
968 /* This is limited to stats collection,
969 cannot use it for regular search */
975 } else if (rec2_f_len
== UNIV_SQL_NULL
) {
977 /* We define the SQL null to be the
978 smallest possible value of a field
979 in the alphabetical order */
990 if (mtype
>= DATA_FLOAT
991 || (mtype
== DATA_BLOB
992 && 0 == (prtype
& DATA_BINARY_TYPE
)
993 && dtype_get_charset_coll(prtype
)
994 != DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL
)) {
996 ret
= cmp_whole_field(mtype
, prtype
,
998 (unsigned) rec1_f_len
,
1000 (unsigned) rec2_f_len
);
1004 goto order_resolved
;
1010 /* Set the pointers at the current byte */
1011 rec1_b_ptr
= rec1_b_ptr
+ cur_bytes
;
1012 rec2_b_ptr
= rec2_b_ptr
+ cur_bytes
;
1014 /* Compare then the fields */
1016 if (rec2_f_len
<= cur_bytes
) {
1018 if (rec1_f_len
<= cur_bytes
) {
1023 rec2_byte
= dtype_get_pad_char(mtype
, prtype
);
1025 if (rec2_byte
== ULINT_UNDEFINED
) {
1028 goto order_resolved
;
1031 rec2_byte
= *rec2_b_ptr
;
1034 if (rec1_f_len
<= cur_bytes
) {
1035 rec1_byte
= dtype_get_pad_char(mtype
, prtype
);
1037 if (rec1_byte
== ULINT_UNDEFINED
) {
1040 goto order_resolved
;
1043 rec1_byte
= *rec1_b_ptr
;
1046 if (rec1_byte
== rec2_byte
) {
1047 /* If the bytes are equal, they will remain
1048 such even after the collation transformation
1054 if (mtype
<= DATA_CHAR
1055 || (mtype
== DATA_BLOB
1056 && !(prtype
& DATA_BINARY_TYPE
))) {
1058 rec1_byte
= cmp_collate(rec1_byte
);
1059 rec2_byte
= cmp_collate(rec2_byte
);
1062 if (rec1_byte
< rec2_byte
) {
1064 goto order_resolved
;
1065 } else if (rec1_byte
> rec2_byte
) {
1067 goto order_resolved
;
1082 ut_ad(cur_bytes
== 0);
1084 /* If we ran out of fields, rec1 was equal to rec2 up
1085 to the common fields */
1089 ut_ad((ret
>= - 1) && (ret
<= 1));
1091 *matched_fields
= cur_field
;
1092 *matched_bytes
= cur_bytes
;
1098 /*************************************************************//**
1099 Used in debug checking of cmp_dtuple_... .
1100 This function is used to compare a data tuple to a physical record. If
1101 dtuple has n fields then rec must have either m >= n fields, or it must
1102 differ from dtuple in some of the m fields rec has. If encounters an
1103 externally stored field, returns 0.
1104 @return 1, 0, -1, if dtuple is greater, equal, less than rec,
1105 respectively, when only the common first fields are compared */
1108 cmp_debug_dtuple_rec_with_match(
1109 /*============================*/
1110 const dtuple_t
* dtuple
, /*!< in: data tuple */
1111 const rec_t
* rec
, /*!< in: physical record which differs from
1112 dtuple in some of the common fields, or which
1113 has an equal number or more fields than
1115 const ulint
* offsets
,/*!< in: array returned by rec_get_offsets() */
1116 ulint
* matched_fields
) /*!< in/out: number of already
1117 completely matched fields; when function
1118 returns, contains the value for current
1121 const dfield_t
* dtuple_field
; /* current field in logical record */
1122 ulint dtuple_f_len
; /* the length of the current field
1123 in the logical record */
1124 const byte
* dtuple_f_data
; /* pointer to the current logical
1126 ulint rec_f_len
; /* length of current field in rec */
1127 const byte
* rec_f_data
; /* pointer to the current rec field */
1128 int ret
= 3333; /* return value */
1129 ulint cur_field
; /* current field number */
1131 ut_ad(dtuple
&& rec
&& matched_fields
);
1132 ut_ad(dtuple_check_typed(dtuple
));
1133 ut_ad(rec_offs_validate(rec
, NULL
, offsets
));
1135 ut_ad(*matched_fields
<= dtuple_get_n_fields_cmp(dtuple
));
1136 ut_ad(*matched_fields
<= rec_offs_n_fields(offsets
));
1138 cur_field
= *matched_fields
;
1140 if (cur_field
== 0) {
1142 (rec_get_info_bits(rec
, rec_offs_comp(offsets
))
1143 & REC_INFO_MIN_REC_FLAG
)) {
1145 ret
= !(dtuple_get_info_bits(dtuple
)
1146 & REC_INFO_MIN_REC_FLAG
);
1148 goto order_resolved
;
1152 (dtuple_get_info_bits(dtuple
) & REC_INFO_MIN_REC_FLAG
)) {
1155 goto order_resolved
;
1159 /* Match fields in a loop; stop if we run out of fields in dtuple */
1161 while (cur_field
< dtuple_get_n_fields_cmp(dtuple
)) {
1166 dtuple_field
= dtuple_get_nth_field(dtuple
, cur_field
);
1169 = dfield_get_type(dtuple_field
);
1171 mtype
= type
->mtype
;
1172 prtype
= type
->prtype
;
1175 dtuple_f_data
= dfield_get_data(dtuple_field
);
1176 dtuple_f_len
= dfield_get_len(dtuple_field
);
1178 rec_f_data
= rec_get_nth_field(rec
, offsets
,
1179 cur_field
, &rec_f_len
);
1181 if (rec_offs_nth_extern(offsets
, cur_field
)) {
1182 /* We do not compare to an externally stored field */
1186 goto order_resolved
;
1189 ret
= cmp_data_data(mtype
, prtype
, dtuple_f_data
, dtuple_f_len
,
1190 rec_f_data
, rec_f_len
);
1192 goto order_resolved
;
1198 ret
= 0; /* If we ran out of fields, dtuple was equal to rec
1199 up to the common fields */
1201 ut_ad((ret
>= - 1) && (ret
<= 1));
1203 *matched_fields
= cur_field
;
1207 #endif /* UNIV_DEBUG */