summaryrefslogtreecommitdiff
path: root/storage/xtradb/rem/rem0rec.cc
diff options
context:
space:
mode:
Diffstat (limited to 'storage/xtradb/rem/rem0rec.cc')
-rw-r--r--storage/xtradb/rem/rem0rec.cc2107
1 files changed, 0 insertions, 2107 deletions
diff --git a/storage/xtradb/rem/rem0rec.cc b/storage/xtradb/rem/rem0rec.cc
deleted file mode 100644
index c62e8c90434..00000000000
--- a/storage/xtradb/rem/rem0rec.cc
+++ /dev/null
@@ -1,2107 +0,0 @@
-/*****************************************************************************
-
-Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, MariaDB Corporation.
-
-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
-Foundation; version 2 of the License.
-
-This program is distributed in the hope that it will be useful, but WITHOUT
-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 Street, Suite 500, Boston, MA 02110-1335 USA
-
-*****************************************************************************/
-
-/********************************************************************//**
-@file rem/rem0rec.cc
-Record manager
-
-Created 5/30/1994 Heikki Tuuri
-*************************************************************************/
-
-#include "rem0rec.h"
-
-#ifdef UNIV_NONINL
-#include "rem0rec.ic"
-#endif
-
-#include "page0page.h"
-#include "mtr0mtr.h"
-#include "mtr0log.h"
-#include "fts0fts.h"
-#ifdef WITH_WSREP
-#include <ha_prototypes.h>
-#endif /* WITH_WSREP */
-
-/* PHYSICAL RECORD (OLD STYLE)
- ===========================
-
-The physical record, which is the data type of all the records
-found in index pages of the database, has the following format
-(lower addresses and more significant bits inside a byte are below
-represented on a higher text line):
-
-| offset of the end of the last field of data, the most significant
- bit is set to 1 if and only if the field is SQL-null,
- if the offset is 2-byte, then the second most significant
- bit is set to 1 if the field is stored on another page:
- mostly this will occur in the case of big BLOB fields |
-...
-| offset of the end of the first field of data + the SQL-null bit |
-| 4 bits used to delete mark a record, and mark a predefined
- minimum record in alphabetical order |
-| 4 bits giving the number of records owned by this record
- (this term is explained in page0page.h) |
-| 13 bits giving the order number of this record in the
- heap of the index page |
-| 10 bits giving the number of fields in this record |
-| 1 bit which is set to 1 if the offsets above are given in
- one byte format, 0 if in two byte format |
-| two bytes giving an absolute pointer to the next record in the page |
-ORIGIN of the record
-| first field of data |
-...
-| last field of data |
-
-The origin of the record is the start address of the first field
-of data. The offsets are given relative to the origin.
-The offsets of the data fields are stored in an inverted
-order because then the offset of the first fields are near the
-origin, giving maybe a better processor cache hit rate in searches.
-
-The offsets of the data fields are given as one-byte
-(if there are less than 127 bytes of data in the record)
-or two-byte unsigned integers. The most significant bit
-is not part of the offset, instead it indicates the SQL-null
-if the bit is set to 1. */
-
-/* PHYSICAL RECORD (NEW STYLE)
- ===========================
-
-The physical record, which is the data type of all the records
-found in index pages of the database, has the following format
-(lower addresses and more significant bits inside a byte are below
-represented on a higher text line):
-
-| length of the last non-null variable-length field of data:
- if the maximum length is 255, one byte; otherwise,
- 0xxxxxxx (one byte, length=0..127), or 1exxxxxxxxxxxxxx (two bytes,
- length=128..16383, extern storage flag) |
-...
-| length of first variable-length field of data |
-| SQL-null flags (1 bit per nullable field), padded to full bytes |
-| 4 bits used to delete mark a record, and mark a predefined
- minimum record in alphabetical order |
-| 4 bits giving the number of records owned by this record
- (this term is explained in page0page.h) |
-| 13 bits giving the order number of this record in the
- heap of the index page |
-| 3 bits record type: 000=conventional, 001=node pointer (inside B-tree),
- 010=infimum, 011=supremum, 1xx=reserved |
-| two bytes giving a relative pointer to the next record in the page |
-ORIGIN of the record
-| first field of data |
-...
-| last field of data |
-
-The origin of the record is the start address of the first field
-of data. The offsets are given relative to the origin.
-The offsets of the data fields are stored in an inverted
-order because then the offset of the first fields are near the
-origin, giving maybe a better processor cache hit rate in searches.
-
-The offsets of the data fields are given as one-byte
-(if there are less than 127 bytes of data in the record)
-or two-byte unsigned integers. The most significant bit
-is not part of the offset, instead it indicates the SQL-null
-if the bit is set to 1. */
-
-/* CANONICAL COORDINATES. A record can be seen as a single
-string of 'characters' in the following way: catenate the bytes
-in each field, in the order of fields. An SQL-null field
-is taken to be an empty sequence of bytes. Then after
-the position of each field insert in the string
-the 'character' <FIELD-END>, except that after an SQL-null field
-insert <NULL-FIELD-END>. Now the ordinal position of each
-byte in this canonical string is its canonical coordinate.
-So, for the record ("AA", SQL-NULL, "BB", ""), the canonical
-string is "AA<FIELD_END><NULL-FIELD-END>BB<FIELD-END><FIELD-END>".
-We identify prefixes (= initial segments) of a record
-with prefixes of the canonical string. The canonical
-length of the prefix is the length of the corresponding
-prefix of the canonical string. The canonical length of
-a record is the length of its canonical string.
-
-For example, the maximal common prefix of records
-("AA", SQL-NULL, "BB", "C") and ("AA", SQL-NULL, "B", "C")
-is "AA<FIELD-END><NULL-FIELD-END>B", and its canonical
-length is 5.
-
-A complete-field prefix of a record is a prefix which ends at the
-end of some field (containing also <FIELD-END>).
-A record is a complete-field prefix of another record, if
-the corresponding canonical strings have the same property. */
-
-/* this is used to fool compiler in rec_validate */
-UNIV_INTERN ulint rec_dummy;
-
-/***************************************************************//**
-Validates the consistency of an old-style physical record.
-@return TRUE if ok */
-static
-ibool
-rec_validate_old(
-/*=============*/
- const rec_t* rec); /*!< in: physical record */
-
-/******************************************************//**
-Determine how many of the first n columns in a compact
-physical record are stored externally.
-@return number of externally stored columns */
-UNIV_INTERN
-ulint
-rec_get_n_extern_new(
-/*=================*/
- 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;
- ulint null_mask;
- ulint n_extern;
- ulint i;
-
- ut_ad(dict_table_is_comp(index->table));
- ut_ad(rec_get_status(rec) == REC_STATUS_ORDINARY);
- ut_ad(n == ULINT_UNDEFINED || n <= dict_index_get_n_fields(index));
-
- if (n == ULINT_UNDEFINED) {
- n = dict_index_get_n_fields(index);
- }
-
- nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
- lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
- null_mask = 1;
- n_extern = 0;
- i = 0;
-
- /* read the lengths of fields 0..n */
- do {
- const dict_field_t* field
- = dict_index_get_nth_field(index, i);
- const dict_col_t* col
- = dict_field_get_col(field);
- ulint len;
-
- if (!(col->prtype & DATA_NOT_NULL)) {
- /* nullable field => read the null flag */
-
- if (UNIV_UNLIKELY(!(byte) null_mask)) {
- nulls--;
- null_mask = 1;
- }
-
- if (*nulls & null_mask) {
- null_mask <<= 1;
- /* No length is stored for NULL fields. */
- continue;
- }
- null_mask <<= 1;
- }
-
- if (UNIV_UNLIKELY(!field->fixed_len)) {
- /* Variable-length field: read the length */
- len = *lens--;
- /* If the maximum length of the field is up
- to 255 bytes, the actual length is always
- stored in one byte. If the maximum length is
- more than 255 bytes, the actual length is
- stored in one byte for 0..127. The length
- will be encoded in two bytes when it is 128 or
- more, or when the field is stored externally. */
- if (UNIV_UNLIKELY(col->len > 255)
- || UNIV_UNLIKELY(col->mtype == DATA_BLOB)) {
- if (len & 0x80) {
- /* 1exxxxxxx xxxxxxxx */
- if (len & 0x40) {
- n_extern++;
- }
- lens--;
- }
- }
- }
- } while (++i < n);
-
- return(n_extern);
-}
-
-/******************************************************//**
-Determine the offset to each field in a leaf-page record
-in ROW_FORMAT=COMPACT. This is a special case of
-rec_init_offsets() and rec_get_offsets_func(). */
-UNIV_INLINE MY_ATTRIBUTE((nonnull))
-void
-rec_init_offsets_comp_ordinary(
-/*===========================*/
- const rec_t* rec, /*!< in: physical record in
- ROW_FORMAT=COMPACT */
- bool temp, /*!< in: whether to use the
- format for temporary files in
- index creation */
- const dict_index_t* index, /*!< in: record descriptor */
- ulint* offsets)/*!< in/out: array of offsets;
- in: n=rec_offs_n_fields(offsets) */
-{
- 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(n_null);
- ulint null_mask = 1;
-
-#ifdef UNIV_DEBUG
- /* 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;
- offsets[3] = (ulint) index;
-#endif /* UNIV_DEBUG */
-
- ut_ad(temp || dict_table_is_comp(index->table));
-
- 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;
- }
-
- /* read the lengths of fields 0..n */
- do {
- const dict_field_t* field
- = dict_index_get_nth_field(index, i);
- const dict_col_t* col
- = dict_field_get_col(field);
- ulint len;
-
- if (!(col->prtype & DATA_NOT_NULL)) {
- /* nullable field => read the null flag */
- ut_ad(n_null--);
-
- if (UNIV_UNLIKELY(!(byte) null_mask)) {
- nulls--;
- null_mask = 1;
- }
-
- if (*nulls & null_mask) {
- null_mask <<= 1;
- /* No length is stored for NULL fields.
- We do not advance offs, and we set
- the length to zero and enable the
- SQL NULL flag in offsets[]. */
- len = offs | REC_OFFS_SQL_NULL;
- goto resolved;
- }
- null_mask <<= 1;
- }
-
- if (!field->fixed_len
- || (temp && !dict_col_get_fixed_size(col, temp))) {
- /* Variable-length field: read the length */
- len = *lens--;
- /* If the maximum length of the field is up
- to 255 bytes, the actual length is always
- stored in one byte. If the maximum length is
- more than 255 bytes, the actual length is
- stored in one byte for 0..127. The length
- will be encoded in two bytes when it is 128 or
- more, or when the field is stored externally. */
- if (UNIV_UNLIKELY(col->len > 255)
- || UNIV_UNLIKELY(col->mtype
- == DATA_BLOB)) {
- if (len & 0x80) {
- /* 1exxxxxxx xxxxxxxx */
- len <<= 8;
- len |= *lens--;
-
- offs += len & 0x3fff;
- if (UNIV_UNLIKELY(len
- & 0x4000)) {
- ut_ad(dict_index_is_clust
- (index));
- any_ext = REC_OFFS_EXTERNAL;
- len = offs
- | REC_OFFS_EXTERNAL;
- } else {
- len = offs;
- }
-
- goto resolved;
- }
- }
-
- len = offs += len;
- } else {
- len = offs += field->fixed_len;
- }
-resolved:
- rec_offs_base(offsets)[i + 1] = len;
- } while (++i < rec_offs_n_fields(offsets));
-
- *rec_offs_base(offsets)
- = (rec - (lens + 1)) | REC_OFFS_COMPACT | any_ext;
-}
-
-/******************************************************//**
-The following function determines the offsets to each field in the
-record. The offsets are written to a previously allocated array of
-ulint, where rec_offs_n_fields(offsets) has been initialized to the
-number of fields in the record. The rest of the array will be
-initialized by this function. rec_offs_base(offsets)[0] will be set
-to the extra size (if REC_OFFS_COMPACT is set, the record is in the
-new format; if REC_OFFS_EXTERNAL is set, the record contains externally
-stored columns), and rec_offs_base(offsets)[1..n_fields] will be set to
-offsets past the end of fields 0..n_fields, or to the beginning of
-fields 1..n_fields+1. When the high-order bit of the offset at [i+1]
-is set (REC_OFFS_SQL_NULL), the field i is NULL. When the second
-high-order bit of the offset at [i+1] is set (REC_OFFS_EXTERNAL), the
-field i is being stored externally. */
-static
-void
-rec_init_offsets(
-/*=============*/
- const rec_t* rec, /*!< in: physical record */
- const dict_index_t* index, /*!< in: record descriptor */
- ulint* offsets)/*!< in/out: array of offsets;
- in: n=rec_offs_n_fields(offsets) */
-{
- ulint i = 0;
- ulint offs;
-
- rec_offs_make_valid(rec, index, offsets);
-
- if (dict_table_is_comp(index->table)) {
- const byte* nulls;
- const byte* lens;
- dict_field_t* field;
- ulint null_mask;
- ulint status = rec_get_status(rec);
- ulint n_node_ptr_field = ULINT_UNDEFINED;
-
- switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
- case REC_STATUS_INFIMUM:
- case REC_STATUS_SUPREMUM:
- /* the field is 8 bytes long */
- rec_offs_base(offsets)[0]
- = REC_N_NEW_EXTRA_BYTES | REC_OFFS_COMPACT;
- rec_offs_base(offsets)[1] = 8;
- return;
- case REC_STATUS_NODE_PTR:
- n_node_ptr_field
- = dict_index_get_n_unique_in_tree(index);
- break;
- case REC_STATUS_ORDINARY:
- rec_init_offsets_comp_ordinary(
- rec, false, index, offsets);
- return;
- }
-
- nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
- lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
- offs = 0;
- null_mask = 1;
-
- /* read the lengths of fields 0..n */
- do {
- ulint len;
- if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
- len = offs += REC_NODE_PTR_SIZE;
- goto resolved;
- }
-
- field = dict_index_get_nth_field(index, i);
- if (!(dict_field_get_col(field)->prtype
- & DATA_NOT_NULL)) {
- /* nullable field => read the null flag */
-
- if (UNIV_UNLIKELY(!(byte) null_mask)) {
- nulls--;
- null_mask = 1;
- }
-
- if (*nulls & null_mask) {
- null_mask <<= 1;
- /* No length is stored for NULL fields.
- We do not advance offs, and we set
- the length to zero and enable the
- SQL NULL flag in offsets[]. */
- len = offs | REC_OFFS_SQL_NULL;
- goto resolved;
- }
- null_mask <<= 1;
- }
-
- if (UNIV_UNLIKELY(!field->fixed_len)) {
- /* Variable-length field: read the length */
- const dict_col_t* col
- = dict_field_get_col(field);
- len = *lens--;
- /* If the maximum length of the field
- is up to 255 bytes, the actual length
- is always stored in one byte. If the
- maximum length is more than 255 bytes,
- the actual length is stored in one
- byte for 0..127. The length will be
- encoded in two bytes when it is 128 or
- more, or when the field is stored
- externally. */
- if (UNIV_UNLIKELY(col->len > 255)
- || UNIV_UNLIKELY(col->mtype
- == DATA_BLOB)) {
- if (len & 0x80) {
- /* 1exxxxxxx xxxxxxxx */
-
- len <<= 8;
- len |= *lens--;
-
- /* B-tree node pointers
- must not contain externally
- stored columns. Thus
- the "e" flag must be 0. */
- ut_a(!(len & 0x4000));
- offs += len & 0x3fff;
- len = offs;
-
- goto resolved;
- }
- }
-
- len = offs += len;
- } else {
- len = offs += field->fixed_len;
- }
-resolved:
- rec_offs_base(offsets)[i + 1] = len;
- } while (++i < rec_offs_n_fields(offsets));
-
- *rec_offs_base(offsets)
- = (rec - (lens + 1)) | REC_OFFS_COMPACT;
- } else {
- /* Old-style record: determine extra size and end offsets */
- offs = REC_N_OLD_EXTRA_BYTES;
- if (rec_get_1byte_offs_flag(rec)) {
- offs += rec_offs_n_fields(offsets);
- *rec_offs_base(offsets) = offs;
- /* Determine offsets to fields */
- do {
- offs = rec_1_get_field_end_info(rec, i);
- if (offs & REC_1BYTE_SQL_NULL_MASK) {
- offs &= ~REC_1BYTE_SQL_NULL_MASK;
- offs |= REC_OFFS_SQL_NULL;
- }
- rec_offs_base(offsets)[1 + i] = offs;
- } while (++i < rec_offs_n_fields(offsets));
- } else {
- offs += 2 * rec_offs_n_fields(offsets);
- *rec_offs_base(offsets) = offs;
- /* Determine offsets to fields */
- do {
- offs = rec_2_get_field_end_info(rec, i);
- if (offs & REC_2BYTE_SQL_NULL_MASK) {
- offs &= ~REC_2BYTE_SQL_NULL_MASK;
- offs |= REC_OFFS_SQL_NULL;
- }
- if (offs & REC_2BYTE_EXTERN_MASK) {
- offs &= ~REC_2BYTE_EXTERN_MASK;
- offs |= REC_OFFS_EXTERNAL;
- *rec_offs_base(offsets) |= REC_OFFS_EXTERNAL;
- }
- rec_offs_base(offsets)[1 + i] = offs;
- } while (++i < rec_offs_n_fields(offsets));
- }
- }
-}
-
-/******************************************************//**
-The following function determines the offsets to each field
-in the record. It can reuse a previously returned array.
-@return the new offsets */
-UNIV_INTERN
-ulint*
-rec_get_offsets_func(
-/*=================*/
- const rec_t* rec, /*!< in: physical record */
- const dict_index_t* index, /*!< in: record descriptor */
- ulint* offsets,/*!< in/out: array consisting of
- offsets[0] allocated elements,
- or an array from rec_get_offsets(),
- or NULL */
- ulint n_fields,/*!< in: maximum number of
- initialized fields
- (ULINT_UNDEFINED if all fields) */
-#ifdef UNIV_DEBUG
- const char* file, /*!< in: file name where called */
- ulint line, /*!< in: line number where called */
-#endif /* UNIV_DEBUG */
- mem_heap_t** heap) /*!< in/out: memory heap */
-{
- ulint n;
- ulint size;
-
- ut_ad(rec);
- ut_ad(index);
- ut_ad(heap);
-
- if (dict_table_is_comp(index->table)) {
- switch (UNIV_EXPECT(rec_get_status(rec),
- REC_STATUS_ORDINARY)) {
- case REC_STATUS_ORDINARY:
- 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:
- case REC_STATUS_SUPREMUM:
- /* infimum or supremum record */
- n = 1;
- break;
- default:
- ut_error;
- return(NULL);
- }
- } else {
- n = rec_get_n_fields_old(rec);
- }
-
- if (UNIV_UNLIKELY(n_fields < n)) {
- 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)
- || UNIV_UNLIKELY(rec_offs_get_n_alloc(offsets) < size)) {
- if (UNIV_UNLIKELY(!*heap)) {
- *heap = mem_heap_create_at(size * sizeof(ulint),
- file, line);
- }
- offsets = static_cast<ulint*>(
- mem_heap_alloc(*heap, size * sizeof(ulint)));
-
- rec_offs_set_n_alloc(offsets, size);
- }
-
- rec_offs_set_n_fields(offsets, n);
- rec_init_offsets(rec, index, offsets);
- return(offsets);
-}
-
-/******************************************************//**
-The following function determines the offsets to each field
-in the record. It can reuse a previously allocated array. */
-UNIV_INTERN
-void
-rec_get_offsets_reverse(
-/*====================*/
- const byte* extra, /*!< in: the extra bytes of a
- compact record in reverse order,
- excluding the fixed-size
- REC_N_NEW_EXTRA_BYTES */
- const dict_index_t* index, /*!< in: record descriptor */
- ulint node_ptr,/*!< in: nonzero=node pointer,
- 0=leaf node */
- ulint* offsets)/*!< in/out: array consisting of
- offsets[0] allocated elements */
-{
- ulint n;
- ulint i;
- ulint offs;
- ulint any_ext;
- const byte* nulls;
- const byte* lens;
- dict_field_t* field;
- ulint null_mask;
- ulint n_node_ptr_field;
-
- ut_ad(extra);
- ut_ad(index);
- ut_ad(offsets);
- ut_ad(dict_table_is_comp(index->table));
-
- if (UNIV_UNLIKELY(node_ptr)) {
- n_node_ptr_field = dict_index_get_n_unique_in_tree(index);
- n = n_node_ptr_field + 1;
- } else {
- n_node_ptr_field = ULINT_UNDEFINED;
- n = dict_index_get_n_fields(index);
- }
-
- ut_a(rec_offs_get_n_alloc(offsets) >= n + (1 + REC_OFFS_HEADER_SIZE));
- rec_offs_set_n_fields(offsets, n);
-
- nulls = extra;
- lens = nulls + UT_BITS_IN_BYTES(index->n_nullable);
- i = offs = 0;
- null_mask = 1;
- any_ext = 0;
-
- /* read the lengths of fields 0..n */
- do {
- ulint len;
- if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
- len = offs += REC_NODE_PTR_SIZE;
- goto resolved;
- }
-
- field = dict_index_get_nth_field(index, i);
- if (!(dict_field_get_col(field)->prtype & DATA_NOT_NULL)) {
- /* nullable field => read the null flag */
-
- if (UNIV_UNLIKELY(!(byte) null_mask)) {
- nulls++;
- null_mask = 1;
- }
-
- if (*nulls & null_mask) {
- null_mask <<= 1;
- /* No length is stored for NULL fields.
- We do not advance offs, and we set
- the length to zero and enable the
- SQL NULL flag in offsets[]. */
- len = offs | REC_OFFS_SQL_NULL;
- goto resolved;
- }
- null_mask <<= 1;
- }
-
- if (UNIV_UNLIKELY(!field->fixed_len)) {
- /* Variable-length field: read the length */
- const dict_col_t* col
- = dict_field_get_col(field);
- len = *lens++;
- /* If the maximum length of the field is up
- to 255 bytes, the actual length is always
- stored in one byte. If the maximum length is
- more than 255 bytes, the actual length is
- stored in one byte for 0..127. The length
- will be encoded in two bytes when it is 128 or
- more, or when the field is stored externally. */
- if (UNIV_UNLIKELY(col->len > 255)
- || UNIV_UNLIKELY(col->mtype == DATA_BLOB)) {
- if (len & 0x80) {
- /* 1exxxxxxx xxxxxxxx */
- len <<= 8;
- len |= *lens++;
-
- offs += len & 0x3fff;
- if (UNIV_UNLIKELY(len & 0x4000)) {
- any_ext = REC_OFFS_EXTERNAL;
- len = offs | REC_OFFS_EXTERNAL;
- } else {
- len = offs;
- }
-
- goto resolved;
- }
- }
-
- len = offs += len;
- } else {
- len = offs += field->fixed_len;
- }
-resolved:
- rec_offs_base(offsets)[i + 1] = len;
- } while (++i < rec_offs_n_fields(offsets));
-
- ut_ad(lens >= extra);
- *rec_offs_base(offsets) = (lens - extra + REC_N_NEW_EXTRA_BYTES)
- | REC_OFFS_COMPACT | any_ext;
-}
-
-/************************************************************//**
-The following function is used to get the offset to the nth
-data field in an old-style record.
-@return offset to the field */
-UNIV_INTERN
-ulint
-rec_get_nth_field_offs_old(
-/*=======================*/
- const rec_t* rec, /*!< in: record */
- ulint n, /*!< in: index of the field */
- ulint* len) /*!< out: length of the field;
- UNIV_SQL_NULL if SQL null */
-{
- ulint os;
- ulint next_os;
-
- ut_ad(len);
- ut_a(rec);
- ut_a(n < rec_get_n_fields_old(rec));
-
- if (rec_get_1byte_offs_flag(rec)) {
- os = rec_1_get_field_start_offs(rec, n);
-
- next_os = rec_1_get_field_end_info(rec, n);
-
- if (next_os & REC_1BYTE_SQL_NULL_MASK) {
- *len = UNIV_SQL_NULL;
-
- return(os);
- }
-
- next_os = next_os & ~REC_1BYTE_SQL_NULL_MASK;
- } else {
- os = rec_2_get_field_start_offs(rec, n);
-
- next_os = rec_2_get_field_end_info(rec, n);
-
- if (next_os & REC_2BYTE_SQL_NULL_MASK) {
- *len = UNIV_SQL_NULL;
-
- return(os);
- }
-
- next_os = next_os & ~(REC_2BYTE_SQL_NULL_MASK
- | REC_2BYTE_EXTERN_MASK);
- }
-
- *len = next_os - os;
-
- ut_ad(*len < UNIV_PAGE_SIZE);
-
- return(os);
-}
-
-/**********************************************************//**
-Determines the size of a data tuple prefix in ROW_FORMAT=COMPACT.
-@return total size */
-UNIV_INLINE MY_ATTRIBUTE((warn_unused_result))
-ulint
-rec_get_converted_size_comp_prefix_low(
-/*===================================*/
- const dict_index_t* index, /*!< in: record descriptor;
- dict_table_is_comp() is
- assumed to hold, even if
- it does not */
- const dfield_t* fields, /*!< in: array of data fields */
- ulint n_fields,/*!< in: number of data fields */
- ulint* extra, /*!< out: extra size */
- bool temp) /*!< in: whether this is a
- temporary file record */
-{
- ulint extra_size;
- ulint data_size;
- ulint i;
- 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(n_null)
- : REC_N_NEW_EXTRA_BYTES
- + 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;
- }
-
- /* read the lengths of fields 0..n */
- for (i = 0; i < n_fields; i++) {
- const dict_field_t* field;
- ulint len;
- ulint fixed_len;
- const dict_col_t* col;
-
- field = dict_index_get_nth_field(index, i);
- len = dfield_get_len(&fields[i]);
- col = dict_field_get_col(field);
-
- 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. */
- ut_ad(!(col->prtype & DATA_NOT_NULL));
- continue;
- }
-
- ut_ad(len <= col->len || col->mtype == DATA_BLOB ||
- ((col->mtype == DATA_VARCHAR || col->mtype == DATA_BINARY
- || col->mtype == DATA_VARMYSQL)
- && (col->len == 0
- || len <= col->len)));
-
- fixed_len = field->fixed_len;
- if (temp && fixed_len
- && !dict_col_get_fixed_size(col, temp)) {
- fixed_len = 0;
- }
- /* If the maximum length of a variable-length field
- is up to 255 bytes, the actual length is always stored
- in one byte. If the maximum length is more than 255
- bytes, the actual length is stored in one byte for
- 0..127. The length will be encoded in two bytes when
- it is 128 or more, or when the field is stored externally. */
-
- if (fixed_len) {
-#ifdef UNIV_DEBUG
- ulint mbminlen = DATA_MBMINLEN(col->mbminmaxlen);
- ulint mbmaxlen = DATA_MBMAXLEN(col->mbminmaxlen);
-
- ut_ad(len <= fixed_len);
-
- ut_ad(!mbmaxlen || len >= mbminlen
- * (fixed_len / mbmaxlen));
-
- /* dict_index_add_col() should guarantee this */
- ut_ad(!field->prefix_len
- || fixed_len == field->prefix_len);
-#endif /* UNIV_DEBUG */
- } else if (dfield_is_ext(&fields[i])) {
- ut_ad(col->len >= 256 || col->mtype == DATA_BLOB);
- extra_size += 2;
- } else if (len < 128
- || (col->len < 256
- && col->mtype != DATA_BLOB)) {
- extra_size++;
- } else {
- /* For variable-length columns, we look up the
- maximum length from the column itself. If this
- is a prefix index column shorter than 256 bytes,
- this will waste one byte. */
- extra_size += 2;
- }
- data_size += len;
- }
-
- if (extra) {
- *extra = extra_size;
- }
-
- return(extra_size + data_size);
-}
-
-/**********************************************************//**
-Determines the size of a data tuple prefix in ROW_FORMAT=COMPACT.
-@return total size */
-UNIV_INTERN
-ulint
-rec_get_converted_size_comp_prefix(
-/*===============================*/
- const dict_index_t* index, /*!< in: record descriptor */
- const dfield_t* fields, /*!< in: array of data fields */
- ulint n_fields,/*!< in: number of data fields */
- ulint* extra) /*!< out: extra size */
-{
- ut_ad(dict_table_is_comp(index->table));
- return(rec_get_converted_size_comp_prefix_low(
- index, fields, n_fields, extra, false));
-}
-
-/**********************************************************//**
-Determines the size of a data tuple in ROW_FORMAT=COMPACT.
-@return total size */
-UNIV_INTERN
-ulint
-rec_get_converted_size_comp(
-/*========================*/
- const dict_index_t* index, /*!< in: record descriptor;
- dict_table_is_comp() is
- assumed to hold, even if
- it does not */
- ulint status, /*!< in: status bits of the record */
- const dfield_t* fields, /*!< in: array of data fields */
- ulint n_fields,/*!< in: number of data fields */
- ulint* extra) /*!< out: extra size */
-{
- ulint size;
- ut_ad(n_fields > 0);
-
- switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
- case REC_STATUS_ORDINARY:
- ut_ad(n_fields == dict_index_get_n_fields(index));
- size = 0;
- break;
- case REC_STATUS_NODE_PTR:
- n_fields--;
- ut_ad(n_fields == dict_index_get_n_unique_in_tree(index));
- ut_ad(dfield_get_len(&fields[n_fields]) == REC_NODE_PTR_SIZE);
- size = REC_NODE_PTR_SIZE; /* child page number */
- break;
- case REC_STATUS_INFIMUM:
- case REC_STATUS_SUPREMUM:
- /* infimum or supremum record, 8 data bytes */
- if (UNIV_LIKELY_NULL(extra)) {
- *extra = REC_N_NEW_EXTRA_BYTES;
- }
- return(REC_N_NEW_EXTRA_BYTES + 8);
- default:
- ut_error;
- return(ULINT_UNDEFINED);
- }
-
- return(size + rec_get_converted_size_comp_prefix_low(
- index, fields, n_fields, extra, false));
-}
-
-/***********************************************************//**
-Sets the value of the ith field SQL null bit of an old-style record. */
-UNIV_INTERN
-void
-rec_set_nth_field_null_bit(
-/*=======================*/
- rec_t* rec, /*!< in: record */
- ulint i, /*!< in: ith field */
- ibool val) /*!< in: value to set */
-{
- ulint info;
-
- if (rec_get_1byte_offs_flag(rec)) {
-
- info = rec_1_get_field_end_info(rec, i);
-
- if (val) {
- info = info | REC_1BYTE_SQL_NULL_MASK;
- } else {
- info = info & ~REC_1BYTE_SQL_NULL_MASK;
- }
-
- rec_1_set_field_end_info(rec, i, info);
-
- return;
- }
-
- info = rec_2_get_field_end_info(rec, i);
-
- if (val) {
- info = info | REC_2BYTE_SQL_NULL_MASK;
- } else {
- info = info & ~REC_2BYTE_SQL_NULL_MASK;
- }
-
- rec_2_set_field_end_info(rec, i, info);
-}
-
-/***********************************************************//**
-Sets an old-style record field to SQL null.
-The physical size of the field is not changed. */
-UNIV_INTERN
-void
-rec_set_nth_field_sql_null(
-/*=======================*/
- rec_t* rec, /*!< in: record */
- ulint n) /*!< in: index of the field */
-{
- ulint offset;
-
- offset = rec_get_field_start_offs(rec, n);
-
- data_write_sql_null(rec + offset, rec_get_nth_field_size(rec, n));
-
- rec_set_nth_field_null_bit(rec, n, TRUE);
-}
-
-/*********************************************************//**
-Builds an old-style physical record out of a data tuple and
-stores it beginning from the start of the given buffer.
-@return pointer to the origin of physical record */
-static
-rec_t*
-rec_convert_dtuple_to_rec_old(
-/*==========================*/
- byte* buf, /*!< in: start address of the physical record */
- const dtuple_t* dtuple, /*!< in: data tuple */
- ulint n_ext) /*!< in: number of externally stored columns */
-{
- const dfield_t* field;
- ulint n_fields;
- ulint data_size;
- rec_t* rec;
- ulint end_offset;
- ulint ored_offset;
- ulint len;
- ulint i;
-
- ut_ad(buf && dtuple);
- ut_ad(dtuple_validate(dtuple));
- ut_ad(dtuple_check_typed(dtuple));
-
- n_fields = dtuple_get_n_fields(dtuple);
- data_size = dtuple_get_data_size(dtuple, 0);
-
- ut_ad(n_fields > 0);
-
- /* Calculate the offset of the origin in the physical record */
-
- rec = buf + rec_get_converted_extra_size(data_size, n_fields, n_ext);
-#ifdef UNIV_DEBUG
- /* Suppress Valgrind warnings of ut_ad()
- in mach_write_to_1(), mach_write_to_2() et al. */
- memset(buf, 0xff, rec - buf + data_size);
-#endif /* UNIV_DEBUG */
- /* Store the number of fields */
- rec_set_n_fields_old(rec, n_fields);
-
- /* Set the info bits of the record */
- rec_set_info_bits_old(rec, dtuple_get_info_bits(dtuple)
- & REC_INFO_BITS_MASK);
-
- /* Store the data and the offsets */
-
- end_offset = 0;
-
- if (!n_ext && 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);
-
- if (dfield_is_null(field)) {
- len = dtype_get_sql_null_size(
- dfield_get_type(field), 0);
- 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 */
- len = dfield_get_len(field);
-
- memcpy(rec + end_offset,
- dfield_get_data(field), 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);
-
- if (dfield_is_null(field)) {
- len = dtype_get_sql_null_size(
- dfield_get_type(field), 0);
- 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 */
- len = dfield_get_len(field);
-
- memcpy(rec + end_offset,
- dfield_get_data(field), len);
-
- end_offset += len;
- ored_offset = end_offset;
-
- if (dfield_is_ext(field)) {
- ored_offset |= REC_2BYTE_EXTERN_MASK;
- }
- }
-
- rec_2_set_field_end_info(rec, i, ored_offset);
- }
- }
-
- return(rec);
-}
-
-/*********************************************************//**
-Builds a ROW_FORMAT=COMPACT record out of a data tuple. */
-UNIV_INLINE MY_ATTRIBUTE((nonnull))
-void
-rec_convert_dtuple_to_rec_comp(
-/*===========================*/
- rec_t* rec, /*!< in: origin of record */
- const dict_index_t* index, /*!< in: record descriptor */
- 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 */
- bool temp) /*!< in: whether to use the
- format for temporary files in
- index creation */
-{
- const dfield_t* field;
- const dtype_t* type;
- byte* end;
- byte* nulls;
- byte* lens;
- ulint len;
- ulint i;
- 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);
-
- if (temp) {
- ut_ad(status == REC_STATUS_ORDINARY);
- ut_ad(n_fields <= dict_index_get_n_fields(index));
- n_node_ptr_field = ULINT_UNDEFINED;
- nulls = rec - 1;
- 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;
- }
- } else {
- nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
-
- switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
- case REC_STATUS_ORDINARY:
- ut_ad(n_fields <= dict_index_get_n_fields(index));
- n_node_ptr_field = ULINT_UNDEFINED;
- break;
- case REC_STATUS_NODE_PTR:
- ut_ad(n_fields
- == dict_index_get_n_unique_in_tree(index) + 1);
- n_node_ptr_field = n_fields - 1;
- break;
- case REC_STATUS_INFIMUM:
- case REC_STATUS_SUPREMUM:
- ut_ad(n_fields == 1);
- n_node_ptr_field = ULINT_UNDEFINED;
- break;
- default:
- ut_error;
- return;
- }
- }
-
- end = rec;
- n_null = index->n_nullable;
- lens = nulls - UT_BITS_IN_BYTES(n_null);
- /* clear the SQL-null flags */
- memset(lens + 1, 0, nulls - lens);
-
- /* Store the data and the offsets */
-
- for (i = 0, field = fields; i < n_fields; i++, field++) {
- const dict_field_t* ifield;
-
- type = dfield_get_type(field);
- len = dfield_get_len(field);
-
- if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
- ut_ad(dtype_get_prtype(type) & DATA_NOT_NULL);
- ut_ad(len == REC_NODE_PTR_SIZE);
- memcpy(end, dfield_get_data(field), len);
- end += REC_NODE_PTR_SIZE;
- break;
- }
-
- if (!(dtype_get_prtype(type) & DATA_NOT_NULL)) {
- /* nullable field */
- ut_ad(n_null--);
-
- if (UNIV_UNLIKELY(!(byte) null_mask)) {
- nulls--;
- null_mask = 1;
- }
-
- ut_ad(*nulls < null_mask);
-
- /* set the null flag if necessary */
- if (dfield_is_null(field)) {
- *nulls |= null_mask;
- null_mask <<= 1;
- continue;
- }
-
- null_mask <<= 1;
- }
- /* only nullable fields can be null */
- ut_ad(!dfield_is_null(field));
-
- ifield = dict_index_get_nth_field(index, i);
- fixed_len = ifield->fixed_len;
- if (temp && fixed_len
- && !dict_col_get_fixed_size(ifield->col, temp)) {
- fixed_len = 0;
- }
- /* If the maximum length of a variable-length field
- is up to 255 bytes, the actual length is always stored
- in one byte. If the maximum length is more than 255
- bytes, the actual length is stored in one byte for
- 0..127. The length will be encoded in two bytes when
- it is 128 or more, or when the field is stored externally. */
- if (fixed_len) {
-#ifdef UNIV_DEBUG
- ulint mbminlen = DATA_MBMINLEN(
- ifield->col->mbminmaxlen);
- ulint mbmaxlen = DATA_MBMAXLEN(
- ifield->col->mbminmaxlen);
-
- ut_ad(len <= fixed_len);
- ut_ad(!mbmaxlen || len >= mbminlen
- * (fixed_len / mbmaxlen));
- ut_ad(!dfield_is_ext(field));
-#endif /* UNIV_DEBUG */
- } else if (dfield_is_ext(field)) {
- ut_ad(ifield->col->len >= 256
- || ifield->col->mtype == DATA_BLOB);
- ut_ad(len <= REC_ANTELOPE_MAX_INDEX_COL_LEN
- + BTR_EXTERN_FIELD_REF_SIZE);
- *lens-- = (byte) (len >> 8) | 0xc0;
- *lens-- = (byte) len;
- } else {
- ut_ad(len <= dtype_get_len(type)
- || 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)) {
-
- *lens-- = (byte) len;
- } else {
- ut_ad(len < 16384);
- *lens-- = (byte) (len >> 8) | 0x80;
- *lens-- = (byte) len;
- }
- }
-
- if (len) {
- memcpy(end, dfield_get_data(field), len);
- end += len;
- }
- }
-}
-
-/*********************************************************//**
-Builds a new-style physical record out of a data tuple and
-stores it beginning from the start of the given buffer.
-@return pointer to the origin of physical record */
-static
-rec_t*
-rec_convert_dtuple_to_rec_new(
-/*==========================*/
- byte* buf, /*!< in: start address of
- the physical record */
- const dict_index_t* index, /*!< in: record descriptor */
- const dtuple_t* dtuple) /*!< in: data tuple */
-{
- ulint extra_size;
- ulint status;
- 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 = buf + extra_size;
-
- rec_convert_dtuple_to_rec_comp(
- 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));
-
- return(rec);
-}
-
-/*********************************************************//**
-Builds a physical record out of a data tuple and
-stores it beginning from the start of the given buffer.
-@return pointer to the origin of physical record */
-UNIV_INTERN
-rec_t*
-rec_convert_dtuple_to_rec(
-/*======================*/
- byte* buf, /*!< in: start address of the
- physical record */
- const dict_index_t* index, /*!< in: record descriptor */
- const dtuple_t* dtuple, /*!< in: data tuple */
- ulint n_ext) /*!< in: number of
- externally stored columns */
-{
- rec_t* rec;
-
- ut_ad(buf != NULL);
- ut_ad(index != NULL);
- ut_ad(dtuple != NULL);
- ut_ad(dtuple_validate(dtuple));
- ut_ad(dtuple_check_typed(dtuple));
-
- if (dict_table_is_comp(index->table)) {
- rec = rec_convert_dtuple_to_rec_new(buf, index, dtuple);
- } else {
- rec = rec_convert_dtuple_to_rec_old(buf, dtuple, n_ext);
- }
-
-#ifdef UNIV_DEBUG
- {
- mem_heap_t* heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- const ulint* offsets;
- ulint i;
- rec_offs_init(offsets_);
-
- offsets = rec_get_offsets(rec, index,
- offsets_, ULINT_UNDEFINED, &heap);
- ut_ad(rec_validate(rec, offsets));
- ut_ad(dtuple_get_n_fields(dtuple)
- == rec_offs_n_fields(offsets));
-
- for (i = 0; i < rec_offs_n_fields(offsets); i++) {
- ut_ad(!dfield_is_ext(dtuple_get_nth_field(dtuple, i))
- == !rec_offs_nth_extern(offsets, i));
- }
-
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
- }
-#endif /* UNIV_DEBUG */
- return(rec);
-}
-
-#ifndef UNIV_HOTBACKUP
-/**********************************************************//**
-Determines the size of a data tuple prefix in ROW_FORMAT=COMPACT.
-@return total size */
-UNIV_INTERN
-ulint
-rec_get_converted_size_temp(
-/*========================*/
- const dict_index_t* index, /*!< in: record descriptor */
- const dfield_t* fields, /*!< in: array of data fields */
- ulint n_fields,/*!< in: number of data fields */
- ulint* extra) /*!< out: extra size */
-{
- return(rec_get_converted_size_comp_prefix_low(
- index, fields, n_fields, extra, true));
-}
-
-/******************************************************//**
-Determine the offset to each field in temporary file.
-@see rec_convert_dtuple_to_temp() */
-UNIV_INTERN
-void
-rec_init_offsets_temp(
-/*==================*/
- const rec_t* rec, /*!< in: temporary file record */
- const dict_index_t* index, /*!< in: record descriptor */
- ulint* offsets)/*!< in/out: array of offsets;
- in: n=rec_offs_n_fields(offsets) */
-{
- rec_init_offsets_comp_ordinary(rec, true, index, offsets);
-}
-
-/*********************************************************//**
-Builds a temporary file record out of a data tuple.
-@see rec_init_offsets_temp() */
-UNIV_INTERN
-void
-rec_convert_dtuple_to_temp(
-/*=======================*/
- rec_t* rec, /*!< out: record */
- const dict_index_t* index, /*!< in: record descriptor */
- const dfield_t* fields, /*!< in: array of data fields */
- ulint n_fields) /*!< in: number of fields */
-{
- rec_convert_dtuple_to_rec_comp(rec, index, fields, n_fields,
- REC_STATUS_ORDINARY, true);
-}
-
-/**************************************************************//**
-Copies the first n fields of a physical record to a data tuple. The fields
-are copied to the memory heap. */
-UNIV_INTERN
-void
-rec_copy_prefix_to_dtuple(
-/*======================*/
- dtuple_t* tuple, /*!< out: data tuple */
- const rec_t* rec, /*!< in: physical record */
- const dict_index_t* index, /*!< in: record descriptor */
- ulint n_fields, /*!< in: number of fields
- to copy */
- mem_heap_t* heap) /*!< in: memory heap */
-{
- ulint i;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- ulint* offsets = offsets_;
- rec_offs_init(offsets_);
-
- offsets = rec_get_offsets(rec, index, offsets, n_fields, &heap);
-
- ut_ad(rec_validate(rec, offsets));
- ut_ad(dtuple_check_typed(tuple));
-
- dtuple_set_info_bits(tuple, rec_get_info_bits(
- rec, dict_table_is_comp(index->table)));
-
- for (i = 0; i < n_fields; i++) {
- dfield_t* field;
- const byte* data;
- ulint len;
-
- field = dtuple_get_nth_field(tuple, i);
- data = rec_get_nth_field(rec, offsets, i, &len);
-
- if (len != UNIV_SQL_NULL) {
- dfield_set_data(field,
- mem_heap_dup(heap, data, len), len);
- ut_ad(!rec_offs_nth_extern(offsets, i));
- } else {
- dfield_set_null(field);
- }
- }
-}
-
-/**************************************************************//**
-Copies the first n fields of an old-style physical record
-to a new physical record in a buffer.
-@return own: copied record */
-static
-rec_t*
-rec_copy_prefix_to_buf_old(
-/*=======================*/
- const rec_t* rec, /*!< in: physical record */
- ulint n_fields, /*!< in: number of fields to copy */
- ulint area_end, /*!< in: end of the prefix data */
- byte** buf, /*!< in/out: memory buffer for
- the copied prefix, or NULL */
- ulint* buf_size) /*!< in/out: buffer size */
-{
- rec_t* copy_rec;
- ulint area_start;
- ulint prefix_len;
-
- if (rec_get_1byte_offs_flag(rec)) {
- area_start = REC_N_OLD_EXTRA_BYTES + n_fields;
- } else {
- area_start = REC_N_OLD_EXTRA_BYTES + 2 * n_fields;
- }
-
- prefix_len = area_start + area_end;
-
- if ((*buf == NULL) || (*buf_size < prefix_len)) {
- if (*buf != NULL) {
- mem_free(*buf);
- }
-
- *buf = static_cast<byte*>(mem_alloc2(prefix_len, buf_size));
- }
-
- ut_memcpy(*buf, rec - area_start, prefix_len);
-
- copy_rec = *buf + area_start;
-
- rec_set_n_fields_old(copy_rec, n_fields);
-
- return(copy_rec);
-}
-
-/**************************************************************//**
-Copies the first n fields of a physical record to a new physical record in
-a buffer.
-@return own: copied record */
-UNIV_INTERN
-rec_t*
-rec_copy_prefix_to_buf(
-/*===================*/
- const rec_t* rec, /*!< in: physical record */
- const dict_index_t* index, /*!< in: record descriptor */
- ulint n_fields, /*!< in: number of fields
- to copy */
- byte** buf, /*!< in/out: memory buffer
- for the copied prefix,
- or NULL */
- ulint* buf_size) /*!< in/out: buffer size */
-{
- const byte* nulls;
- const byte* lens;
- ulint i;
- ulint prefix_len;
- ulint null_mask;
- ulint status;
-
- UNIV_PREFETCH_RW(*buf);
-
- if (!dict_table_is_comp(index->table)) {
- ut_ad(rec_validate_old(rec));
- return(rec_copy_prefix_to_buf_old(
- rec, n_fields,
- rec_get_field_start_offs(rec, n_fields),
- buf, buf_size));
- }
-
- status = rec_get_status(rec);
-
- switch (status) {
- case REC_STATUS_ORDINARY:
- ut_ad(n_fields <= dict_index_get_n_fields(index));
- break;
- case REC_STATUS_NODE_PTR:
- /* it doesn't make sense to copy the child page number field */
- ut_ad(n_fields <= dict_index_get_n_unique_in_tree(index));
- break;
- case REC_STATUS_INFIMUM:
- case REC_STATUS_SUPREMUM:
- /* infimum or supremum record: no sense to copy anything */
- default:
- ut_error;
- return(NULL);
- }
-
- nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
- lens = nulls - UT_BITS_IN_BYTES(index->n_nullable);
- UNIV_PREFETCH_R(lens);
- prefix_len = 0;
- null_mask = 1;
-
- /* read the lengths of fields 0..n */
- for (i = 0; i < n_fields; i++) {
- const dict_field_t* field;
- const dict_col_t* col;
-
- field = dict_index_get_nth_field(index, i);
- col = dict_field_get_col(field);
-
- if (!(col->prtype & DATA_NOT_NULL)) {
- /* nullable field => read the null flag */
- if (UNIV_UNLIKELY(!(byte) null_mask)) {
- nulls--;
- null_mask = 1;
- }
-
- if (*nulls & null_mask) {
- null_mask <<= 1;
- continue;
- }
-
- null_mask <<= 1;
- }
-
- if (field->fixed_len) {
- prefix_len += field->fixed_len;
- } else {
- ulint len = *lens--;
- /* If the maximum length of the column is up
- to 255 bytes, the actual length is always
- stored in one byte. If the maximum length is
- more than 255 bytes, the actual length is
- stored in one byte for 0..127. The length
- will be encoded in two bytes when it is 128 or
- more, or when the column is stored externally. */
- if (col->len > 255 || col->mtype == DATA_BLOB) {
- if (len & 0x80) {
- /* 1exxxxxx */
- len &= 0x3f;
- len <<= 8;
- len |= *lens--;
- UNIV_PREFETCH_R(lens);
- }
- }
- prefix_len += len;
- }
- }
-
- UNIV_PREFETCH_R(rec + prefix_len);
-
- prefix_len += rec - (lens + 1);
-
- if ((*buf == NULL) || (*buf_size < prefix_len)) {
- if (*buf != NULL) {
- mem_free(*buf);
- }
-
- *buf = static_cast<byte*>(mem_alloc2(prefix_len, buf_size));
- }
-
- memcpy(*buf, lens + 1, prefix_len);
-
- return(*buf + (rec - (lens + 1)));
-}
-#endif /* UNIV_HOTBACKUP */
-
-/***************************************************************//**
-Validates the consistency of an old-style physical record.
-@return TRUE if ok */
-static
-ibool
-rec_validate_old(
-/*=============*/
- const rec_t* rec) /*!< in: physical record */
-{
- const byte* data;
- ulint len;
- ulint n_fields;
- ulint len_sum = 0;
- ulint sum = 0;
- ulint i;
-
- ut_a(rec);
- n_fields = rec_get_n_fields_old(rec);
-
- if ((n_fields == 0) || (n_fields > REC_MAX_N_FIELDS)) {
- fprintf(stderr, "InnoDB: Error: record has %lu fields\n",
- (ulong) n_fields);
- return(FALSE);
- }
-
- for (i = 0; i < n_fields; i++) {
- data = rec_get_nth_field_old(rec, i, &len);
-
- if (!((len < UNIV_PAGE_SIZE) || (len == UNIV_SQL_NULL))) {
- fprintf(stderr,
- "InnoDB: Error: record field %lu len %lu\n",
- (ulong) i,
- (ulong) len);
- return(FALSE);
- }
-
- if (len != UNIV_SQL_NULL) {
- len_sum += len;
- sum += *(data + len -1); /* dereference the
- end of the field to
- cause a memory trap
- if possible */
- } else {
- len_sum += rec_get_nth_field_size(rec, i);
- }
- }
-
- if (len_sum != rec_get_data_size_old(rec)) {
- fprintf(stderr,
- "InnoDB: Error: record len should be %lu, len %lu\n",
- (ulong) len_sum,
- rec_get_data_size_old(rec));
- return(FALSE);
- }
-
- rec_dummy = sum; /* This is here only to fool the compiler */
-
- return(TRUE);
-}
-
-/***************************************************************//**
-Validates the consistency of a physical record.
-@return TRUE if ok */
-UNIV_INTERN
-ibool
-rec_validate(
-/*=========*/
- const rec_t* rec, /*!< in: physical record */
- const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
-{
- const byte* data;
- ulint len;
- ulint n_fields;
- ulint len_sum = 0;
- ulint sum = 0;
- ulint i;
-
- ut_a(rec);
- n_fields = rec_offs_n_fields(offsets);
-
- if ((n_fields == 0) || (n_fields > REC_MAX_N_FIELDS)) {
- fprintf(stderr, "InnoDB: Error: record has %lu fields\n",
- (ulong) n_fields);
- return(FALSE);
- }
-
- ut_a(rec_offs_comp(offsets) || n_fields <= rec_get_n_fields_old(rec));
-
- for (i = 0; i < n_fields; i++) {
- data = rec_get_nth_field(rec, offsets, i, &len);
-
- if (!((len < UNIV_PAGE_SIZE) || (len == UNIV_SQL_NULL))) {
- fprintf(stderr,
- "InnoDB: Error: record field %lu len %lu\n",
- (ulong) i,
- (ulong) len);
- return(FALSE);
- }
-
- if (len != UNIV_SQL_NULL) {
- len_sum += len;
- sum += *(data + len -1); /* dereference the
- end of the field to
- cause a memory trap
- if possible */
- } else if (!rec_offs_comp(offsets)) {
- len_sum += rec_get_nth_field_size(rec, i);
- }
- }
-
- if (len_sum != rec_offs_data_size(offsets)) {
- fprintf(stderr,
- "InnoDB: Error: record len should be %lu, len %lu\n",
- (ulong) len_sum,
- (ulong) rec_offs_data_size(offsets));
- return(FALSE);
- }
-
- rec_dummy = sum; /* This is here only to fool the compiler */
-
- if (!rec_offs_comp(offsets)) {
- ut_a(rec_validate_old(rec));
- }
-
- return(TRUE);
-}
-
-/***************************************************************//**
-Prints an old-style physical record. */
-UNIV_INTERN
-void
-rec_print_old(
-/*==========*/
- FILE* file, /*!< in: file where to print */
- const rec_t* rec) /*!< in: physical record */
-{
- const byte* data;
- ulint len;
- ulint n;
- ulint i;
-
- ut_ad(rec);
-
- n = rec_get_n_fields_old(rec);
-
- fprintf(file, "PHYSICAL RECORD: n_fields %lu;"
- " %u-byte offsets; info bits %lu\n",
- (ulong) n,
- rec_get_1byte_offs_flag(rec) ? 1 : 2,
- (ulong) rec_get_info_bits(rec, FALSE));
-
- for (i = 0; i < n; i++) {
-
- data = rec_get_nth_field_old(rec, i, &len);
-
- fprintf(file, " %lu:", (ulong) i);
-
- if (len != UNIV_SQL_NULL) {
- if (len <= 30) {
-
- ut_print_buf(file, data, len);
- } else {
- ut_print_buf(file, data, 30);
-
- fprintf(file, " (total %lu bytes)",
- (ulong) len);
- }
- } else {
- fprintf(file, " SQL NULL, size %lu ",
- rec_get_nth_field_size(rec, i));
- }
-
- putc(';', file);
- putc('\n', file);
- }
-
- rec_validate_old(rec);
-}
-
-#ifndef UNIV_HOTBACKUP
-/***************************************************************//**
-Prints a physical record in ROW_FORMAT=COMPACT. Ignores the
-record header. */
-UNIV_INTERN
-void
-rec_print_comp(
-/*===========*/
- FILE* file, /*!< in: file where to print */
- const rec_t* rec, /*!< in: physical record */
- const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
-{
- ulint i;
-
- for (i = 0; i < rec_offs_n_fields(offsets); i++) {
- const byte* data;
- ulint len;
-
- data = rec_get_nth_field(rec, offsets, i, &len);
-
- fprintf(file, " %lu:", (ulong) i);
-
- if (len != UNIV_SQL_NULL) {
- 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);
-
- fprintf(file, " (total %lu bytes)",
- (ulong) len);
- }
- } else {
- fputs(" SQL NULL", file);
- }
- putc(';', file);
- putc('\n', file);
- }
-}
-
-/***************************************************************//**
-Prints a physical record. */
-UNIV_INTERN
-void
-rec_print_new(
-/*==========*/
- FILE* file, /*!< in: file where to print */
- const rec_t* rec, /*!< in: physical record */
- const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
-{
- ut_ad(rec);
- ut_ad(offsets);
- ut_ad(rec_offs_validate(rec, NULL, offsets));
-
- if (!rec_offs_comp(offsets)) {
- rec_print_old(file, rec);
- return;
- }
-
- fprintf(file, "PHYSICAL RECORD: n_fields %lu;"
- " compact format; info bits %lu\n",
- (ulong) rec_offs_n_fields(offsets),
- (ulong) rec_get_info_bits(rec, TRUE));
-
- rec_print_comp(file, rec, offsets);
- rec_validate(rec, offsets);
-}
-
-/***************************************************************//**
-Prints a physical record. */
-UNIV_INTERN
-void
-rec_print(
-/*======*/
- FILE* file, /*!< in: file where to print */
- const rec_t* rec, /*!< in: physical record */
- const dict_index_t* index) /*!< in: record descriptor */
-{
- ut_ad(index);
-
- if (!dict_table_is_comp(index->table)) {
- rec_print_old(file, rec);
- return;
- } else {
- mem_heap_t* heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- rec_offs_init(offsets_);
-
- rec_print_new(file, rec,
- rec_get_offsets(rec, index, offsets_,
- ULINT_UNDEFINED, &heap));
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
- }
-}
-#endif /* !UNIV_HOTBACKUP */
-
-#ifdef WITH_WSREP
-int
-wsrep_rec_get_foreign_key(
- byte *buf, /* out: extracted key */
- ulint *buf_len, /* in/out: length of buf */
- const rec_t* rec, /* in: physical record */
- dict_index_t* index_for, /* in: index in foreign table */
- dict_index_t* index_ref, /* in: index in referenced table */
- ibool new_protocol) /* in: protocol > 1 */
-{
- const byte* data;
- ulint len;
- ulint key_len = 0;
- ulint i;
- uint key_parts;
- mem_heap_t* heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- const ulint* offsets;
-
- ut_ad(index_for);
- ut_ad(index_ref);
-
- rec_offs_init(offsets_);
- offsets = rec_get_offsets(rec, index_for, offsets_,
- ULINT_UNDEFINED, &heap);
-
- ut_ad(rec_offs_validate(rec, NULL, offsets));
-
- ut_ad(rec);
-
- key_parts = dict_index_get_n_unique_in_tree(index_for);
- for (i = 0;
- i < key_parts &&
- (index_for->type & DICT_CLUSTERED || i < key_parts - 1);
- i++) {
- dict_field_t* field_f =
- dict_index_get_nth_field(index_for, i);
- const dict_col_t* col_f = dict_field_get_col(field_f);
- dict_field_t* field_r =
- dict_index_get_nth_field(index_ref, i);
- const dict_col_t* col_r = dict_field_get_col(field_r);
-
- data = rec_get_nth_field(rec, offsets, i, &len);
- if (key_len + ((len != UNIV_SQL_NULL) ? len + 1 : 1) >
- *buf_len) {
- fprintf (stderr,
- "WSREP: FK key len exceeded %lu %lu %lu\n",
- key_len, len, *buf_len);
- goto err_out;
- }
-
- if (len == UNIV_SQL_NULL) {
- ut_a(!(col_f->prtype & DATA_NOT_NULL));
- *buf++ = 1;
- key_len++;
- } else if (!new_protocol) {
- if (!(col_r->prtype & DATA_NOT_NULL)) {
- *buf++ = 0;
- key_len++;
- }
- memcpy(buf, data, len);
- *buf_len = wsrep_innobase_mysql_sort(
- (int)(col_f->prtype & DATA_MYSQL_TYPE_MASK),
- (uint)dtype_get_charset_coll(col_f->prtype),
- buf, len, *buf_len);
- } else { /* new protocol */
- if (!(col_r->prtype & DATA_NOT_NULL)) {
- *buf++ = 0;
- key_len++;
- }
- switch (col_f->mtype) {
- case DATA_INT: {
- byte* ptr = buf+len;
- for (;;) {
- ptr--;
- *ptr = *data;
- if (ptr == buf) {
- break;
- }
- data++;
- }
-
- if (!(col_f->prtype & DATA_UNSIGNED)) {
- buf[len-1] = (byte) (buf[len-1] ^ 128);
- }
-
- break;
- }
- case DATA_VARCHAR:
- case DATA_VARMYSQL:
- case DATA_CHAR:
- case DATA_MYSQL:
- /* Copy the actual data */
- ut_memcpy(buf, data, len);
- len = wsrep_innobase_mysql_sort(
- (int)
- (col_f->prtype & DATA_MYSQL_TYPE_MASK),
- (uint)
- dtype_get_charset_coll(col_f->prtype),
- buf, len, *buf_len);
- break;
- case DATA_BLOB:
- case DATA_BINARY:
- memcpy(buf, data, len);
- break;
- default:
- break;
- }
-
- key_len += len;
- buf += len;
- }
- }
-
- rec_validate(rec, offsets);
-
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
-
- *buf_len = key_len;
- return DB_SUCCESS;
-
- err_out:
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
- return DB_ERROR;
-}
-#endif /* WITH_WSREP */
-
-# 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 */
-