diff options
author | Sergei Golubchik <sergii@pisem.net> | 2013-12-22 17:06:50 +0100 |
---|---|---|
committer | Sergei Golubchik <sergii@pisem.net> | 2013-12-22 17:06:50 +0100 |
commit | ffa8c4cfcc41d4f160e3bdfca5cfd4b01a7d6e63 (patch) | |
tree | 728585c36f22a5db3cea796430883d0ebc5c05eb /storage/xtradb/rem | |
parent | e27c34f9e4ca15c797fcd3191ee5679c2f237a09 (diff) | |
parent | 52c26f7a1f675185d2ef1a28aca7f9bcc67c6414 (diff) | |
download | mariadb-git-ffa8c4cfcc41d4f160e3bdfca5cfd4b01a7d6e63.tar.gz |
Percona-Server-5.6.14-rel62.0 merge
support ha_innodb.so as a dynamic plugin.
* remove obsolete *,innodb_plugin.rdiff files
* s/--plugin-load=/--plugin-load-add=/
* MYSQL_PLUGIN_IMPORT glob_hostname[]
* use my_error instead of push_warning_printf(ER_DEFAULT)
* don't use tdc_size and tc_size in a module
update test cases (XtraDB is 5.6.14, InnoDB is 5.6.10)
* copy new tests over
* disable some tests for (old) InnoDB
* delete XtraDB tests that no longer apply
small compatibility changes:
* s/HTON_EXTENDED_KEYS/HTON_SUPPORTS_EXTENDED_KEYS/
* revert unnecessary InnoDB changes to make it a bit closer to the upstream
fix XtraDB to compile on Windows (both as a static and a dynamic plugin)
disable XtraDB on Windows (deadlocks) and where no atomic ops are available (e.g. CentOS 5)
storage/innobase/handler/ha_innodb.cc:
revert few unnecessary changes to make it a bit closer to the original InnoDB
storage/innobase/include/univ.i:
correct the version to match what it was merged from
Diffstat (limited to 'storage/xtradb/rem')
-rw-r--r-- | storage/xtradb/rem/rem0cmp.cc (renamed from storage/xtradb/rem/rem0cmp.c) | 520 | ||||
-rw-r--r-- | storage/xtradb/rem/rem0rec.cc (renamed from storage/xtradb/rem/rem0rec.c) | 139 |
2 files changed, 486 insertions, 173 deletions
diff --git a/storage/xtradb/rem/rem0cmp.c b/storage/xtradb/rem/rem0cmp.cc index a49a42e8c3f..db0fdf3ee21 100644 --- a/storage/xtradb/rem/rem0cmp.c +++ b/storage/xtradb/rem/rem0cmp.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1994, 2012, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -11,13 +11,13 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., -51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA *****************************************************************************/ /*******************************************************************//** -@file rem/rem0cmp.c +@file rem/rem0cmp.cc Comparison services for records Created 7/1/1994 Heikki Tuuri @@ -29,6 +29,8 @@ Created 7/1/1994 Heikki Tuuri #include "rem0cmp.ic" #endif +#include "ha_prototypes.h" +#include "handler0alter.h" #include "srv0srv.h" /* ALPHABETICAL ORDER @@ -68,10 +70,12 @@ cmp_debug_dtuple_rec_with_match( 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 + ulint n_cmp, /*!< in: number of fields to compare */ + ulint* matched_fields)/*!< in/out: number of already completely matched fields; when function returns, contains the value for current comparison */ + __attribute__((nonnull, warn_unused_result)); #endif /* UNIV_DEBUG */ /*************************************************************//** This function is used to compare two data fields for which the data type @@ -90,6 +94,23 @@ innobase_mysql_cmp( const unsigned char* b, /*!< in: data field */ unsigned int b_length); /*!< in: data field length, not UNIV_SQL_NULL */ +/*************************************************************//** +This function is used to compare two data fields for which the data type +is such that we must use MySQL code to compare them. The prototype here +must be a copy of the one in ha_innobase.cc! +@return 1, 0, -1, if a is greater, equal, less than b, respectively */ +extern +int +innobase_mysql_cmp_prefix( +/*======================*/ + int mysql_type, /*!< in: MySQL type */ + uint charset_number, /*!< in: number of the charset */ + const unsigned char* a, /*!< in: data field */ + unsigned int a_length, /*!< in: data field length, + not UNIV_SQL_NULL */ + const unsigned char* b, /*!< in: data field */ + unsigned int b_length); /*!< in: data field length, + not UNIV_SQL_NULL */ /*********************************************************************//** Transforms the character code so that it is ordered appropriately for the language. This is only used for the latin1 char set. MySQL does the @@ -184,8 +205,8 @@ cmp_whole_field( case DATA_DECIMAL: /* Remove preceding spaces */ - for (; a_length && *a == ' '; a++, a_length--); - for (; b_length && *b == ' '; b++, b_length--); + for (; a_length && *a == ' '; a++, a_length--) { } + for (; b_length && *b == ' '; b++, b_length--) { } if (*a == '-') { if (*b != '-') { @@ -271,7 +292,7 @@ cmp_whole_field( case DATA_MYSQL: return(innobase_mysql_cmp( (int)(prtype & DATA_MYSQL_TYPE_MASK), - (uint)dtype_get_charset_coll(prtype), + (uint) dtype_get_charset_coll(prtype), a, a_length, b, b_length)); default: fprintf(stderr, @@ -283,6 +304,44 @@ cmp_whole_field( return(0); } +/***************************************************************** +This function is used to compare two dfields where at least the first +has its data type field set. */ +UNIV_INTERN +int +cmp_dfield_dfield_like_prefix( +/*==========================*/ + /* out: 1, 0, -1, if dfield1 is greater, equal, + less than dfield2, respectively */ + dfield_t* dfield1,/* in: data field; must have type field set */ + dfield_t* dfield2)/* in: data field */ +{ + const dtype_t* type; + ulint ret; + + ut_ad(dfield_check_typed(dfield1)); + + type = dfield_get_type(dfield1); + + if (type->mtype >= DATA_FLOAT) { + ret = innobase_mysql_cmp_prefix( + (int)(type->prtype & DATA_MYSQL_TYPE_MASK), + (uint) dtype_get_charset_coll(type->prtype), + static_cast<byte*>(dfield_get_data(dfield1)), + dfield_get_len(dfield1), + static_cast<byte*>(dfield_get_data(dfield2)), + dfield_get_len(dfield2)); + } else { + ret = (cmp_data_data_like_prefix( + static_cast<byte*>(dfield_get_data(dfield1)), + dfield_get_len(dfield1), + static_cast<byte*>(dfield_get_data(dfield2)), + dfield_get_len(dfield2))); + } + + return(ret); +} + /*************************************************************//** This function is used to compare two data fields for which we know the data type. @@ -396,6 +455,162 @@ next_byte: return(0); /* Not reached */ } +/***************************************************************** +This function is used to compare two data fields for which we know the +data type to be VARCHAR */ + +int +cmp_data_data_slow_varchar( +/*=======================*/ + /* out: 1, 0, -1, if lhs is greater, equal, + less than rhs, respectively */ + const byte* lhs, /* in: data field (== a pointer to a memory + buffer) */ + ulint lhs_len,/* in: data field length or UNIV_SQL_NULL */ + const byte* rhs, /* in: data field (== a pointer to a memory + buffer) */ + ulint rhs_len)/* in: data field length or UNIV_SQL_NULL */ +{ + ulint i; + + ut_a(rhs_len != UNIV_SQL_NULL); + + if (lhs_len == UNIV_SQL_NULL) { + + /* We define the SQL null to be the smallest possible + value of a field in the alphabetical order */ + + return(-1); + } + + /* Compare the values.*/ + + for (i = 0; i < lhs_len && i < rhs_len; ++i, ++rhs, ++lhs) { + ulint lhs_byte = *lhs; + ulint rhs_byte = *rhs; + + if (lhs_byte != rhs_byte) { + /* If the bytes are equal, they will remain such even + after the collation transformation below */ + + lhs_byte = cmp_collate(lhs_byte); + rhs_byte = cmp_collate(rhs_byte); + + if (lhs_byte > rhs_byte) { + + return(1); + } else if (lhs_byte < rhs_byte) { + + return(-1); + } + } + } + + return(i == lhs_len && i == rhs_len) ? 0 : rhs_len - lhs_len; +} + +/***************************************************************** +This function is used to compare two data fields for which we know the +data type. The comparison is done for the LIKE operator.*/ + +int +cmp_data_data_slow_like_prefix( +/*===========================*/ + /* out: 1, 0, -1, if lhs is greater, equal, + less than rhs, respectively */ + const byte* lhs, /* in: data field (== a pointer to a memory + buffer) */ + ulint len1, /* in: data field length or UNIV_SQL_NULL */ + const byte* rhs, /* in: data field (== a pointer to a memory + buffer) */ + ulint len2) /* in: data field length or UNIV_SQL_NULL */ +{ + ulint i; + + ut_a(len2 != UNIV_SQL_NULL); + + if (len1 == UNIV_SQL_NULL) { + + /* We define the SQL null to be the smallest possible + value of a field in the alphabetical order */ + + return(-1); + } + + /* Compare the values.*/ + + for (i = 0; i < len1 && i < len2; ++i, ++rhs, ++lhs) { + ulint lhs_byte = *lhs; + ulint rhs_byte = *rhs; + + if (lhs_byte != rhs_byte) { + /* If the bytes are equal, they will remain such even + after the collation transformation below */ + + lhs_byte = cmp_collate(lhs_byte); + rhs_byte = cmp_collate(rhs_byte); + + if (lhs_byte > rhs_byte) { + + return(1); + } else if (lhs_byte < rhs_byte) { + + return(-1); + } + } + } + + return(i == len2 ? 0 : 1); +} + +/***************************************************************** +This function is used to compare two data fields for which we know the +data type. The comparison is done for the LIKE operator.*/ + +int +cmp_data_data_slow_like_suffix( +/*===========================*/ + /* out: 1, 0, -1, if data1 is greater, equal, + less than data2, respectively */ + /* in: data field (== a pointer to a + memory buffer) */ + const byte* data1 UNIV_UNUSED, + /* in: data field length or UNIV_SQL_NULL */ + ulint len1 UNIV_UNUSED, + /* in: data field (== a pointer to a memory + buffer) */ + const byte* data2 UNIV_UNUSED, + /* in: data field length or UNIV_SQL_NULL */ + ulint len2 UNIV_UNUSED) + +{ + ut_error; // FIXME: + return(1); +} + +/***************************************************************** +This function is used to compare two data fields for which we know the +data type. The comparison is done for the LIKE operator.*/ + +int +cmp_data_data_slow_like_substr( +/*===========================*/ + /* out: 1, 0, -1, if data1 is greater, equal, + less than data2, respectively */ + /* in: data field (== a pointer to a + memory buffer) */ + const byte* data1 UNIV_UNUSED, + /* in: data field length or UNIV_SQL_NULL */ + ulint len1 UNIV_UNUSED, + /* in: data field (== a pointer to a memory + buffer) */ + const byte* data2 UNIV_UNUSED, + /* in: data field length or UNIV_SQL_NULL */ + ulint len2 UNIV_UNUSED) +{ + ut_error; // FIXME: + return(1); +} /*************************************************************//** 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 @@ -409,14 +624,15 @@ 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( -/*======================*/ +cmp_dtuple_rec_with_match_low( +/*==========================*/ 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 n_cmp, /*!< in: number of fields to compare */ ulint* matched_fields, /*!< in/out: number of already completely matched fields; when function returns, contains the value for current comparison */ @@ -440,7 +656,7 @@ cmp_dtuple_rec_with_match( ulint cur_field; /* current field number */ ulint cur_bytes; /* number of already matched bytes in current field */ - int ret = 3333; /* return value */ + int ret; /* return value */ ut_ad(dtuple && rec && matched_fields && matched_bytes); ut_ad(dtuple_check_typed(dtuple)); @@ -449,7 +665,9 @@ cmp_dtuple_rec_with_match( cur_field = *matched_fields; cur_bytes = *matched_bytes; - ut_ad(cur_field <= dtuple_get_n_fields_cmp(dtuple)); + ut_ad(n_cmp > 0); + ut_ad(n_cmp <= dtuple_get_n_fields(dtuple)); + ut_ad(cur_field <= n_cmp); ut_ad(cur_field <= rec_offs_n_fields(offsets)); if (cur_bytes == 0 && cur_field == 0) { @@ -469,7 +687,7 @@ cmp_dtuple_rec_with_match( /* 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)) { + while (cur_field < n_cmp) { ulint mtype; ulint prtype; @@ -527,10 +745,12 @@ cmp_dtuple_rec_with_match( && 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); + ret = cmp_whole_field( + mtype, prtype, + static_cast<const byte*>( + dfield_get_data(dtuple_field)), + (unsigned) dtuple_f_len, + rec_b_ptr, (unsigned) rec_f_len); if (ret != 0) { cur_bytes = 0; @@ -544,7 +764,7 @@ cmp_dtuple_rec_with_match( /* Set the pointers at the current byte */ rec_b_ptr = rec_b_ptr + cur_bytes; - dtuple_b_ptr = (byte*)dfield_get_data(dtuple_field) + dtuple_b_ptr = (byte*) dfield_get_data(dtuple_field) + cur_bytes; /* Compare then the fields */ @@ -624,7 +844,7 @@ next_field: order_resolved: ut_ad((ret >= - 1) && (ret <= 1)); ut_ad(ret == cmp_debug_dtuple_rec_with_match(dtuple, rec, offsets, - matched_fields)); + n_cmp, matched_fields)); ut_ad(*matched_fields == cur_field); /* In the debug version, the above cmp_debug_... sets *matched_fields to a value */ @@ -695,156 +915,181 @@ cmp_dtuple_is_prefix_of_rec( } /*************************************************************//** -Compare two physical records that contain the same number of columns, -none of which are stored externally. -@return 1, 0, -1 if rec1 is greater, equal, less, respectively, than rec2 */ -UNIV_INTERN +Compare two physical record fields. +@retval 1 if rec1 field is greater than rec2 +@retval -1 if rec1 field is less than rec2 +@retval 0 if rec1 field equals to rec2 */ +static __attribute__((nonnull, warn_unused_result)) int -cmp_rec_rec_simple( -/*===============*/ +cmp_rec_rec_simple_field( +/*=====================*/ const rec_t* rec1, /*!< in: physical record */ const rec_t* rec2, /*!< in: physical record */ const ulint* offsets1,/*!< in: rec_get_offsets(rec1, ...) */ const ulint* offsets2,/*!< in: rec_get_offsets(rec2, ...) */ const dict_index_t* index, /*!< in: data dictionary index */ - ibool* null_eq)/*!< out: set to TRUE if - found matching null values */ + ulint n) /*!< in: field to compare */ { - ulint rec1_f_len; /*!< length of current field in rec1 */ - const byte* rec1_b_ptr; /*!< pointer to the current byte - in rec1 field */ - ulint rec1_byte; /*!< value of current byte to be - compared in rec1 */ - ulint rec2_f_len; /*!< length of current field in rec2 */ - const byte* rec2_b_ptr; /*!< pointer to the current byte - in rec2 field */ - ulint rec2_byte; /*!< value of current byte to be - compared in rec2 */ - ulint cur_field; /*!< current field number */ - ulint n_uniq; - - n_uniq = dict_index_get_n_unique(index); - ut_ad(rec_offs_n_fields(offsets1) >= n_uniq); - ut_ad(rec_offs_n_fields(offsets2) >= n_uniq); - - ut_ad(rec_offs_comp(offsets1) == rec_offs_comp(offsets2)); + const byte* rec1_b_ptr; + const byte* rec2_b_ptr; + ulint rec1_f_len; + ulint rec2_f_len; + const dict_col_t* col = dict_index_get_nth_col(index, n); - for (cur_field = 0; cur_field < n_uniq; cur_field++) { + ut_ad(!rec_offs_nth_extern(offsets1, n)); + ut_ad(!rec_offs_nth_extern(offsets2, n)); - ulint cur_bytes; - ulint mtype; - ulint prtype; + rec1_b_ptr = rec_get_nth_field(rec1, offsets1, n, &rec1_f_len); + rec2_b_ptr = rec_get_nth_field(rec2, offsets2, n, &rec2_f_len); - { - const dict_col_t* col - = dict_index_get_nth_col(index, cur_field); - - mtype = col->mtype; - prtype = col->prtype; + if (rec1_f_len == UNIV_SQL_NULL || rec2_f_len == UNIV_SQL_NULL) { + if (rec1_f_len == rec2_f_len) { + return(0); } + /* We define the SQL null to be the smallest possible + value of a field in the alphabetical order */ + return(rec1_f_len == UNIV_SQL_NULL ? -1 : 1); + } - ut_ad(!rec_offs_nth_extern(offsets1, cur_field)); - ut_ad(!rec_offs_nth_extern(offsets2, cur_field)); + if (col->mtype >= DATA_FLOAT + || (col->mtype == DATA_BLOB + && !(col->prtype & DATA_BINARY_TYPE) + && dtype_get_charset_coll(col->prtype) + != DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL)) { + return(cmp_whole_field(col->mtype, col->prtype, + rec1_b_ptr, (unsigned) rec1_f_len, + rec2_b_ptr, (unsigned) rec2_f_len)); + } - rec1_b_ptr = rec_get_nth_field(rec1, offsets1, - cur_field, &rec1_f_len); - rec2_b_ptr = rec_get_nth_field(rec2, offsets2, - cur_field, &rec2_f_len); + /* Compare the fields */ + for (ulint cur_bytes = 0;; cur_bytes++, rec1_b_ptr++, rec2_b_ptr++) { + ulint rec1_byte; + ulint rec2_byte; - if (rec1_f_len == UNIV_SQL_NULL - || rec2_f_len == UNIV_SQL_NULL) { + if (rec2_f_len <= cur_bytes) { + if (rec1_f_len <= cur_bytes) { + return(0); + } - if (rec1_f_len == rec2_f_len) { - if (null_eq) { - *null_eq = TRUE; - } + rec2_byte = dtype_get_pad_char( + col->mtype, col->prtype); - goto next_field; + if (rec2_byte == ULINT_UNDEFINED) { + return(1); + } + } else { + rec2_byte = *rec2_b_ptr; + } - } else if (rec2_f_len == UNIV_SQL_NULL) { + if (rec1_f_len <= cur_bytes) { + rec1_byte = dtype_get_pad_char( + col->mtype, col->prtype); - /* We define the SQL null to be the - smallest possible value of a field - in the alphabetical order */ - - return(1); - } else { + if (rec1_byte == ULINT_UNDEFINED) { return(-1); } + } else { + rec1_byte = *rec1_b_ptr; } - if (mtype >= DATA_FLOAT - || (mtype == DATA_BLOB - && 0 == (prtype & DATA_BINARY_TYPE) - && dtype_get_charset_coll(prtype) - != DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL)) { - int ret = cmp_whole_field(mtype, prtype, - rec1_b_ptr, - (unsigned) rec1_f_len, - rec2_b_ptr, - (unsigned) rec2_f_len); - if (ret) { - return(ret); - } + if (rec1_byte == rec2_byte) { + /* If the bytes are equal, they will remain such + even after the collation transformation below */ + continue; + } - goto next_field; + if (col->mtype <= DATA_CHAR + || (col->mtype == DATA_BLOB + && !(col->prtype & DATA_BINARY_TYPE))) { + + rec1_byte = cmp_collate(rec1_byte); + rec2_byte = cmp_collate(rec2_byte); } - /* Compare the fields */ - for (cur_bytes = 0;; cur_bytes++, rec1_b_ptr++, rec2_b_ptr++) { - if (rec2_f_len <= cur_bytes) { + if (rec1_byte < rec2_byte) { + return(-1); + } else if (rec1_byte > rec2_byte) { + return(1); + } + } +} - if (rec1_f_len <= cur_bytes) { +/*************************************************************//** +Compare two physical records that contain the same number of columns, +none of which are stored externally. +@retval 1 if rec1 (including non-ordering columns) is greater than rec2 +@retval -1 if rec1 (including non-ordering columns) is less than rec2 +@retval 0 if rec1 is a duplicate of rec2 */ +UNIV_INTERN +int +cmp_rec_rec_simple( +/*===============*/ + const rec_t* rec1, /*!< in: physical record */ + const rec_t* rec2, /*!< in: physical record */ + const ulint* offsets1,/*!< in: rec_get_offsets(rec1, ...) */ + const ulint* offsets2,/*!< in: rec_get_offsets(rec2, ...) */ + const dict_index_t* index, /*!< in: data dictionary index */ + struct TABLE* table) /*!< in: MySQL table, for reporting + duplicate key value if applicable, + or NULL */ +{ + ulint n; + ulint n_uniq = dict_index_get_n_unique(index); + bool null_eq = false; - goto next_field; - } + ut_ad(rec_offs_n_fields(offsets1) >= n_uniq); + ut_ad(rec_offs_n_fields(offsets2) == rec_offs_n_fields(offsets2)); - rec2_byte = dtype_get_pad_char(mtype, prtype); + ut_ad(rec_offs_comp(offsets1) == rec_offs_comp(offsets2)); - if (rec2_byte == ULINT_UNDEFINED) { - return(1); - } - } else { - rec2_byte = *rec2_b_ptr; - } + for (n = 0; n < n_uniq; n++) { + int cmp = cmp_rec_rec_simple_field( + rec1, rec2, offsets1, offsets2, index, n); - if (rec1_f_len <= cur_bytes) { - rec1_byte = dtype_get_pad_char(mtype, prtype); + if (cmp) { + return(cmp); + } - if (rec1_byte == ULINT_UNDEFINED) { - return(-1); - } - } else { - rec1_byte = *rec1_b_ptr; - } + /* If the fields are internally equal, they must both + be NULL or non-NULL. */ + ut_ad(rec_offs_nth_sql_null(offsets1, n) + == rec_offs_nth_sql_null(offsets2, n)); - if (rec1_byte == rec2_byte) { - /* If the bytes are equal, they will remain - such even after the collation transformation - below */ + if (rec_offs_nth_sql_null(offsets1, n)) { + ut_ad(!(dict_index_get_nth_col(index, n)->prtype + & DATA_NOT_NULL)); + null_eq = true; + } + } - continue; - } + /* If we ran out of fields, the ordering columns of rec1 were + equal to rec2. Issue a duplicate key error if needed. */ - if (mtype <= DATA_CHAR - || (mtype == DATA_BLOB - && !(prtype & DATA_BINARY_TYPE))) { + if (!null_eq && table && dict_index_is_unique(index)) { + /* Report erroneous row using new version of table. */ + innobase_rec_to_mysql(table, rec1, index, offsets1); + return(0); + } - rec1_byte = cmp_collate(rec1_byte); - rec2_byte = cmp_collate(rec2_byte); - } + /* Else, keep comparing so that we have the full internal + order. */ + for (; n < dict_index_get_n_fields(index); n++) { + int cmp = cmp_rec_rec_simple_field( + rec1, rec2, offsets1, offsets2, index, n); - if (rec1_byte < rec2_byte) { - return(-1); - } else if (rec1_byte > rec2_byte) { - return(1); - } + if (cmp) { + return(cmp); } -next_field: - continue; + + /* If the fields are internally equal, they must both + be NULL or non-NULL. */ + ut_ad(rec_offs_nth_sql_null(offsets1, n) + == rec_offs_nth_sql_null(offsets2, n)); } - /* If we ran out of fields, rec1 was equal to rec2. */ + /* This should never be reached. Internally, an index must + never contain duplicate entries. */ + ut_ad(0); return(0); } @@ -912,7 +1157,7 @@ cmp_rec_rec_with_match( ulint mtype; ulint prtype; - if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) { + if (dict_index_is_univ(index)) { /* This is for the insert buffer B-tree. */ mtype = DATA_BINARY; prtype = 0; @@ -1113,6 +1358,7 @@ cmp_debug_dtuple_rec_with_match( has an equal number or more fields than dtuple */ const ulint* offsets,/*!< in: array returned by rec_get_offsets() */ + ulint n_cmp, /*!< in: number of fields to compare */ ulint* matched_fields) /*!< in/out: number of already completely matched fields; when function returns, contains the value for current @@ -1125,14 +1371,16 @@ cmp_debug_dtuple_rec_with_match( 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 */ + int ret; /* 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(n_cmp > 0); + ut_ad(n_cmp <= dtuple_get_n_fields(dtuple)); + ut_ad(*matched_fields <= n_cmp); ut_ad(*matched_fields <= rec_offs_n_fields(offsets)); cur_field = *matched_fields; @@ -1158,7 +1406,7 @@ cmp_debug_dtuple_rec_with_match( /* Match fields in a loop; stop if we run out of fields in dtuple */ - while (cur_field < dtuple_get_n_fields_cmp(dtuple)) { + while (cur_field < n_cmp) { ulint mtype; ulint prtype; @@ -1172,7 +1420,9 @@ cmp_debug_dtuple_rec_with_match( prtype = type->prtype; } - dtuple_f_data = dfield_get_data(dtuple_field); + dtuple_f_data = static_cast<const byte*>( + dfield_get_data(dtuple_field)); + dtuple_f_len = dfield_get_len(dtuple_field); rec_f_data = rec_get_nth_field(rec, offsets, diff --git a/storage/xtradb/rem/rem0rec.c b/storage/xtradb/rem/rem0rec.cc index d938aa696dd..43072159b9e 100644 --- a/storage/xtradb/rem/rem0rec.c +++ b/storage/xtradb/rem/rem0rec.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2013, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -11,13 +11,13 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., -51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA *****************************************************************************/ /********************************************************************//** -@file rem/rem0rec.c +@file rem/rem0rec.cc Record manager Created 5/30/1994 Heikki Tuuri @@ -29,8 +29,10 @@ Created 5/30/1994 Heikki Tuuri #include "rem0rec.ic" #endif +#include "page0page.h" #include "mtr0mtr.h" #include "mtr0log.h" +#include "fts0fts.h" /* PHYSICAL RECORD (OLD STYLE) =========================== @@ -161,9 +163,9 @@ UNIV_INTERN ulint rec_get_n_extern_new( /*=================*/ - const rec_t* rec, /*!< in: compact physical record */ - dict_index_t* index, /*!< in: record descriptor */ - ulint n) /*!< in: number of columns to scan */ + const rec_t* rec, /*!< in: compact physical record */ + const dict_index_t* index, /*!< in: record descriptor */ + ulint n) /*!< in: number of columns to scan */ { const byte* nulls; const byte* lens; @@ -245,7 +247,7 @@ rec_init_offsets_comp_ordinary( /*===========================*/ const rec_t* rec, /*!< in: physical record in ROW_FORMAT=COMPACT */ - ibool temp, /*!< in: whether to use the + bool temp, /*!< in: whether to use the format for temporary files in index creation */ const dict_index_t* index, /*!< in: record descriptor */ @@ -255,15 +257,15 @@ rec_init_offsets_comp_ordinary( ulint i = 0; ulint offs = 0; ulint any_ext = 0; + ulint n_null = index->n_nullable; const byte* nulls = temp ? rec - 1 : rec - (1 + REC_N_NEW_EXTRA_BYTES); - const byte* lens = nulls - - UT_BITS_IN_BYTES(index->n_nullable); + const byte* lens = nulls - UT_BITS_IN_BYTES(n_null); ulint null_mask = 1; #ifdef UNIV_DEBUG - /* We cannot invoke rec_offs_make_valid() here if temp=TRUE. + /* We cannot invoke rec_offs_make_valid() here if temp=true. Similarly, rec_offs_validate() will fail in that case, because it invokes rec_get_status(). */ offsets[2] = (ulint) rec; @@ -275,7 +277,7 @@ rec_init_offsets_comp_ordinary( if (temp && dict_table_is_comp(index->table)) { /* No need to do adjust fixed_len=0. We only need to adjust it for ROW_FORMAT=REDUNDANT. */ - temp = FALSE; + temp = false; } /* read the lengths of fields 0..n */ @@ -288,6 +290,7 @@ rec_init_offsets_comp_ordinary( if (!(col->prtype & DATA_NOT_NULL)) { /* nullable field => read the null flag */ + ut_ad(n_null--); if (UNIV_UNLIKELY(!(byte) null_mask)) { nulls--; @@ -403,7 +406,7 @@ rec_init_offsets( break; case REC_STATUS_ORDINARY: rec_init_offsets_comp_ordinary( - rec, FALSE, index, offsets); + rec, false, index, offsets); return; } @@ -558,6 +561,9 @@ rec_get_offsets_func( n = dict_index_get_n_fields(index); break; case REC_STATUS_NODE_PTR: + /* Node pointer records consist of the + uniquely identifying fields of the record + followed by a child page number field. */ n = dict_index_get_n_unique_in_tree(index) + 1; break; case REC_STATUS_INFIMUM: @@ -577,6 +583,8 @@ rec_get_offsets_func( n = n_fields; } + /* The offsets header consists of the allocation size at + offsets[0] and the REC_OFFS_HEADER_SIZE bytes. */ size = n + (1 + REC_OFFS_HEADER_SIZE); if (UNIV_UNLIKELY(!offsets) @@ -586,7 +594,9 @@ rec_get_offsets_func( MEM_HEAP_DYNAMIC, file, line); } - offsets = mem_heap_alloc(*heap, size * sizeof(ulint)); + offsets = static_cast<ulint*>( + mem_heap_alloc(*heap, size * sizeof(ulint))); + rec_offs_set_n_alloc(offsets, size); } @@ -785,28 +795,27 @@ rec_get_converted_size_comp_prefix_low( const dfield_t* fields, /*!< in: array of data fields */ ulint n_fields,/*!< in: number of data fields */ ulint* extra, /*!< out: extra size */ - ibool temp) /*!< in: whether this is a + bool temp) /*!< in: whether this is a temporary file record */ { ulint extra_size; ulint data_size; ulint i; - ut_ad(index); - ut_ad(fields); + ulint n_null = index->n_nullable; ut_ad(n_fields > 0); ut_ad(n_fields <= dict_index_get_n_fields(index)); ut_ad(!temp || extra); extra_size = temp - ? UT_BITS_IN_BYTES(index->n_nullable) + ? UT_BITS_IN_BYTES(n_null) : REC_N_NEW_EXTRA_BYTES - + UT_BITS_IN_BYTES(index->n_nullable); + + UT_BITS_IN_BYTES(n_null); data_size = 0; if (temp && dict_table_is_comp(index->table)) { /* No need to do adjust fixed_len=0. We only need to adjust it for ROW_FORMAT=REDUNDANT. */ - temp = FALSE; + temp = false; } /* read the lengths of fields 0..n */ @@ -822,6 +831,8 @@ rec_get_converted_size_comp_prefix_low( ut_ad(dict_col_type_assert_equal(col, dfield_get_type(&fields[i]))); + /* All NULLable fields must be included in the n_null count. */ + ut_ad((col->prtype & DATA_NOT_NULL) || n_null--); if (dfield_is_null(&fields[i])) { /* No length is stored for NULL fields. */ @@ -895,7 +906,7 @@ rec_get_converted_size_comp_prefix( { ut_ad(dict_table_is_comp(index->table)); return(rec_get_converted_size_comp_prefix_low( - index, fields, n_fields, extra, FALSE)); + index, fields, n_fields, extra, false)); } /**********************************************************//** @@ -915,8 +926,6 @@ rec_get_converted_size_comp( ulint* extra) /*!< out: extra size */ { ulint size; - ut_ad(index); - ut_ad(fields); ut_ad(n_fields > 0); switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) { @@ -943,7 +952,7 @@ rec_get_converted_size_comp( } return(size + rec_get_converted_size_comp_prefix_low( - index, fields, n_fields, extra, FALSE)); + index, fields, n_fields, extra, false)); } /***********************************************************//** @@ -1129,7 +1138,7 @@ rec_convert_dtuple_to_rec_comp( const dfield_t* fields, /*!< in: array of data fields */ ulint n_fields,/*!< in: number of data fields */ ulint status, /*!< in: status bits of the record */ - ibool temp) /*!< in: whether to use the + bool temp) /*!< in: whether to use the format for temporary files in index creation */ { @@ -1143,6 +1152,8 @@ rec_convert_dtuple_to_rec_comp( ulint n_node_ptr_field; ulint fixed_len; ulint null_mask = 1; + ulint n_null; + ut_ad(temp || dict_table_is_comp(index->table)); ut_ad(n_fields > 0); @@ -1154,7 +1165,7 @@ rec_convert_dtuple_to_rec_comp( if (dict_table_is_comp(index->table)) { /* No need to do adjust fixed_len=0. We only need to adjust it for ROW_FORMAT=REDUNDANT. */ - temp = FALSE; + temp = false; } } else { nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1); @@ -1181,7 +1192,8 @@ rec_convert_dtuple_to_rec_comp( } end = rec; - lens = nulls - UT_BITS_IN_BYTES(index->n_nullable); + n_null = index->n_nullable; + lens = nulls - UT_BITS_IN_BYTES(n_null); /* clear the SQL-null flags */ memset(lens + 1, 0, nulls - lens); @@ -1203,7 +1215,7 @@ rec_convert_dtuple_to_rec_comp( if (!(dtype_get_prtype(type) & DATA_NOT_NULL)) { /* nullable field */ - ut_ad(index->n_nullable > 0); + ut_ad(n_null--); if (UNIV_UNLIKELY(!(byte) null_mask)) { nulls--; @@ -1257,7 +1269,9 @@ rec_convert_dtuple_to_rec_comp( *lens-- = (byte) len; } else { ut_ad(len <= dtype_get_len(type) - || dtype_get_mtype(type) == DATA_BLOB); + || dtype_get_mtype(type) == DATA_BLOB + || !strcmp(index->name, + FTS_INDEX_TABLE_IND_NAME)); if (len < 128 || (dtype_get_len(type) < 256 && dtype_get_mtype(type) != DATA_BLOB)) { @@ -1293,13 +1307,12 @@ rec_convert_dtuple_to_rec_new( rec_t* rec; status = dtuple_get_info_bits(dtuple) & REC_NEW_STATUS_MASK; - rec_get_converted_size_comp(index, status, - dtuple->fields, dtuple->n_fields, - &extra_size); + rec_get_converted_size_comp( + index, status, dtuple->fields, dtuple->n_fields, &extra_size); rec = buf + extra_size; rec_convert_dtuple_to_rec_comp( - rec, index, dtuple->fields, dtuple->n_fields, status, FALSE); + rec, index, dtuple->fields, dtuple->n_fields, status, false); /* Set the info bits of the record */ rec_set_info_and_status_bits(rec, dtuple_get_info_bits(dtuple)); @@ -1375,7 +1388,7 @@ rec_get_converted_size_temp( ulint* extra) /*!< out: extra size */ { return(rec_get_converted_size_comp_prefix_low( - index, fields, n_fields, extra, TRUE)); + index, fields, n_fields, extra, true)); } /******************************************************//** @@ -1390,7 +1403,7 @@ rec_init_offsets_temp( ulint* offsets)/*!< in/out: array of offsets; in: n=rec_offs_n_fields(offsets) */ { - rec_init_offsets_comp_ordinary(rec, TRUE, index, offsets); + rec_init_offsets_comp_ordinary(rec, true, index, offsets); } /*********************************************************//** @@ -1406,7 +1419,7 @@ rec_convert_dtuple_to_temp( ulint n_fields) /*!< in: number of fields */ { rec_convert_dtuple_to_rec_comp(rec, index, fields, n_fields, - REC_STATUS_ORDINARY, TRUE); + REC_STATUS_ORDINARY, true); } /**************************************************************//** @@ -1486,7 +1499,7 @@ rec_copy_prefix_to_buf_old( mem_free(*buf); } - *buf = mem_alloc2(prefix_len, buf_size); + *buf = static_cast<byte*>(mem_alloc2(prefix_len, buf_size)); } ut_memcpy(*buf, rec - area_start, prefix_len); @@ -1612,7 +1625,7 @@ rec_copy_prefix_to_buf( mem_free(*buf); } - *buf = mem_alloc2(prefix_len, buf_size); + *buf = static_cast<byte*>(mem_alloc2(prefix_len, buf_size)); } memcpy(*buf, lens + 1, prefix_len); @@ -1826,6 +1839,13 @@ rec_print_comp( if (len <= 30) { ut_print_buf(file, data, len); + } else if (rec_offs_nth_extern(offsets, i)) { + ut_print_buf(file, data, 30); + fprintf(file, " (total %lu bytes, external)", + (ulong) len); + ut_print_buf(file, data + len + - BTR_EXTERN_FIELD_REF_SIZE, + BTR_EXTERN_FIELD_REF_SIZE); } else { ut_print_buf(file, data, 30); @@ -1896,4 +1916,47 @@ rec_print( } } } + +# ifdef UNIV_DEBUG +/************************************************************//** +Reads the DB_TRX_ID of a clustered index record. +@return the value of DB_TRX_ID */ +UNIV_INTERN +trx_id_t +rec_get_trx_id( +/*===========*/ + const rec_t* rec, /*!< in: record */ + const dict_index_t* index) /*!< in: clustered index */ +{ + const page_t* page + = page_align(rec); + ulint trx_id_col + = dict_index_get_sys_col_pos(index, DATA_TRX_ID); + const byte* trx_id; + ulint len; + mem_heap_t* heap = NULL; + ulint offsets_[REC_OFFS_NORMAL_SIZE]; + ulint* offsets = offsets_; + rec_offs_init(offsets_); + + ut_ad(fil_page_get_type(page) == FIL_PAGE_INDEX); + ut_ad(mach_read_from_8(page + PAGE_HEADER + PAGE_INDEX_ID) + == index->id); + ut_ad(dict_index_is_clust(index)); + ut_ad(trx_id_col > 0); + ut_ad(trx_id_col != ULINT_UNDEFINED); + + offsets = rec_get_offsets(rec, index, offsets, trx_id_col + 1, &heap); + + trx_id = rec_get_nth_field(rec, offsets, trx_id_col, &len); + + ut_ad(len == DATA_TRX_ID_LEN); + + if (heap) { + mem_heap_free(heap); + } + + return(trx_read_trx_id(trx_id)); +} +# endif /* UNIV_DEBUG */ #endif /* !UNIV_HOTBACKUP */ |