Commit fbe49648 authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-11369: Introduce REC_STATUS_COLUMNS_ADDED

For ROW_FORMAT=DYNAMIC and ROW_FORMAT=COMPACT records, we have to
identify whether the record contains more columns than when the
clustered index tree was originally created. In this case, the
number of fields
(FIXME: number_of_added_fields-1, not the total number of fields)
needs to be written to the record header.

rec_comp_status_t: An enum of the status bit values.

rec_leaf_format: An enum that replaces the bool parameter of
rec_init_offsets_comp_ordinary().

rec_get_converted_size_comp(): Do not support infimum,supremum.
They are never supposed to be stored in dtuple_t, as page creation
nowadays uses a lower-level method for inserting them.

innobase_add_instant_try(): Initialize the dtuple_t::info_bits
appropriately to REC_INFO_MIN_REC_FLAG | REC_STATUS_COLUMNS_ADDED
so that it can be inserted into a ROW_FORMAT!=REDUNDANT table.
parent 116d494f
......@@ -3303,7 +3303,8 @@ fts_fetch_doc_from_rec(
parser = get_doc->index_cache->index->parser;
clust_rec = btr_pcur_get_rec(pcur);
ut_ad(!page_rec_is_comp(clust_rec) || !rec_is_instant(clust_rec));
ut_ad(!page_rec_is_comp(clust_rec)
|| rec_get_status(clust_rec) == REC_STATUS_ORDINARY);
num_field = dict_index_get_n_fields(index);
......
......@@ -4343,7 +4343,7 @@ innobase_add_instant_try(
pars_info_add_int4_literal(info, "id", user_table->id);
dtuple_t* entry = row_build_index_entry(row, NULL, index, ctx->heap);
entry->info_bits = REC_INFO_MIN_REC_FLAG;
entry->info_bits = REC_INFO_MIN_REC_FLAG | REC_STATUS_COLUMNS_ADDED;
dberr_t err = que_eval_sql(
info,
......
......@@ -47,8 +47,6 @@ B-tree page that is the leftmost page on its level
/* The deleted flag in info bits */
#define REC_INFO_DELETED_FLAG 0x20UL /* when bit is set to 1, it means the
record has been delete marked */
#define REC_INFO_ADDED_FLAG 0x80UL /* when bit is set to 1, it means the
record has been instant added columns */
/* Number of extra bytes in an old-style record,
in addition to the data and the offsets */
......@@ -57,16 +55,24 @@ in addition to the data and the offsets */
in addition to the data and the offsets */
#define REC_N_NEW_EXTRA_BYTES 5
/* Record status values */
#define REC_STATUS_ORDINARY 0
#define REC_STATUS_NODE_PTR 1
#define REC_STATUS_INFIMUM 2
#define REC_STATUS_SUPREMUM 3
/** Record status values for ROW_FORMAT=COMPACT,DYNAMIC,COMPRESSED */
enum rec_comp_status_t {
/** User record (PAGE_LEVEL=0, heap>=PAGE_HEAP_NO_USER_LOW) */
REC_STATUS_ORDINARY = 0,
/** Node pointer record (PAGE_LEVEL>=0, heap>=PAGE_HEAP_NO_USER_LOW) */
REC_STATUS_NODE_PTR = 1,
/** The page infimum pseudo-record (heap=PAGE_HEAP_NO_INFIMUM) */
REC_STATUS_INFIMUM = 2,
/** The page supremum pseudo-record (heap=PAGE_HEAP_NO_SUPREMUM) */
REC_STATUS_SUPREMUM = 3,
/** Clustered index record that has been inserted or updated
after instant ADD COLUMN (more than dict_index_t::n_core_fields) */
REC_STATUS_COLUMNS_ADDED = 4
};
/* REC_FLAG for instant add columns */
#define REC_FLAG_NONE 0x00
#define REC_FLAG_INSTANT 0x01
#define REC_FLAG_NODE_PTR 0x02
#define REC_NEW_STATUS 3 /* This is single byte bit-field */
#define REC_NEW_STATUS_MASK 0x7UL
#define REC_NEW_STATUS_SHIFT 0
/* The following four constants are needed in page0zip.cc in order to
efficiently compress and decompress pages. */
......@@ -276,25 +282,30 @@ rec_set_info_bits_new(
rec_t* rec, /*!< in/out: new-style physical record */
ulint bits) /*!< in: info bits */
MY_ATTRIBUTE((nonnull));
/******************************************************//**
The following function retrieves the status bits of a new-style record.
/** Determine the status bits of a non-REDUNDANT record.
@param[in] rec ROW_FORMAT=COMPACT,DYNAMIC,COMPRESSED record
@return status bits */
UNIV_INLINE
ulint
rec_get_status(
/*===========*/
const rec_t* rec) /*!< in: physical record */
MY_ATTRIBUTE((warn_unused_result));
inline
rec_comp_status_t
rec_get_status(const rec_t* rec)
{
byte bits = rec[-REC_NEW_STATUS] & REC_NEW_STATUS_MASK;
ut_ad(bits <= REC_STATUS_COLUMNS_ADDED);
return static_cast<rec_comp_status_t>(bits);
}
/******************************************************//**
The following function is used to set the status bits of a new-style record. */
UNIV_INLINE
/** Set the status bits of a non-REDUNDANT record.
@param[in,out] rec ROW_FORMAT=COMPACT,DYNAMIC,COMPRESSED record
@param[in] bits status bits */
inline
void
rec_set_status(
/*===========*/
rec_t* rec, /*!< in/out: physical record */
ulint bits) /*!< in: info bits */
MY_ATTRIBUTE((nonnull));
rec_set_status(rec_t* rec, byte bits)
{
ut_ad(bits <= REC_STATUS_COLUMNS_ADDED);
rec[-REC_NEW_STATUS] = (rec[-REC_NEW_STATUS] & ~REC_NEW_STATUS_MASK)
| bits;
}
/******************************************************//**
The following function is used to retrieve the info and status
......@@ -1055,7 +1066,7 @@ rec_get_converted_size_comp(
dict_table_is_comp() is
assumed to hold, even if
it does not */
ulint status, /*!< in: status bits of the record */
rec_comp_status_t 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 */
......@@ -1145,31 +1156,6 @@ rec_print(
ulint info,
const ulint* offsets);
/******************************************************//**
set instant flag */
UNIV_INLINE
void
rec_set_instant_flag(
/*=====================*/
rec_t* rec, /*!< in/out: new-style physical record */
ulint flag); /*!< in: nonzero if instant marked */
/******************************************************//**
@return TRUE if instant record type */
UNIV_INLINE
ibool
rec_is_instant(
/*=====================*/
const rec_t* rec); /*!< in: new-style physical record */
/**********************************************************//**
Returns length of field count input
@return size */
UNIV_INLINE
ulint rec_get_field_count_len (
/*==========*/
ulint field_count ); /*!< in: field count*/
/**********************************************************//**
Returns field count of instant record
@return size */
......
......@@ -89,10 +89,6 @@ and the shift needed to obtain each bit-field of the record. */
#define REC_OLD_N_FIELDS_MASK 0x7FEUL
#define REC_OLD_N_FIELDS_SHIFT 1
#define REC_NEW_STATUS 3 /* This is single byte bit-field */
#define REC_NEW_STATUS_MASK 0x7UL
#define REC_NEW_STATUS_SHIFT 0
#define REC_OLD_HEAP_NO 5
#define REC_HEAP_NO_MASK 0xFFF8UL
#if 0 /* defined in rem0rec.h for use of page0zip.cc */
......@@ -446,26 +442,6 @@ rec_set_n_fields_old(
REC_OLD_N_FIELDS_MASK, REC_OLD_N_FIELDS_SHIFT);
}
/******************************************************//**
The following function retrieves the status bits of a new-style record.
@return status bits */
UNIV_INLINE
ulint
rec_get_status(
/*===========*/
const rec_t* rec) /*!< in: physical record */
{
ulint ret;
ut_ad(rec);
ret = rec_get_bit_field_1(rec, REC_NEW_STATUS,
REC_NEW_STATUS_MASK, REC_NEW_STATUS_SHIFT);
ut_ad((ret & ~REC_NEW_STATUS_MASK) == 0);
return(ret);
}
/******************************************************//**
The following function is used to get the number of fields
in a record.
......@@ -485,6 +461,7 @@ rec_get_n_fields(
}
switch (rec_get_status(rec)) {
case REC_STATUS_COLUMNS_ADDED:
case REC_STATUS_ORDINARY:
return(dict_index_get_n_fields(index));
case REC_STATUS_NODE_PTR:
......@@ -492,10 +469,10 @@ rec_get_n_fields(
case REC_STATUS_INFIMUM:
case REC_STATUS_SUPREMUM:
return(1);
default:
}
ut_error;
return(ULINT_UNDEFINED);
}
}
/** Confirms the n_fields of the entry is sane with comparing the other
......@@ -589,7 +566,7 @@ bool
rec_info_bits_valid(
ulint bits)
{
return(0 == (bits & ~(REC_INFO_DELETED_FLAG | REC_INFO_MIN_REC_FLAG | REC_INFO_ADDED_FLAG)));
return(0 == (bits & ~(REC_INFO_DELETED_FLAG | REC_INFO_MIN_REC_FLAG)));
}
#endif /* UNIV_DEBUG */
......@@ -637,19 +614,6 @@ rec_set_info_bits_new(
REC_INFO_BITS_MASK, REC_INFO_BITS_SHIFT);
}
/******************************************************//**
The following function is used to set the status bits of a new-style record. */
UNIV_INLINE
void
rec_set_status(
/*===========*/
rec_t* rec, /*!< in/out: physical record */
ulint bits) /*!< in: info bits */
{
rec_set_bit_field_1(rec, bits, REC_NEW_STATUS,
REC_NEW_STATUS_MASK, REC_NEW_STATUS_SHIFT);
}
/******************************************************//**
The following function is used to retrieve the info and status
bits of a record. (Only compact records have status bits.)
......@@ -1368,44 +1332,6 @@ rec_offs_size(
return(rec_offs_data_size(offsets) + rec_offs_extra_size(offsets));
}
/******************************************************//**
set instant flag */
UNIV_INLINE
void
rec_set_instant_flag(
/*=====================*/
rec_t* rec, /*!< in/out: new-style physical record */
ulint flag) /*!< in: nonzero if instant marked */
{
ulint val;
val = rec_get_info_bits(rec, TRUE);
if (flag) {
val |= REC_INFO_ADDED_FLAG;
} else {
val &= ~REC_INFO_ADDED_FLAG;
}
rec_set_info_bits_new(rec, val);
}
/******************************************************//**
@return TRUE if instant record type */
UNIV_INLINE
ibool
rec_is_instant(
/*=====================*/
const rec_t* rec) /*!< in: new-style physical record */
{
ulint val;
val = rec_get_info_bits(rec, TRUE);
return (val & REC_INFO_ADDED_FLAG) != 0;
}
#define REC_FIELD_COUNT_TWO_BYTES_FLAG 0x80
#define REC_FIELD_COUNT_ONE_BYTE_MAX 0x7F
#define REC_FIELD_COUNT_HIGHER_BYTE_MASK 0x7F
......@@ -1422,7 +1348,7 @@ rec_get_field_count(
{
byte* ptr;
ulint ret;
ut_ad(rec_is_instant(rec));
ut_ad(rec_get_status(rec) == REC_STATUS_COLUMNS_ADDED);
ptr = (byte*)rec - (REC_N_NEW_EXTRA_BYTES + 1);
......@@ -1447,22 +1373,6 @@ rec_get_field_count(
return ret;
}
/**********************************************************//**
Returns length of field count input
@return size */
UNIV_INLINE
ulint rec_get_field_count_len (
/*==========*/
ulint field_count ) /*!< in: field count*/
{
if (field_count > REC_FIELD_COUNT_ONE_BYTE_MAX)
return 2;
return 1;
}
#define rec_get_feild_count_len(n_feilds) ((n_feilds > 127) ? 2 : 1)
/**********************************************************//**
Set field count of instant record
@return the occupy size of field count */
......@@ -1475,7 +1385,7 @@ rec_set_field_count(
{
byte* ptr;
//ut_ad(rec_is_instant(rec));
ut_ad(rec_get_status(rec) == REC_STATUS_COLUMNS_ADDED);
ut_ad(n_fields < REC_MAX_N_FIELDS);
if (n_fields <= REC_FIELD_COUNT_ONE_BYTE_MAX) {
......@@ -1605,9 +1515,11 @@ rec_get_converted_size(
== dict_index_get_n_fields(index) - 1));
if (dict_table_is_comp(index->table)) {
return(rec_get_converted_size_comp(index,
dtuple_get_info_bits(dtuple)
& REC_NEW_STATUS_MASK,
return(rec_get_converted_size_comp(
index,
static_cast<rec_comp_status_t>(
dtuple->info_bits
& REC_NEW_STATUS_MASK),
dtuple->fields,
dtuple->n_fields, NULL));
}
......@@ -1617,41 +1529,6 @@ rec_get_converted_size(
extra_size = rec_get_converted_extra_size(
data_size, dtuple_get_n_fields(dtuple), n_ext);
#if 0
/* This code is inactive since it may be the wrong place to add
in the size of node pointers used in parent pages AND it is not
currently needed since ha_innobase::max_supported_key_length()
ensures that the key size limit for each page size is well below
the actual limit ((free space on page / 4) - record overhead).
But those limits will need to be raised when InnoDB can
support multiple page sizes. At that time, we will need
to consider the node pointer on these universal btrees. */
if (dict_index_is_ibuf(index)) {
/* This is for the insert buffer B-tree.
All fields in the leaf tuple ascend to the
parent node plus the child page pointer. */
/* ibuf cannot contain externally stored fields */
ut_ad(n_ext == 0);
/* Add the data pointer and recompute extra_size
based on one more field. */
data_size += REC_NODE_PTR_SIZE;
extra_size = rec_get_converted_extra_size(
data_size,
dtuple_get_n_fields(dtuple) + 1,
0);
/* Be sure dtuple->n_fields has this node ptr
accounted for. This function should correspond to
what rec_convert_dtuple_to_rec() needs in storage.
In optimistic insert or update-not-in-place, we will
have to ensure that if the record is converted to a
node pointer, it will not become too large.*/
}
#endif
return(data_size + extra_size);
}
......
......@@ -1319,27 +1319,6 @@ page_cur_insert_rec_low(
insert_rec = rec_copy(insert_buf, rec, offsets);
rec_offs_make_valid(insert_rec, index, page_is_leaf(page), offsets);
/* This is because assertion below is debug assertion */
#ifdef UNIV_DEBUG
if (UNIV_UNLIKELY(current_rec == insert_rec)) {
ulint extra_len, data_len;
extra_len = rec_offs_extra_size(offsets);
data_len = rec_offs_data_size(offsets);
fprintf(stderr, "InnoDB: Error: current_rec == insert_rec "
" extra_len " ULINTPF
" data_len " ULINTPF " insert_buf %p rec %p\n",
extra_len, data_len, insert_buf, rec);
fprintf(stderr, "InnoDB; Physical record: \n");
rec_print(stderr, rec, index);
fprintf(stderr, "InnoDB: Inserted record: \n");
rec_print(stderr, insert_rec, index);
fprintf(stderr, "InnoDB: Current record: \n");
rec_print(stderr, current_rec, index);
ut_a(current_rec != insert_rec);
}
#endif /* UNIV_DEBUG */
/* 4. Insert the record in the linked list of records */
ut_ad(current_rec != insert_rec);
......@@ -1348,9 +1327,24 @@ page_cur_insert_rec_low(
rec_t* next_rec = page_rec_get_next(current_rec);
#ifdef UNIV_DEBUG
if (page_is_comp(page)) {
ut_ad(rec_get_status(current_rec)
<= REC_STATUS_INFIMUM);
ut_ad(rec_get_status(insert_rec) < REC_STATUS_INFIMUM);
switch (rec_get_status(current_rec)) {
case REC_STATUS_ORDINARY:
case REC_STATUS_NODE_PTR:
case REC_STATUS_COLUMNS_ADDED:
case REC_STATUS_INFIMUM:
break;
case REC_STATUS_SUPREMUM:
ut_ad(!"wrong status on current_rec");
}
switch (rec_get_status(insert_rec)) {
case REC_STATUS_ORDINARY:
case REC_STATUS_NODE_PTR:
case REC_STATUS_COLUMNS_ADDED:
break;
case REC_STATUS_INFIMUM:
case REC_STATUS_SUPREMUM:
ut_ad(!"wrong status on insert_rec");
}
ut_ad(rec_get_status(next_rec) != REC_STATUS_INFIMUM);
}
#endif
......
......@@ -2168,9 +2168,7 @@ page_zip_apply_log(
continue;
}
#if REC_STATUS_NODE_PTR != TRUE
# error "REC_STATUS_NODE_PTR != TRUE"
#endif
compile_time_assert(REC_STATUS_NODE_PTR == TRUE);
rec_get_offsets_reverse(data, index,
hs & REC_STATUS_NODE_PTR,
offsets);
......
......@@ -172,7 +172,8 @@ rec_get_n_extern_new(
ulint i;
ut_ad(dict_table_is_comp(index->table));
ut_ad(rec_get_status(rec) == REC_STATUS_ORDINARY);
ut_ad(rec_get_status(rec) == REC_STATUS_ORDINARY
|| rec_get_status(rec) == REC_STATUS_COLUMNS_ADDED);
ut_ad(n == ULINT_UNDEFINED || n <= dict_index_get_n_fields(index));
if (n == ULINT_UNDEFINED) {
......@@ -234,40 +235,40 @@ rec_get_n_extern_new(
return(n_extern);
}
/** Get the number of nullable columns.
@param[in] rec clustered index record with added columns
@param[in] index clustered index
@return number of possibly NULL columns in rec */
static
ulint
rec_get_n_nullable(const rec_t* rec, const dict_index_t* index)
/** Get the storage length of field count in rec_get_instant() header
@param[in] n_fields_add number of added fields
@return size in bytes */
inline
unsigned
rec_get_field_count_len(ulint n_fields_add)
{
ut_ad(index->is_instant());
ut_ad(dict_table_is_comp(index->table));
ut_ad(rec_is_instant(rec));
ulint len;
ulint n_fields = rec_get_field_count(rec, &len);
ut_ad(len == rec_get_field_count_len(n_fields));
return dict_index_get_first_n_field_n_nullable(index, n_fields);
return (n_fields_add > REC_FIELD_COUNT_ONE_BYTE_MAX) ? 2 : 1;
}
/******************************************************//**
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))
/** Format of a leaf-page ROW_FORMAT!=REDUNDANT record */
enum rec_leaf_format {
/** temporary file record */
REC_LEAF_TEMP,
/** Normal (REC_STATUS_ORDINARY) */
REC_LEAF_ORDINARY,
/** With added columns (REC_STATUS_COLUMNS_ADDED) */
REC_LEAF_COLUMNS_ADDED
};
/** Determine the offset to each field in a leaf-page record
in ROW_FORMAT=COMPACT,DYNAMIC,COMPRESSED.
This is a special case of rec_init_offsets() and rec_get_offsets_func().
@param[in] rec leaf-page record
@param[in] index the index that the record belongs in
@param[in,out] offsets offsets, with valid rec_offs_n_fields(offsets)
@param[in] format record format */
static inline
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) */
const rec_t* rec,
const dict_index_t* index,
ulint* offsets,
rec_leaf_format format)
{
ulint offs = 0;
ulint any = 0;
......@@ -275,55 +276,59 @@ rec_init_offsets_comp_ordinary(
const byte* lens = NULL;
ulint n_fields;
ulint null_mask = 1;
ulint extra_bytes = temp ? 0 : REC_N_NEW_EXTRA_BYTES;
ulint extra_bytes = REC_N_NEW_EXTRA_BYTES;
ut_ad(index->n_core_fields > 0);
ut_ad(index->n_fields >= index->n_core_fields);
ut_ad(index->n_core_null_bytes <= UT_BITS_IN_BYTES(index->n_nullable));
ut_ad(format == REC_LEAF_TEMP || dict_table_is_comp(index->table));
ut_d(ulint n_null);
if (!temp && rec_is_instant(rec)) {
ulint field_count_len;
switch (format) {
case REC_LEAF_TEMP:
ut_ad(!index->is_instant());
extra_bytes = 0;
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. */
format = REC_LEAF_ORDINARY;
}
/* fall through */
case REC_LEAF_ORDINARY:
nulls = rec - (1 + extra_bytes);
lens = nulls - index->n_core_null_bytes;
ut_d(n_null = std::min(index->n_core_null_bytes * 8U,
index->n_nullable));
n_fields = index->n_core_fields;
break;
case REC_LEAF_COLUMNS_ADDED:
ulint len;
ut_ad(index->is_instant());
ut_ad(!dict_index_is_ibuf(index));
n_fields = rec_get_field_count(rec, &field_count_len);
ut_a(extra_bytes == REC_N_NEW_EXTRA_BYTES);
nulls = rec - (1 + extra_bytes + field_count_len);
const ulint n_nullable = rec_get_n_nullable(rec, index);
n_fields = rec_get_field_count(rec, &len);
ut_ad(n_fields > index->n_core_fields);
ut_ad(extra_bytes == REC_N_NEW_EXTRA_BYTES);
nulls = rec - (1 + REC_N_NEW_EXTRA_BYTES) - len;
const ulint n_nullable
= dict_index_get_first_n_field_n_nullable(index,
n_fields);
const ulint n_null_bytes = UT_BITS_IN_BYTES(n_nullable);
ut_d(n_null = n_nullable);
ut_ad(n_null <= index->n_nullable);
ut_ad(n_null_bytes >= index->n_core_null_bytes);
lens = nulls - n_null_bytes;
} else {
ut_ad(!temp || !index->is_instant());
nulls = rec - (1 + extra_bytes);
lens = nulls - index->n_core_null_bytes;
ut_d(n_null = std::min(index->n_core_null_bytes * 8U,
index->n_nullable));
n_fields = index->n_core_fields;
}
#ifdef UNIV_DEBUG
/* We cannot invoke rec_offs_make_valid() here if temp=true.
/* We cannot invoke rec_offs_make_valid() if format==REC_LEAF_TEMP.
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_fields */
ulint i = 0;
do {
......@@ -371,7 +376,8 @@ rec_init_offsets_comp_ordinary(
}
if (!field->fixed_len
|| (temp && !dict_col_get_fixed_size(col, temp))) {
|| (format == REC_LEAF_TEMP
&& !dict_col_get_fixed_size(col, true))) {
/* Variable-length field: read the length */
len = *lens--;
/* If the maximum length of the field is up
......@@ -486,6 +492,7 @@ rec_offs_validate(
dict_index_get_n_unique_in_tree(index) + 1);
if (comp && rec) {
switch (rec_get_status(rec)) {
case REC_STATUS_COLUMNS_ADDED:
case REC_STATUS_ORDINARY:
break;
case REC_STATUS_NODE_PTR:
......@@ -567,10 +574,15 @@ rec_init_offsets(
= dict_index_get_n_unique_in_tree_nonleaf(
index);
break;
case REC_STATUS_COLUMNS_ADDED:
ut_ad(leaf);
rec_init_offsets_comp_ordinary(rec, index, offsets,
REC_LEAF_COLUMNS_ADDED);
return;
case REC_STATUS_ORDINARY:
ut_ad(leaf);
rec_init_offsets_comp_ordinary(
rec, false, index, offsets);
rec_init_offsets_comp_ordinary(rec, index, offsets,
REC_LEAF_ORDINARY);
return;
}
......@@ -582,7 +594,6 @@ rec_init_offsets(
(Clustered index node pointer records only contain the
PRIMARY KEY columns, which are always NOT NULL,
so we should have used n_nullable=0.) */
ut_ad(!rec_is_instant(rec));
ut_ad(index->n_core_fields > 0);
nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
......@@ -748,6 +759,7 @@ rec_get_offsets_func(
if (dict_table_is_comp(index->table)) {
switch (UNIV_EXPECT(rec_get_status(rec),
REC_STATUS_ORDINARY)) {
case REC_STATUS_COLUMNS_ADDED:
case REC_STATUS_ORDINARY:
ut_ad(leaf);
n = dict_index_get_n_fields(index);
......@@ -1037,7 +1049,7 @@ 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 */
ulint rec_flag, /*!< in: REC_FLAG_* */
rec_comp_status_t status, /*!< in: status flags */
bool temp) /*!< in: whether this is a
temporary file record */
{
......@@ -1047,21 +1059,22 @@ rec_get_converted_size_comp_prefix_low(
ut_ad(n_fields > 0);
ut_ad(n_fields <= dict_index_get_n_fields(index));
ut_ad(!temp || extra);
ut_ad(!temp || rec_flag == REC_FLAG_NONE);
ut_ad(!temp || status == REC_STATUS_ORDINARY);
ut_d(ulint n_null = index->n_nullable);
ut_d(const ulint n_null_bytes = UT_BITS_IN_BYTES(n_null));
if (rec_flag == REC_FLAG_INSTANT && index->is_instant()) {
ut_ad(n_null_bytes >= index->n_core_null_bytes);
extra_size = REC_N_NEW_EXTRA_BYTES
+ UT_BITS_IN_BYTES(index->n_nullable)
+ rec_get_field_count_len(n_fields);
} else {
if (status == REC_STATUS_NODE_PTR || !index->is_instant()) {
ut_ad(n_null_bytes == index->n_core_null_bytes);
extra_size = temp
? index->n_core_null_bytes
: REC_N_NEW_EXTRA_BYTES + index->n_core_null_bytes;
} else {
ut_ad(!temp);
ut_ad(n_null_bytes >= index->n_core_null_bytes);
extra_size = REC_N_NEW_EXTRA_BYTES
+ UT_BITS_IN_BYTES(index->n_nullable)
+ rec_get_field_count_len(n_fields);
}
data_size = 0;
......@@ -1224,7 +1237,8 @@ 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, REC_FLAG_NONE, false));
index, fields, n_fields, extra,
REC_STATUS_ORDINARY, false));
}
/**********************************************************//**
......@@ -1237,43 +1251,35 @@ rec_get_converted_size_comp(
dict_table_is_comp() is
assumed to hold, even if
it does not */
ulint status, /*!< in: status bits of the record */
rec_comp_status_t 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);
ulint rec_flag = REC_FLAG_NONE;
switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
case REC_STATUS_ORDINARY:
case REC_STATUS_COLUMNS_ADDED:
ut_ad(n_fields == dict_index_get_n_fields(index));
size = 0;
rec_flag |= REC_FLAG_INSTANT;
break;
return rec_get_converted_size_comp_prefix_low(
index, fields, n_fields, extra, status, false);
case REC_STATUS_NODE_PTR:
n_fields--;
ut_ad(n_fields == dict_index_get_n_unique_in_tree_nonleaf(
index));
ut_ad(dfield_get_len(&fields[n_fields]) == REC_NODE_PTR_SIZE);
size = REC_NODE_PTR_SIZE; /* child page number */
rec_flag |= REC_FLAG_NODE_PTR;
break;
return REC_NODE_PTR_SIZE /* child page number */
+ rec_get_converted_size_comp_prefix_low(
index, fields, n_fields, extra, status, false);
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;
/* not supported */
break;
}
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, rec_flag, false));
}
/***********************************************************//**
......@@ -1453,7 +1459,7 @@ rec_convert_dtuple_to_rec_comp(
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 */
rec_comp_status_t status, /*!< in: status bits of the record */
bool temp) /*!< in: whether to use the
format for temporary files in
index creation */
......@@ -1492,15 +1498,17 @@ rec_convert_dtuple_to_rec_comp(
nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
case REC_STATUS_COLUMNS_ADDED:
ut_ad(index->is_instant());
/* fall through */
case REC_STATUS_ORDINARY:
ut_ad(n_fields <= dict_index_get_n_fields(index));
is_instant = index->is_instant();
if (is_instant) {
ut_ad(n_fields == index->n_fields);
ulint field_count_len = rec_set_field_count(
rec, n_fields);
nulls = rec - (REC_N_NEW_EXTRA_BYTES
+ field_count_len + 1);
rec_set_status(rec, REC_STATUS_COLUMNS_ADDED);
nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1)
- rec_set_field_count(rec, n_fields);
}
n_node_ptr_field = ULINT_UNDEFINED;
......@@ -1704,21 +1712,30 @@ rec_convert_dtuple_to_rec_new(
const dict_index_t* index, /*!< in: record descriptor */
const dtuple_t* dtuple) /*!< in: data tuple */
{
ulint bits = dtuple->info_bits;
ut_ad(!(bits & ~(REC_NEW_STATUS_MASK | REC_INFO_DELETED_FLAG
| REC_INFO_MIN_REC_FLAG)));
rec_comp_status_t status = static_cast<rec_comp_status_t>(
bits & REC_NEW_STATUS_MASK);
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;
bool is_instant = rec_convert_dtuple_to_rec_comp(
rec, index, dtuple->fields, dtuple->n_fields, status, false);
rec_set_info_and_status_bits(rec, dtuple_get_info_bits(dtuple));
rec_set_instant_flag(rec, is_instant);
rec_t* rec = buf + extra_size;
if (rec_convert_dtuple_to_rec_comp(
rec, index, dtuple->fields, dtuple->n_fields,
status, false)) {
ut_ad(status == REC_STATUS_ORDINARY
|| status == REC_STATUS_COLUMNS_ADDED);
bits &= ~REC_NEW_STATUS_MASK;
bits |= REC_STATUS_COLUMNS_ADDED;
} else {
ut_ad(status == REC_STATUS_ORDINARY
|| status == REC_STATUS_NODE_PTR);
}
rec_set_info_and_status_bits(rec, bits);
return(rec);
}
......@@ -1767,7 +1784,8 @@ rec_get_converted_size_temp(
ulint* extra)
{
return(rec_get_converted_size_comp_prefix_low(
index, fields, n_fields, extra, REC_FLAG_NONE, true));
index, fields, n_fields, extra,
REC_STATUS_ORDINARY, true));
}
/******************************************************//**
......@@ -1781,7 +1799,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, index, offsets, REC_LEAF_TEMP);
}
/*********************************************************//**
......@@ -1931,8 +1949,27 @@ rec_copy_prefix_to_buf(
status = rec_get_status(rec);
switch (status) {
case REC_STATUS_COLUMNS_ADDED:
ut_ad(index->is_instant());
if (n_fields >= index->n_core_fields) {
ut_ad(n_fields <= index->n_fields);
ulint len;
ulint n_fields_rec = rec_get_field_count(rec, &len);
ut_ad(len == rec_get_field_count_len(n_fields_rec));
ut_ad(n_fields_rec >= n_fields);
const ulint n_nullable
= dict_index_get_first_n_field_n_nullable(
index, n_fields_rec);
ut_ad(n_nullable <= index->n_nullable);
nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1) - len;
lens = nulls - UT_BITS_IN_BYTES(n_nullable);
break;
}
/* fall through */
case REC_STATUS_ORDINARY:
ut_ad(n_fields <= dict_index_get_n_fields(index));
ut_ad(n_fields <= index->n_core_fields);
nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
lens = nulls - index->n_core_null_bytes;
break;
case REC_STATUS_NODE_PTR:
/* For R-tree, we need to copy the child page number field. */
......@@ -1945,38 +1982,16 @@ rec_copy_prefix_to_buf(
ut_ad(n_fields <=
dict_index_get_n_unique_in_tree_nonleaf(index));
}
nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
lens = nulls - index->n_core_null_bytes;
break;
case REC_STATUS_INFIMUM:
case REC_STATUS_SUPREMUM:
/* infimum or supremum record: no sense to copy anything */
default:
ut_error;
return(NULL);
}
if (rec_is_instant(rec)) {
ut_ad(!dict_index_is_ibuf(index));
ulint field_count_len = 0;
ulint field_count = 0;
ulint n_nullable = 0;
ut_a(index->is_instant());
field_count = rec_get_field_count(rec, &field_count_len);
ut_ad(field_count_len == rec_get_field_count_len(field_count));
ut_ad(field_count >= n_fields);
n_nullable = rec_get_n_nullable(rec, index);
ut_ad(n_nullable <= index->n_nullable);
nulls = rec - (REC_N_NEW_EXTRA_BYTES + field_count_len + 1);
lens = nulls - UT_BITS_IN_BYTES(n_nullable);
} else {
nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
lens = nulls - index->n_core_null_bytes;
}
UNIV_PREFETCH_R(lens);
prefix_len = 0;
null_mask = 1;
......
......@@ -2634,7 +2634,8 @@ row_ins_clust_index_entry_low(
#endif /* UNIV_DEBUG */
if (entry->info_bits) {
ut_ad(entry->info_bits == REC_INFO_MIN_REC_FLAG);
ut_ad(entry->info_bits
== (REC_INFO_MIN_REC_FLAG | REC_STATUS_COLUMNS_ADDED));
ut_ad(flags == BTR_NO_LOCKING_FLAG);
ut_ad(index->is_instant());
ut_ad(!dict_index_is_online_ddl(index));
......
......@@ -1022,7 +1022,8 @@ row_log_table_low(
}
ut_ad(page_is_comp(page_align(rec)));
ut_ad(rec_get_status(rec) == REC_STATUS_ORDINARY);
ut_ad(rec_get_status(rec) == REC_STATUS_ORDINARY
|| rec_get_status(rec) == REC_STATUS_COLUMNS_ADDED);
omit_size = REC_N_NEW_EXTRA_BYTES;
......
......@@ -700,19 +700,25 @@ row_upd_rec_in_place(
ut_ad(rec_offs_validate(rec, index, offsets));
if (rec_offs_comp(offsets)) {
ulint is_instant = rec_is_instant(rec);
ut_ad(!is_instant ||
(index->is_instant() &&
rec_get_field_count(rec, NULL) <= dict_index_get_n_fields(index)));
#ifdef UNIV_DEBUG
switch (rec_get_status(rec)) {
case REC_STATUS_ORDINARY:
break;
case REC_STATUS_COLUMNS_ADDED:
ut_ad(index->is_instant());
ut_ad(rec_get_field_count(rec, NULL)
<= index->n_fields);
ut_ad(rec_get_field_count(rec, NULL)
> index->n_core_fields);
break;
case REC_STATUS_INFIMUM:
case REC_STATUS_SUPREMUM:
case REC_STATUS_NODE_PTR:
ut_ad(!"wrong record status in update");
}
#endif /* UNIV_DEBUG */
rec_set_info_bits_new(rec, update->info_bits);
if(is_instant)
rec_set_instant_flag(rec, TRUE);
else
rec_set_instant_flag(rec, FALSE);
} else {
rec_set_info_bits_old(rec, update->info_bits);
}
......
......@@ -500,7 +500,8 @@ trx_undo_page_report_insert(
/* Store then the fields required to uniquely determine the record
to be inserted in the clustered index */
if (UNIV_UNLIKELY(clust_entry->info_bits)) {
ut_ad(clust_entry->info_bits == REC_INFO_MIN_REC_FLAG);
ut_ad(clust_entry->info_bits
== (REC_INFO_MIN_REC_FLAG | REC_STATUS_COLUMNS_ADDED));
ut_ad(index->is_instant());
ut_ad(undo_page[first_free + 2] == TRX_UNDO_INSERT_REC);
undo_page[first_free + 2] = TRX_UNDO_INSERT_DEFAULT;
......@@ -1899,7 +1900,8 @@ trx_undo_report_row_operation(
ut_ad(!trx->read_only);
ut_ad(trx->id);
if (UNIV_LIKELY(!clust_entry || clust_entry->info_bits
!= REC_INFO_MIN_REC_FLAG)) {
!= (REC_INFO_MIN_REC_FLAG
| REC_STATUS_COLUMNS_ADDED))) {
/* Keep INFORMATION_SCHEMA.TABLES.UPDATE_TIME
up-to-date for persistent tables outside
instant ADD COLUMN. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment