Commit 76f09b53 authored by Marko Mäkelä's avatar Marko Mäkelä

row_build_index_entry_low(): Handle dropped columns correctly

row_build_index_entry_low(): Clean up the code, removing
redundant variables and conditions. For instantly dropped columns,
generate a dummy value that is NULL, the empty string, or a
fixed length of NUL bytes, depending on the type of the dropped column.

FIXME: For some reason, during the test gcol.innodb_virtual_debug_purge
we are returning NULL for indexes on virtual columns, meaning that
purge on the indexes is being skipped. Does this lead to missed purge,
or is it merely causing unnecessary memory allocation? Why are we not
evaluating the virtual column values before calling this function?
(And why not write all index keys (virtual columns or spatial index MBR)
directly to the undo log records?)
parent 0ab49a10
...@@ -199,7 +199,7 @@ row_build_index_entry_low( ...@@ -199,7 +199,7 @@ row_build_index_entry_low(
{ {
dtuple_t* entry; dtuple_t* entry;
ulint entry_len; ulint entry_len;
ulint i; ulint i = 0;
ulint num_v = 0; ulint num_v = 0;
entry_len = dict_index_get_n_fields(index); entry_len = dict_index_get_n_fields(index);
...@@ -219,105 +219,89 @@ row_build_index_entry_low( ...@@ -219,105 +219,89 @@ row_build_index_entry_low(
} else { } else {
dtuple_set_n_fields_cmp( dtuple_set_n_fields_cmp(
entry, dict_index_get_n_unique_in_tree(index)); entry, dict_index_get_n_unique_in_tree(index));
} if (dict_index_is_spatial(index)) {
/* Set the MBR field */
for (i = 0; i < entry_len + num_v; i++) { if (!row_build_spatial_index_key(
const dict_field_t* ind_field = NULL; index, ext,
const dict_col_t* col; dtuple_get_nth_field(entry, 0),
ulint col_no = 0; dtuple_get_nth_field(
dfield_t* dfield; row,
dfield_t* dfield2; dict_index_get_nth_field(index, i)
ulint len; ->col->ind), flag, heap)) {
return NULL;
if (i >= entry_len) { }
/* This is to insert new rows to cluster index */
ut_ad(dict_index_is_clust(index)
&& flag == ROW_BUILD_FOR_INSERT);
dfield = dtuple_get_nth_v_field(entry, i - entry_len);
col = &dict_table_get_nth_v_col(
index->table, i - entry_len)->m_col;
} else { i = 1;
ind_field = dict_index_get_nth_field(index, i);
col = ind_field->col;
dfield = dtuple_get_nth_field(entry, i);
} }
}
if (col->is_dropped()) { for (; i < entry_len; i++) {
const dict_field_t& f = index->fields[i];
dfield_t* dfield = dtuple_get_nth_field(entry, i);
if (f.col->is_dropped()) {
ut_ad(index->is_primary()); ut_ad(index->is_primary());
ut_ad(index->is_instant()); ut_ad(index->is_instant());
ut_ad(!col->is_virtual()); ut_ad(!f.col->is_virtual());
dict_col_copy_type(col, &dfield->type); dict_col_copy_type(f.col, &dfield->type);
if (col->is_nullable()) { if (f.col->is_nullable()) {
dfield_set_null(dfield); dfield_set_null(dfield);
} else { } else {
dfield_set_data(dfield, field_ref_zero, dfield_set_data(dfield, field_ref_zero,
col->len); f.fixed_len);
} }
continue; continue;
} else {
col_no = dict_col_get_no(col);
} }
compile_time_assert(DATA_MISSING == 0); const dfield_t* dfield2;
if (col->is_virtual()) { if (f.col->is_virtual()) {
const dict_v_col_t* v_col const dict_v_col_t* v_col
= reinterpret_cast<const dict_v_col_t*>(col); = reinterpret_cast<const dict_v_col_t*>(f.col);
ut_ad(v_col->v_pos < dtuple_get_n_v_fields(row)); ut_ad(v_col->v_pos < dtuple_get_n_v_fields(row));
dfield2 = dtuple_get_nth_v_field(row, v_col->v_pos); dfield2 = dtuple_get_nth_v_field(row, v_col->v_pos);
ut_ad(dfield_is_null(dfield2) || ut_ad(dfield_is_null(dfield2) ||
dfield_get_len(dfield2) == 0 || dfield2->data); dfield_get_len(dfield2) == 0 || dfield2->data);
ut_ad(!dfield_is_ext(dfield2));
if (UNIV_UNLIKELY(dfield2->type.mtype
== DATA_MISSING)) {
/* FIXME: why does this happen?
Should the column not be evaluated? */
ut_ad(flag == ROW_BUILD_FOR_PURGE);
return(NULL);
}
} else { } else {
dfield2 = dtuple_get_nth_field(row, col_no); dfield2 = dtuple_get_nth_field(row, f.col->ind);
ut_ad(dfield_get_type(dfield2)->mtype == DATA_MISSING if (UNIV_UNLIKELY(dfield2->type.mtype
|| (!(dfield_get_type(dfield2)->prtype == DATA_MISSING)) {
& DATA_VIRTUAL))); /* The field has not been initialized in
} the row. This should be from
trx_undo_rec_get_partial_row(). */
if (UNIV_UNLIKELY(dfield_get_type(dfield2)->mtype return(NULL);
== DATA_MISSING)) {
/* The field has not been initialized in the row.
This should be from trx_undo_rec_get_partial_row(). */
return(NULL);
}
#ifdef UNIV_DEBUG
if (dfield_get_type(dfield2)->prtype & DATA_VIRTUAL
&& dict_index_is_clust(index)) {
ut_ad(flag == ROW_BUILD_FOR_INSERT);
}
#endif /* UNIV_DEBUG */
/* Special handle spatial index, set the first field
which is for store MBR. */
if (dict_index_is_spatial(index) && i == 0) {
if (!row_build_spatial_index_key(
index, ext, dfield, dfield2, flag, heap)) {
return NULL;
} }
continue; ut_ad(!(dfield2->type.prtype & DATA_VIRTUAL));
} }
len = dfield_get_len(dfield2); compile_time_assert(DATA_MISSING == 0);
dfield_copy(dfield, dfield2); *dfield = *dfield2;
if (dfield_is_null(dfield)) { if (dfield_is_null(dfield)) {
continue; continue;
} }
if ((!ind_field || ind_field->prefix_len == 0) ulint len = dfield_get_len(dfield);
if (f.prefix_len == 0
&& (!dfield_is_ext(dfield) && (!dfield_is_ext(dfield)
|| dict_index_is_clust(index))) { || dict_index_is_clust(index))) {
/* The dfield_copy() above suffices for /* The dfield_copy() above suffices for
columns that are stored in-page, or for columns that are stored in-page, or for
clustered index record columns that are not clustered index record columns that are not
part of a column prefix in the PRIMARY KEY, part of a column prefix in the PRIMARY KEY. */
or for virtaul columns in cluster index record. */
continue; continue;
} }
...@@ -328,11 +312,11 @@ row_build_index_entry_low( ...@@ -328,11 +312,11 @@ row_build_index_entry_low(
index record with an off-page column is when it is a index record with an off-page column is when it is a
column prefix index. If atomic_blobs, also fully column prefix index. If atomic_blobs, also fully
indexed long columns may be stored off-page. */ indexed long columns may be stored off-page. */
ut_ad(col->ord_part); ut_ad(f.col->ord_part);
if (ext) { if (ext) {
/* See if the column is stored externally. */ /* See if the column is stored externally. */
const byte* buf = row_ext_lookup(ext, col_no, const byte* buf = row_ext_lookup(ext, f.col->ind,
&len); &len);
if (UNIV_LIKELY_NULL(buf)) { if (UNIV_LIKELY_NULL(buf)) {
if (UNIV_UNLIKELY(buf == field_ref_zero)) { if (UNIV_UNLIKELY(buf == field_ref_zero)) {
...@@ -341,7 +325,7 @@ row_build_index_entry_low( ...@@ -341,7 +325,7 @@ row_build_index_entry_low(
dfield_set_data(dfield, buf, len); dfield_set_data(dfield, buf, len);
} }
if (ind_field->prefix_len == 0) { if (f.prefix_len == 0) {
/* If ROW_FORMAT=DYNAMIC or /* If ROW_FORMAT=DYNAMIC or
ROW_FORMAT=COMPRESSED, we can have a ROW_FORMAT=COMPRESSED, we can have a
secondary index on an entire column secondary index on an entire column
...@@ -368,16 +352,36 @@ row_build_index_entry_low( ...@@ -368,16 +352,36 @@ row_build_index_entry_low(
} }
/* If a column prefix index, take only the prefix. */ /* If a column prefix index, take only the prefix. */
if (ind_field->prefix_len) { if (f.prefix_len) {
len = dtype_get_at_most_n_mbchars( len = dtype_get_at_most_n_mbchars(
col->prtype, col->mbminlen, col->mbmaxlen, f.col->prtype,
ind_field->prefix_len, len, f.col->mbminlen, f.col->mbmaxlen,
f.prefix_len, len,
static_cast<char*>(dfield_get_data(dfield))); static_cast<char*>(dfield_get_data(dfield)));
dfield_set_len(dfield, len); dfield_set_len(dfield, len);
} }
} }
return(entry); for (i = num_v; i--; ) {
ut_ad(index->is_primary());
ut_ad(flag == ROW_BUILD_FOR_INSERT);
dfield_t* dfield = dtuple_get_nth_v_field(entry, i);
const dict_v_col_t* v_col = dict_table_get_nth_v_col(
index->table, i);
ut_ad(!v_col->m_col.is_dropped());
ut_ad(v_col->v_pos < dtuple_get_n_v_fields(row));
const dfield_t* dfield2 = dtuple_get_nth_v_field(
row, v_col->v_pos);
ut_ad(dfield_is_null(dfield2) ||
dfield_get_len(dfield2) == 0 || dfield2->data);
if (UNIV_UNLIKELY(dfield2->type.mtype == DATA_MISSING)) {
/* FIXME: why does this happen? */
return(NULL);
}
*dfield = *dfield2;
}
return entry;
} }
/** An inverse function to row_build_index_entry. Builds a row from a /** An inverse function to row_build_index_entry. Builds a row from a
......
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