summaryrefslogtreecommitdiff
path: root/storage/xtradb/rem
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2013-12-22 17:06:50 +0100
committerSergei Golubchik <sergii@pisem.net>2013-12-22 17:06:50 +0100
commitffa8c4cfcc41d4f160e3bdfca5cfd4b01a7d6e63 (patch)
tree728585c36f22a5db3cea796430883d0ebc5c05eb /storage/xtradb/rem
parente27c34f9e4ca15c797fcd3191ee5679c2f237a09 (diff)
parent52c26f7a1f675185d2ef1a28aca7f9bcc67c6414 (diff)
downloadmariadb-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 */