/*************************************************************//** Used in debug checking of cmp_dtuple_... . This function is used to compare a data tuple to a physical record. If dtuple has n fields then rec must have either m >= n fields, or it must differ from dtuple in some of the m fields rec has. If encounters an externally stored field, returns 0. @return 1, 0, -1, if dtuple is greater, equal, less than rec, respectively, when only the common first fields are compared */ static int cmp_debug_dtuple_rec_with_match( /*============================*/ const dtuple_t* dtuple, /*!< in: data tuple */ const rec_t* rec, /*!< in: physical record which differs from dtuple in some of the common fields, or which has an equal number or more fields than dtuple */ const ulint* offsets,/*!< in: array returned by rec_get_offsets() */ ulint* matched_fields) /*!< in/out: number of already completely matched fields; when function returns, contains the value for current comparison */ { const dfield_t* dtuple_field; /* current field in logical record */ ulint dtuple_f_len; /* the length of the current field in the logical record */ const byte* dtuple_f_data; /* pointer to the current logical field data */ ulint rec_f_len; /* length of current field in rec */ const byte* rec_f_data; /* pointer to the current rec field */ int ret = 3333; /* return value */ ulint cur_field; /* current field number */ ut_ad(dtuple && rec && matched_fields); ut_ad(dtuple_check_typed(dtuple)); ut_ad(rec_offs_validate(rec, NULL, offsets)); ut_ad(*matched_fields <= dtuple_get_n_fields_cmp(dtuple)); ut_ad(*matched_fields <= rec_offs_n_fields(offsets)); cur_field = *matched_fields; if (cur_field == 0) { if (UNIV_UNLIKELY (rec_get_info_bits(rec, rec_offs_comp(offsets)) & REC_INFO_MIN_REC_FLAG)) { ret = !(dtuple_get_info_bits(dtuple) & REC_INFO_MIN_REC_FLAG); goto order_resolved; } if (UNIV_UNLIKELY (dtuple_get_info_bits(dtuple) & REC_INFO_MIN_REC_FLAG)) { ret = -1; goto order_resolved; } } /* Match fields in a loop; stop if we run out of fields in dtuple */ while (cur_field < dtuple_get_n_fields_cmp(dtuple)) { ulint mtype; ulint prtype; dtuple_field = dtuple_get_nth_field(dtuple, cur_field); { const dtype_t* type = dfield_get_type(dtuple_field); mtype = type->mtype; prtype = type->prtype; } dtuple_f_data = dfield_get_data(dtuple_field); dtuple_f_len = dfield_get_len(dtuple_field); rec_f_data = rec_get_nth_field(rec, offsets, cur_field, &rec_f_len); if (rec_offs_nth_extern(offsets, cur_field)) { /* We do not compare to an externally stored field */ ret = 0; goto order_resolved; } ret = cmp_data_data(mtype, prtype, dtuple_f_data, dtuple_f_len, rec_f_data, rec_f_len); if (ret != 0) { goto order_resolved; } cur_field++; } ret = 0; /* If we ran out of fields, dtuple was equal to rec up to the common fields */ order_resolved: ut_ad((ret >= - 1) && (ret <= 1)); *matched_fields = cur_field; return(ret); }
/*************************************************************//** This function is used to compare a data tuple to a physical record. Only dtuple->n_fields_cmp first fields are taken into account for the data tuple! If we denote by n = n_fields_cmp, then rec must have either m >= n fields, or it must differ from dtuple in some of the m fields rec has. If rec has an externally stored field we do not compare it but return with value 0 if such a comparison should be made. @return 1, 0, -1, if dtuple is greater, equal, less than rec, respectively, when only the common first fields are compared, or until the first externally stored field in rec */ UNIV_INTERN int cmp_dtuple_rec_with_match( /*======================*/ const dtuple_t* dtuple, /*!< in: data tuple */ const rec_t* rec, /*!< in: physical record which differs from dtuple in some of the common fields, or which has an equal number or more fields than dtuple */ const ulint* offsets,/*!< in: array returned by rec_get_offsets() */ ulint* matched_fields, /*!< in/out: number of already completely matched fields; when function returns, contains the value for current comparison */ ulint* matched_bytes) /*!< in/out: number of already matched bytes within the first field not completely matched; when function returns, contains the value for current comparison */ { const dfield_t* dtuple_field; /* current field in logical record */ ulint dtuple_f_len; /* the length of the current field in the logical record */ const byte* dtuple_b_ptr; /* pointer to the current byte in logical field data */ ulint dtuple_byte; /* value of current byte to be compared in dtuple*/ ulint rec_f_len; /* length of current field in rec */ const byte* rec_b_ptr; /* pointer to the current byte in rec field */ ulint rec_byte; /* value of current byte to be compared in rec */ ulint cur_field; /* current field number */ ulint cur_bytes; /* number of already matched bytes in current field */ int ret = 3333; /* return value */ ut_ad(dtuple && rec && matched_fields && matched_bytes); ut_ad(dtuple_check_typed(dtuple)); ut_ad(rec_offs_validate(rec, NULL, offsets)); cur_field = *matched_fields; cur_bytes = *matched_bytes; ut_ad(cur_field <= dtuple_get_n_fields_cmp(dtuple)); ut_ad(cur_field <= rec_offs_n_fields(offsets)); if (cur_bytes == 0 && cur_field == 0) { ulint rec_info = rec_get_info_bits(rec, rec_offs_comp(offsets)); ulint tup_info = dtuple_get_info_bits(dtuple); if (UNIV_UNLIKELY(rec_info & REC_INFO_MIN_REC_FLAG)) { ret = !(tup_info & REC_INFO_MIN_REC_FLAG); goto order_resolved; } else if (UNIV_UNLIKELY(tup_info & REC_INFO_MIN_REC_FLAG)) { ret = -1; goto order_resolved; } } /* Match fields in a loop; stop if we run out of fields in dtuple or find an externally stored field */ while (cur_field < dtuple_get_n_fields_cmp(dtuple)) { ulint mtype; ulint prtype; dtuple_field = dtuple_get_nth_field(dtuple, cur_field); { const dtype_t* type = dfield_get_type(dtuple_field); mtype = type->mtype; prtype = type->prtype; } dtuple_f_len = dfield_get_len(dtuple_field); rec_b_ptr = rec_get_nth_field(rec, offsets, cur_field, &rec_f_len); /* If we have matched yet 0 bytes, it may be that one or both the fields are SQL null, or the record or dtuple may be the predefined minimum record, or the field is externally stored */ if (UNIV_LIKELY(cur_bytes == 0)) { if (rec_offs_nth_extern(offsets, cur_field)) { /* We do not compare to an externally stored field */ ret = 0; goto order_resolved; } if (dtuple_f_len == UNIV_SQL_NULL) { if (rec_f_len == UNIV_SQL_NULL) { goto next_field; } ret = -1; goto order_resolved; } else if (rec_f_len == UNIV_SQL_NULL) { /* We define the SQL null to be the smallest possible value of a field in the alphabetical order */ ret = 1; goto order_resolved; } } if (mtype >= DATA_FLOAT || (mtype == DATA_BLOB && 0 == (prtype & DATA_BINARY_TYPE) && dtype_get_charset_coll(prtype) != DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL)) { ret = cmp_whole_field(mtype, prtype, dfield_get_data(dtuple_field), (unsigned) dtuple_f_len, rec_b_ptr, (unsigned) rec_f_len); if (ret != 0) { cur_bytes = 0; goto order_resolved; } else { goto next_field; } } /* Set the pointers at the current byte */ rec_b_ptr = rec_b_ptr + cur_bytes; dtuple_b_ptr = (byte*)dfield_get_data(dtuple_field) + cur_bytes; /* Compare then the fields */ for (;;) { if (UNIV_UNLIKELY(rec_f_len <= cur_bytes)) { if (dtuple_f_len <= cur_bytes) { goto next_field; } rec_byte = dtype_get_pad_char(mtype, prtype); if (rec_byte == ULINT_UNDEFINED) { ret = 1; goto order_resolved; } } else { rec_byte = *rec_b_ptr; } if (UNIV_UNLIKELY(dtuple_f_len <= cur_bytes)) { dtuple_byte = dtype_get_pad_char(mtype, prtype); if (dtuple_byte == ULINT_UNDEFINED) { ret = -1; goto order_resolved; } } else { dtuple_byte = *dtuple_b_ptr; } if (dtuple_byte == rec_byte) { /* If the bytes are equal, they will remain such even after the collation transformation below */ goto next_byte; } if (mtype <= DATA_CHAR || (mtype == DATA_BLOB && !(prtype & DATA_BINARY_TYPE))) { rec_byte = cmp_collate(rec_byte); dtuple_byte = cmp_collate(dtuple_byte); } ret = (int) (dtuple_byte - rec_byte); if (UNIV_LIKELY(ret)) { if (ret < 0) { ret = -1; goto order_resolved; } else { ret = 1; goto order_resolved; } } next_byte: /* Next byte */ cur_bytes++; rec_b_ptr++; dtuple_b_ptr++; } next_field: cur_field++; cur_bytes = 0; } ut_ad(cur_bytes == 0); ret = 0; /* If we ran out of fields, dtuple was equal to rec up to the common fields */ order_resolved: ut_ad((ret >= - 1) && (ret <= 1)); ut_ad(ret == cmp_debug_dtuple_rec_with_match(dtuple, rec, offsets, matched_fields)); ut_ad(*matched_fields == cur_field); /* In the debug version, the above cmp_debug_... sets *matched_fields to a value */ *matched_fields = cur_field; *matched_bytes = cur_bytes; return(ret); }
rec_t* rec_convert_dtuple_to_rec_low( /*==========================*/ /* out: pointer to the origin of physical record */ byte* destination, /* in: start address of the physical record */ dtuple_t* dtuple, /* in: data tuple */ ulint data_size) /* in: data size of dtuple */ { dfield_t* field; ulint n_fields; rec_t* rec; ulint end_offset; ulint ored_offset; byte* data; ulint len; ulint i; ut_ad(destination && dtuple); ut_ad(dtuple_validate(dtuple)); ut_ad(dtuple_check_typed(dtuple)); ut_ad(dtuple_get_data_size(dtuple) == data_size); n_fields = dtuple_get_n_fields(dtuple); ut_ad(n_fields > 0); /* Calculate the offset of the origin in the physical record */ rec = destination + rec_get_converted_extra_size(data_size, n_fields); /* Store the number of fields */ rec_set_n_fields(rec, n_fields); /* Set the info bits of the record */ rec_set_info_bits(rec, dtuple_get_info_bits(dtuple)); /* Store the data and the offsets */ end_offset = 0; if (data_size <= REC_1BYTE_OFFS_LIMIT) { rec_set_1byte_offs_flag(rec, TRUE); for (i = 0; i < n_fields; i++) { field = dtuple_get_nth_field(dtuple, i); data = dfield_get_data(field); len = dfield_get_len(field); if (len == UNIV_SQL_NULL) { len = dtype_get_sql_null_size(dfield_get_type(field)); data_write_sql_null(rec + end_offset, len); end_offset += len; ored_offset = end_offset | REC_1BYTE_SQL_NULL_MASK; } else { /* If the data is not SQL null, store it */ ut_memcpy(rec + end_offset, data, len); end_offset += len; ored_offset = end_offset; } rec_1_set_field_end_info(rec, i, ored_offset); } } else { rec_set_1byte_offs_flag(rec, FALSE); for (i = 0; i < n_fields; i++) { field = dtuple_get_nth_field(dtuple, i); data = dfield_get_data(field); len = dfield_get_len(field); if (len == UNIV_SQL_NULL) { len = dtype_get_sql_null_size(dfield_get_type(field)); data_write_sql_null(rec + end_offset, len); end_offset += len; ored_offset = end_offset | REC_2BYTE_SQL_NULL_MASK; } else { /* If the data is not SQL null, store it */ ut_memcpy(rec + end_offset, data, len); end_offset += len; ored_offset = end_offset; } rec_2_set_field_end_info(rec, i, ored_offset); } } ut_ad(rec_validate(rec)); return(rec); }