summaryrefslogtreecommitdiff
path: root/storage/innobase
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase')
-rw-r--r--storage/innobase/handler/ha_innodb.cc117
-rw-r--r--storage/innobase/include/rem0rec.h8
-rw-r--r--storage/innobase/include/row0mysql.h42
-rw-r--r--storage/innobase/os/os0proc.cc1
-rw-r--r--storage/innobase/row/row0ins.cc137
-rw-r--r--storage/innobase/row/row0merge.cc52
-rw-r--r--storage/innobase/row/row0sel.cc123
-rw-r--r--storage/innobase/row/row0upd.cc83
-rw-r--r--storage/innobase/row/row0vers.cc47
9 files changed, 343 insertions, 267 deletions
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index b190f60632a..054ff3f3b0f 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -103,6 +103,7 @@ this program; if not, write to the Free Software Foundation, Inc.,
#include "srv0mon.h"
#include "srv0srv.h"
#include "srv0start.h"
+#include "rem0rec.h"
#ifdef UNIV_DEBUG
#include "trx0purge.h"
#endif /* UNIV_DEBUG */
@@ -5656,14 +5657,13 @@ innobase_vcol_build_templ(
mysql_row_templ_t* templ,
ulint col_no)
{
- if (col->is_virtual()) {
- templ->is_virtual = true;
- templ->col_no = col_no;
+ templ->col_no = col_no;
+ templ->is_virtual = col->is_virtual();
+
+ if (templ->is_virtual) {
templ->clust_rec_field_no = ULINT_UNDEFINED;
templ->rec_field_no = col->ind;
} else {
- templ->is_virtual = false;
- templ->col_no = col_no;
templ->clust_rec_field_no = dict_col_get_clust_pos(
col, clust_index);
ut_a(templ->clust_rec_field_no != ULINT_UNDEFINED);
@@ -20935,64 +20935,53 @@ innobase_get_field_from_update_vector(
Allocate a heap and record for calculating virtual fields
Used mainly for virtual fields in indexes
-@param[in] thd MariaDB THD
-@param[in] index Index in use
-@param[out] heap Heap that holds temporary row
-@param[in,out] table MariaDB table
-@param[out] record Pointer to allocated MariaDB record
-@param[out] storage Internal storage for blobs etc
+@param[in] thd MariaDB THD
+@param[in] index Index in use
+@param[out] heap Heap that holds temporary row
+@param[in,out] table MariaDB table
+@param[out] record Pointer to allocated MariaDB record
+@param[out] storage Internal storage for blobs etc
-@retval false on success
-@retval true on malloc failure or failed to open the maria table
+@retval true on success
+@retval false on malloc failure or failed to open the maria table
for purge thread.
*/
-bool innobase_allocate_row_for_vcol(
- THD * thd,
- dict_index_t* index,
- mem_heap_t** heap,
- TABLE** table,
- byte** record,
- VCOL_STORAGE** storage)
-{
- TABLE *maria_table;
- String *blob_value_storage;
- if (!*table)
- *table= innodb_find_table_for_vc(thd, index->table);
-
- /* For purge thread, there is a possiblity that table could have
- dropped, corrupted or unaccessible. */
- if (!*table)
- return true;
- maria_table= *table;
- if (!*heap && !(*heap= mem_heap_create(srv_page_size)))
- {
- *storage= 0;
- return TRUE;
- }
- *record= static_cast<byte*>(mem_heap_alloc(*heap,
- maria_table->s->reclength));
- *storage= static_cast<VCOL_STORAGE*>
- (mem_heap_alloc(*heap, sizeof(**storage)));
- blob_value_storage= static_cast<String*>
- (mem_heap_alloc(*heap,
- maria_table->s->virtual_not_stored_blob_fields *
- sizeof(String)));
- if (!*record || !*storage || !blob_value_storage)
- {
- *storage= 0;
- return TRUE;
- }
- (*storage)->maria_table= maria_table;
- (*storage)->innobase_record= *record;
- (*storage)->maria_record= maria_table->field[0]->record_ptr();
- (*storage)->blob_value_storage= blob_value_storage;
+bool innobase_allocate_row_for_vcol(THD *thd, dict_index_t *index,
+ mem_heap_t **heap, TABLE **table,
+ VCOL_STORAGE *storage)
+{
+ TABLE *maria_table;
+ String *blob_value_storage;
+ if (!*table)
+ *table = innodb_find_table_for_vc(thd, index->table);
+
+ /* For purge thread, there is a possiblity that table could have
+ dropped, corrupted or unaccessible. */
+ if (!*table)
+ return false;
+ maria_table = *table;
+ if (!*heap && !(*heap = mem_heap_create(srv_page_size)))
+ return false;
+
+ uchar *record = static_cast<byte *>(mem_heap_alloc(*heap,
+ maria_table->s->reclength));
- maria_table->move_fields(maria_table->field, *record,
- (*storage)->maria_record);
- maria_table->remember_blob_values(blob_value_storage);
+ size_t len = maria_table->s->virtual_not_stored_blob_fields * sizeof(String);
+ blob_value_storage = static_cast<String *>(mem_heap_alloc(*heap, len));
- return FALSE;
+ if (!record || !blob_value_storage)
+ return false;
+
+ storage->maria_table = maria_table;
+ storage->innobase_record = record;
+ storage->maria_record = maria_table->field[0]->record_ptr();
+ storage->blob_value_storage = blob_value_storage;
+
+ maria_table->move_fields(maria_table->field, record, storage->maria_record);
+ maria_table->remember_blob_values(blob_value_storage);
+
+ return true;
}
@@ -21007,6 +20996,13 @@ void innobase_free_row_for_vcol(VCOL_STORAGE *storage)
}
+void innobase_report_computed_value_failed(dtuple_t *row)
+{
+ ib::error() << "Compute virtual column values failed for "
+ << rec_printer(row).str();
+}
+
+
/** Get the computed value by supplying the base column values.
@param[in,out] row the data row
@param[in] col virtual column
@@ -21134,13 +21130,6 @@ innobase_get_computed_value(
dbug_tmp_restore_column_map(mysql_table->write_set, old_write_set);
if (ret != 0) {
- // FIXME: Why this error message is macro-hidden?
-#ifdef INNODB_VIRTUAL_DEBUG
- ib::warn() << "Compute virtual column values failed ";
- fputs("InnoDB: Cannot compute value for following record ",
- stderr);
- dtuple_print(stderr, row);
-#endif /* INNODB_VIRTUAL_DEBUG */
DBUG_RETURN(NULL);
}
diff --git a/storage/innobase/include/rem0rec.h b/storage/innobase/include/rem0rec.h
index acf8896b225..f88df8de25c 100644
--- a/storage/innobase/include/rem0rec.h
+++ b/storage/innobase/include/rem0rec.h
@@ -1227,16 +1227,17 @@ struct rec_offsets_print
@param[in,out] o output stream
@param[in] r record to display
@return the output stream */
+ATTRIBUTE_COLD
std::ostream&
operator<<(std::ostream& o, const rec_offsets_print& r);
-# ifndef DBUG_OFF
/** Pretty-printer of records and tuples */
class rec_printer : public std::ostringstream {
public:
/** Construct a pretty-printed record.
@param rec record with header
@param offsets rec_get_offsets(rec, ...) */
+ ATTRIBUTE_COLD
rec_printer(const rec_t* rec, const rec_offs* offsets)
:
std::ostringstream ()
@@ -1250,6 +1251,7 @@ public:
@param rec record, possibly lacking header
@param info rec_get_info_bits(rec)
@param offsets rec_get_offsets(rec, ...) */
+ ATTRIBUTE_COLD
rec_printer(const rec_t* rec, ulint info, const rec_offs* offsets)
:
std::ostringstream ()
@@ -1259,6 +1261,7 @@ public:
/** Construct a pretty-printed tuple.
@param tuple data tuple */
+ ATTRIBUTE_COLD
rec_printer(const dtuple_t* tuple)
:
std::ostringstream ()
@@ -1269,6 +1272,7 @@ public:
/** Construct a pretty-printed tuple.
@param field array of data tuple fields
@param n number of fields */
+ ATTRIBUTE_COLD
rec_printer(const dfield_t* field, ulint n)
:
std::ostringstream ()
@@ -1285,7 +1289,7 @@ private:
/** Assignment operator */
rec_printer& operator=(const rec_printer& other);
};
-# endif /* !DBUG_OFF */
+
# ifdef UNIV_DEBUG
/** Read the DB_TRX_ID of a clustered index record.
diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h
index 8c9b5325c5f..d32b84198e0 100644
--- a/storage/innobase/include/row0mysql.h
+++ b/storage/innobase/include/row0mysql.h
@@ -843,6 +843,8 @@ struct VCOL_STORAGE
byte *innobase_record;
byte *maria_record;
String *blob_value_storage;
+ VCOL_STORAGE(): maria_table(NULL), innobase_record(NULL),
+ maria_record(NULL), blob_value_storage(NULL) {}
};
/**
@@ -865,12 +867,48 @@ bool innobase_allocate_row_for_vcol(
dict_index_t* index,
mem_heap_t** heap,
TABLE** table,
- byte** record,
- VCOL_STORAGE** storage);
+ VCOL_STORAGE* storage);
/** Free memory allocated by innobase_allocate_row_for_vcol() */
void innobase_free_row_for_vcol(VCOL_STORAGE *storage);
+class ib_vcol_row
+{
+ VCOL_STORAGE storage;
+public:
+ mem_heap_t *heap;
+
+ ib_vcol_row(mem_heap_t *heap) : heap(heap) {}
+
+ byte *record(THD *thd, dict_index_t *index, TABLE **table)
+ {
+ if (!storage.innobase_record)
+ {
+ bool ok = innobase_allocate_row_for_vcol(thd, index, &heap, table,
+ &storage);
+ if (!ok)
+ return NULL;
+ }
+ return storage.innobase_record;
+ };
+
+ ~ib_vcol_row()
+ {
+ if (heap)
+ {
+ if (storage.innobase_record)
+ innobase_free_row_for_vcol(&storage);
+ mem_heap_free(heap);
+ }
+ }
+};
+
+/** Report virtual value computation failure in ib::error
+@param[in] row the data row
+*/
+ATTRIBUTE_COLD
+void innobase_report_computed_value_failed(dtuple_t *row);
+
/** Get the computed value by supplying the base column values.
@param[in,out] row the data row
@param[in] col virtual column
diff --git a/storage/innobase/os/os0proc.cc b/storage/innobase/os/os0proc.cc
index 4a4076f4a1f..5d0e53bcd82 100644
--- a/storage/innobase/os/os0proc.cc
+++ b/storage/innobase/os/os0proc.cc
@@ -29,6 +29,7 @@ Created 9/30/1995 Heikki Tuuri
#ifdef HAVE_LINUX_LARGE_PAGES
# include "mysqld.h"
#endif
+#include "my_valgrind.h"
/* FreeBSD for example has only MAP_ANON, Linux has MAP_ANONYMOUS and
MAP_ANON but MAP_ANON is marked as deprecated */
diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc
index 13649777419..f25e9648a32 100644
--- a/storage/innobase/row/row0ins.cc
+++ b/storage/innobase/row/row0ins.cc
@@ -882,16 +882,15 @@ row_ins_invalidate_query_cache(
@param[in] index clustered index of child table
@param[in] node parent update node
@param[in] foreign foreign key information
-@param[out] err error code. */
+@return error code. */
static
-void
+dberr_t
row_ins_foreign_fill_virtual(
upd_node_t* cascade,
const rec_t* rec,
dict_index_t* index,
upd_node_t* node,
- dict_foreign_t* foreign,
- dberr_t* err)
+ dict_foreign_t* foreign)
{
THD* thd = current_thd;
row_ext_t* ext;
@@ -900,10 +899,7 @@ row_ins_foreign_fill_virtual(
const rec_offs* offsets =
rec_get_offsets(rec, index, offsets_, true,
ULINT_UNDEFINED, &cascade->heap);
- mem_heap_t* v_heap = NULL;
TABLE* mysql_table= NULL;
- VCOL_STORAGE* vcol_storage= NULL;
- byte* record;
upd_t* update = cascade->update;
ulint n_v_fld = index->table->n_v_def;
ulint n_diff;
@@ -923,12 +919,10 @@ row_ins_foreign_fill_virtual(
innobase_init_vc_templ(index->table);
}
- if (innobase_allocate_row_for_vcol(thd, index, &v_heap,
- &mysql_table,
- &record, &vcol_storage)) {
- if (v_heap) mem_heap_free(v_heap);
- *err = DB_OUT_OF_MEMORY;
- goto func_exit;
+ ib_vcol_row vc(NULL);
+ uchar *record = vc.record(thd, index, &mysql_table);
+ if (!record) {
+ return DB_OUT_OF_MEMORY;
}
for (ulint i = 0; i < n_v_fld; i++) {
@@ -944,12 +938,11 @@ row_ins_foreign_fill_virtual(
dfield_t* vfield = innobase_get_computed_value(
update->old_vrow, col, index,
- &v_heap, update->heap, NULL, thd, mysql_table,
+ &vc.heap, update->heap, NULL, thd, mysql_table,
record, NULL, NULL, NULL);
if (vfield == NULL) {
- *err = DB_COMPUTE_VALUE_FAILED;
- goto func_exit;
+ return DB_COMPUTE_VALUE_FAILED;
}
upd_field = upd_get_nth_field(update, n_diff);
@@ -974,13 +967,12 @@ row_ins_foreign_fill_virtual(
dfield_t* new_vfield = innobase_get_computed_value(
update->old_vrow, col, index,
- &v_heap, update->heap, NULL, thd,
+ &vc.heap, update->heap, NULL, thd,
mysql_table, record, NULL,
node->update, foreign);
if (new_vfield == NULL) {
- *err = DB_COMPUTE_VALUE_FAILED;
- goto func_exit;
+ return DB_COMPUTE_VALUE_FAILED;
}
dfield_copy(&(upd_field->new_val), new_vfield);
@@ -990,14 +982,7 @@ row_ins_foreign_fill_virtual(
}
update->n_fields = n_diff;
- *err = DB_SUCCESS;
-
-func_exit:
- if (v_heap) {
- if (vcol_storage)
- innobase_free_row_for_vcol(vcol_storage);
- mem_heap_free(v_heap);
- }
+ return DB_SUCCESS;
}
#ifdef WITH_WSREP
@@ -1281,9 +1266,9 @@ row_ins_foreign_check_on_constraint(
if (foreign->v_cols != NULL
&& foreign->v_cols->size() > 0) {
- row_ins_foreign_fill_virtual(
+ err = row_ins_foreign_fill_virtual(
cascade, clust_rec, clust_index,
- node, foreign, &err);
+ node, foreign);
if (err != DB_SUCCESS) {
goto nonstandard_exit_func;
@@ -1319,9 +1304,9 @@ row_ins_foreign_check_on_constraint(
node, foreign, tmp_heap, trx);
if (foreign->v_cols && !foreign->v_cols->empty()) {
- row_ins_foreign_fill_virtual(
+ err = row_ins_foreign_fill_virtual(
cascade, clust_rec, clust_index,
- node, foreign, &err);
+ node, foreign);
if (err != DB_SUCCESS) {
goto nonstandard_exit_func;
@@ -1379,20 +1364,20 @@ row_ins_foreign_check_on_constraint(
btr_pcur_store_position(cascade->pcur, mtr);
}
+#ifdef WITH_WSREP
+ err = wsrep_append_foreign_key(trx, foreign, clust_rec, clust_index,
+ FALSE, WSREP_KEY_EXCLUSIVE);
+ if (err != DB_SUCCESS) {
+ ib::info() << "WSREP: foreign key append failed: " << err;
+ goto nonstandard_exit_func;
+ }
+#endif /* WITH_WSREP */
mtr_commit(mtr);
ut_a(cascade->pcur->rel_pos == BTR_PCUR_ON);
cascade->state = UPD_NODE_UPDATE_CLUSTERED;
-#ifdef WITH_WSREP
- err = wsrep_append_foreign_key(trx, foreign, cascade->pcur->old_rec, clust_index,
- FALSE, WSREP_KEY_EXCLUSIVE);
- if (err != DB_SUCCESS) {
- fprintf(stderr,
- "WSREP: foreign key append failed: %d\n", err);
- } else
-#endif /* WITH_WSREP */
err = row_update_cascade_for_mysql(thr, cascade,
foreign->foreign_table);
@@ -1928,6 +1913,39 @@ exit_func:
DBUG_RETURN(err);
}
+/** Sets the values of the dtuple fields in ref_entry from the values of
+foreign columns in entry.
+@param[in] foreign foreign key constraint
+@param[in] index clustered index
+@param[in] entry tuple of clustered index
+@param[in] ref_entry tuple of foreign columns
+@return true if all foreign key fields present in clustered index */
+static
+bool row_ins_foreign_index_entry(dict_foreign_t *foreign,
+ const dict_index_t *index,
+ const dtuple_t *entry,
+ dtuple_t *ref_entry)
+{
+ for (ulint i= 0; i < foreign->n_fields; i++)
+ {
+ for (ulint j= 0; j < index->n_fields; j++)
+ {
+ const char *col_name= dict_table_get_col_name(
+ index->table, dict_index_get_nth_col_no(index, j));
+ if (0 == innobase_strcasecmp(col_name, foreign->foreign_col_names[i]))
+ {
+ dfield_copy(&ref_entry->fields[i], &entry->fields[j]);
+ goto got_match;
+ }
+ }
+ return false;
+got_match:
+ continue;
+ }
+
+ return true;
+}
+
/***************************************************************//**
Checks if foreign key constraints fail for an index entry. If index
is not mentioned in any constraint, this function does nothing,
@@ -1946,9 +1964,10 @@ row_ins_check_foreign_constraints(
que_thr_t* thr) /*!< in: query thread */
{
dict_foreign_t* foreign;
- dberr_t err;
+ dberr_t err = DB_SUCCESS;
trx_t* trx;
ibool got_s_lock = FALSE;
+ mem_heap_t* heap = NULL;
DBUG_ASSERT(index->is_primary() == pk);
@@ -1958,13 +1977,36 @@ row_ins_check_foreign_constraints(
"foreign_constraint_check_for_ins");
for (dict_foreign_set::iterator it = table->foreign_set.begin();
- it != table->foreign_set.end();
+ err == DB_SUCCESS && it != table->foreign_set.end();
++it) {
foreign = *it;
if (foreign->foreign_index == index
|| (pk && !foreign->foreign_index)) {
+
+ dtuple_t* ref_tuple = entry;
+ if (UNIV_UNLIKELY(!foreign->foreign_index)) {
+ /* Change primary key entry to
+ foreign key index entry */
+ if (!heap) {
+ heap = mem_heap_create(1000);
+ } else {
+ mem_heap_empty(heap);
+ }
+
+ ref_tuple = dtuple_create(
+ heap, foreign->n_fields);
+ dtuple_set_n_fields_cmp(
+ ref_tuple, foreign->n_fields);
+ if (!row_ins_foreign_index_entry(
+ foreign, index, entry, ref_tuple)) {
+ err = DB_NO_REFERENCED_ROW;
+ break;
+ }
+
+ }
+
dict_table_t* ref_table = NULL;
dict_table_t* referenced_table
= foreign->referenced_table;
@@ -1992,7 +2034,7 @@ row_ins_check_foreign_constraints(
table from being dropped while the check is running. */
err = row_ins_check_foreign_constraint(
- TRUE, foreign, table, entry, thr);
+ TRUE, foreign, table, ref_tuple, thr);
if (referenced_table) {
foreign->foreign_table->dec_fk_checks();
@@ -2005,15 +2047,14 @@ row_ins_check_foreign_constraints(
if (ref_table != NULL) {
dict_table_close(ref_table, FALSE, FALSE);
}
-
- if (err != DB_SUCCESS) {
-
- return(err);
- }
}
}
- return(DB_SUCCESS);
+ if (UNIV_LIKELY_NULL(heap)) {
+ mem_heap_free(heap);
+ }
+
+ return err;
}
/***************************************************************//**
diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc
index b88e6ed28f7..a488c9ce605 100644
--- a/storage/innobase/row/row0merge.cc
+++ b/storage/innobase/row/row0merge.cc
@@ -520,8 +520,7 @@ row_merge_buf_add(
ulint bucket = 0;
doc_id_t write_doc_id;
ulint n_row_added = 0;
- VCOL_STORAGE* vcol_storage= 0;
- byte* record;
+ VCOL_STORAGE vcol_storage;
DBUG_ENTER("row_merge_buf_add");
if (buf->n_tuples >= buf->max_tuples) {
@@ -555,23 +554,16 @@ row_merge_buf_add(
for (i = 0; i < n_fields; i++, field++, ifield++) {
ulint len;
- const dict_col_t* col;
- ulint col_no;
ulint fixed_len;
const dfield_t* row_field;
-
- col = ifield->col;
- const dict_v_col_t* v_col = NULL;
- if (col->is_virtual()) {
- v_col = reinterpret_cast<const dict_v_col_t*>(col);
- }
-
- col_no = dict_col_get_no(col);
+ const dict_col_t* const col = ifield->col;
+ const dict_v_col_t* const v_col = col->is_virtual()
+ ? reinterpret_cast<const dict_v_col_t*>(col)
+ : NULL;
/* Process the Doc ID column */
- if (*doc_id > 0
- && col_no == index->table->fts->doc_col
- && !col->is_virtual()) {
+ if (!v_col && *doc_id
+ && col->ind == index->table->fts->doc_col) {
fts_write_doc_id((byte*) &write_doc_id, *doc_id);
/* Note: field->data now points to a value on the
@@ -590,12 +582,15 @@ row_merge_buf_add(
field->type.len = ifield->col->len;
} else {
/* Use callback to get the virtual column value */
- if (col->is_virtual()) {
+ if (v_col) {
dict_index_t* clust_index
= dict_table_get_first_index(new_table);
- if (!vcol_storage &&
- innobase_allocate_row_for_vcol(trx->mysql_thd, clust_index, v_heap, &my_table, &record, &vcol_storage)) {
+ if (!vcol_storage.innobase_record &&
+ !innobase_allocate_row_for_vcol(
+ trx->mysql_thd, clust_index,
+ v_heap, &my_table,
+ &vcol_storage)) {
*err = DB_OUT_OF_MEMORY;
goto error;
}
@@ -603,8 +598,8 @@ row_merge_buf_add(
row_field = innobase_get_computed_value(
row, v_col, clust_index,
v_heap, NULL, ifield, trx->mysql_thd,
- my_table, record, old_table, NULL,
- NULL);
+ my_table, vcol_storage.innobase_record,
+ old_table, NULL, NULL);
if (row_field == NULL) {
*err = DB_COMPUTE_VALUE_FAILED;
@@ -612,7 +607,8 @@ row_merge_buf_add(
}
dfield_copy(field, row_field);
} else {
- row_field = dtuple_get_nth_field(row, col_no);
+ row_field = dtuple_get_nth_field(row,
+ col->ind);
dfield_copy(field, row_field);
}
@@ -718,7 +714,7 @@ row_merge_buf_add(
} else if (!ext) {
} else if (dict_index_is_clust(index)) {
/* Flag externally stored fields. */
- const byte* buf = row_ext_lookup(ext, col_no,
+ const byte* buf = row_ext_lookup(ext, col->ind,
&len);
if (UNIV_LIKELY_NULL(buf)) {
ut_a(buf != field_ref_zero);
@@ -729,9 +725,9 @@ row_merge_buf_add(
len = dfield_get_len(field);
}
}
- } else if (!col->is_virtual()) {
+ } else if (!v_col) {
/* Only non-virtual column are stored externally */
- const byte* buf = row_ext_lookup(ext, col_no,
+ const byte* buf = row_ext_lookup(ext, col->ind,
&len);
if (UNIV_LIKELY_NULL(buf)) {
ut_a(buf != field_ref_zero);
@@ -846,13 +842,13 @@ row_merge_buf_add(
}
end:
- if (vcol_storage)
- innobase_free_row_for_vcol(vcol_storage);
+ if (vcol_storage.innobase_record)
+ innobase_free_row_for_vcol(&vcol_storage);
DBUG_RETURN(n_row_added);
error:
- if (vcol_storage)
- innobase_free_row_for_vcol(vcol_storage);
+ if (vcol_storage.innobase_record)
+ innobase_free_row_for_vcol(&vcol_storage);
DBUG_RETURN(0);
}
diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc
index 1dbbc018a9c..dc5c9d802f6 100644
--- a/storage/innobase/row/row0sel.cc
+++ b/storage/innobase/row/row0sel.cc
@@ -153,11 +153,15 @@ fields are compared with collation!
must be protected by a page s-latch
@param[in] clust_index clustered index
@param[in] thr query thread
-@return TRUE if the secondary record is equal to the corresponding
-fields in the clustered record, when compared with collation;
-FALSE if not equal or if the clustered record has been marked for deletion */
+@retval DB_COMPUTE_VALUE_FAILED in case of virtual column value computation
+ failure.
+@retval DB_SUCCESS_LOCKED_REC if the secondary record is equal to the
+ corresponding fields in the clustered record, when compared with
+ collation;
+@retval DB_SUCCESS if not equal or if the clustered record has been marked
+ for deletion */
static
-ibool
+dberr_t
row_sel_sec_rec_is_for_clust_rec(
const rec_t* sec_rec,
dict_index_t* sec_index,
@@ -175,9 +179,6 @@ row_sel_sec_rec_is_for_clust_rec(
rec_offs sec_offsets_[REC_OFFS_SMALL_SIZE];
rec_offs* clust_offs = clust_offsets_;
rec_offs* sec_offs = sec_offsets_;
- ibool is_equal = TRUE;
- VCOL_STORAGE* vcol_storage= 0;
- byte* record;
rec_offs_init(clust_offsets_);
rec_offs_init(sec_offsets_);
@@ -192,10 +193,11 @@ row_sel_sec_rec_is_for_clust_rec(
it is not visible in the read view. Besides,
if there are any externally stored columns,
some of them may have already been purged. */
- return(FALSE);
+ return DB_SUCCESS;
}
heap = mem_heap_create(256);
+ ib_vcol_row vc(heap);
clust_offs = rec_get_offsets(clust_rec, clust_index, clust_offs,
true, ULINT_UNDEFINED, &heap);
@@ -224,16 +226,9 @@ row_sel_sec_rec_is_for_clust_rec(
dfield_t* vfield;
row_ext_t* ext;
- if (!vcol_storage)
- {
- TABLE *mysql_table= thr->prebuilt->m_mysql_table;
- innobase_allocate_row_for_vcol(thr_get_trx(thr)->mysql_thd,
- clust_index,
- &heap,
- &mysql_table,
- &record,
- &vcol_storage);
- }
+ byte *record = vc.record(thr_get_trx(thr)->mysql_thd,
+ clust_index,
+ &thr->prebuilt->m_mysql_table);
v_col = reinterpret_cast<const dict_v_col_t*>(col);
@@ -250,6 +245,10 @@ row_sel_sec_rec_is_for_clust_rec(
thr->prebuilt->m_mysql_table,
record, NULL, NULL, NULL);
+ if (vfield == NULL) {
+ innobase_report_computed_value_failed(row);
+ return DB_COMPUTE_VALUE_FAILED;
+ }
clust_len = vfield->len;
clust_field = static_cast<byte*>(vfield->data);
} else {
@@ -283,7 +282,7 @@ row_sel_sec_rec_is_for_clust_rec(
sec_field, sec_len,
ifield->prefix_len,
clust_index->table)) {
- goto inequal;
+ return DB_SUCCESS;
}
continue;
@@ -319,28 +318,19 @@ row_sel_sec_rec_is_for_clust_rec(
rtr_read_mbr(sec_field, &sec_mbr);
if (!MBR_EQUAL_CMP(&sec_mbr, &tmp_mbr)) {
- is_equal = FALSE;
- goto func_exit;
+ return DB_SUCCESS;
}
} else {
if (0 != cmp_data_data(col->mtype, col->prtype,
clust_field, len,
sec_field, sec_len)) {
-inequal:
- is_equal = FALSE;
- goto func_exit;
+ return DB_SUCCESS;
}
}
}
-func_exit:
- if (UNIV_LIKELY_NULL(heap)) {
- if (UNIV_LIKELY_NULL(vcol_storage))
- innobase_free_row_for_vcol(vcol_storage);
- mem_heap_free(heap);
- }
- return(is_equal);
+ return DB_SUCCESS_LOCKED_REC;
}
/*********************************************************************//**
@@ -906,7 +896,7 @@ row_sel_get_clust_rec(
dict_index_t* index;
rec_t* clust_rec;
rec_t* old_vers;
- dberr_t err;
+ dberr_t err = DB_SUCCESS;
mem_heap_t* heap = NULL;
rec_offs offsets_[REC_OFFS_NORMAL_SIZE];
rec_offs* offsets = offsets_;
@@ -948,7 +938,7 @@ row_sel_get_clust_rec(
clustered index record did not exist in the read view of
trx. */
- goto func_exit;
+ goto err_exit;
}
offsets = rec_get_offsets(clust_rec, index, offsets, true,
@@ -1011,7 +1001,7 @@ row_sel_get_clust_rec(
clust_rec = old_vers;
if (clust_rec == NULL) {
- goto func_exit;
+ goto err_exit;
}
}
@@ -1028,13 +1018,14 @@ row_sel_get_clust_rec(
visit through secondary index records that would not really
exist in our snapshot. */
- if ((old_vers
- || rec_get_deleted_flag(rec, dict_table_is_comp(
- plan->table)))
- && !row_sel_sec_rec_is_for_clust_rec(rec, plan->index,
- clust_rec, index,
- thr)) {
- goto func_exit;
+ if (old_vers || rec_get_deleted_flag(rec, dict_table_is_comp(
+ plan->table))) {
+ err = row_sel_sec_rec_is_for_clust_rec(rec,
+ plan->index, clust_rec,
+ index, thr);
+ if (err != DB_SUCCESS_LOCKED_REC) {
+ goto err_exit;
+ }
}
}
@@ -1047,7 +1038,6 @@ row_sel_get_clust_rec(
row_sel_fetch_columns(index, clust_rec, offsets,
UT_LIST_GET_FIRST(plan->columns));
*out_rec = clust_rec;
-func_exit:
err = DB_SUCCESS;
err_exit:
if (UNIV_LIKELY_NULL(heap)) {
@@ -3496,10 +3486,18 @@ Row_sel_get_clust_rec_for_mysql::operator()(
|| trx->isolation_level <= TRX_ISO_READ_UNCOMMITTED
|| dict_index_is_spatial(sec_index)
|| rec_get_deleted_flag(rec, dict_table_is_comp(
- sec_index->table)))
- && !row_sel_sec_rec_is_for_clust_rec(
- rec, sec_index, clust_rec, clust_index, thr)) {
- clust_rec = NULL;
+ sec_index->table)))) {
+ err = row_sel_sec_rec_is_for_clust_rec(rec, sec_index,
+ clust_rec, clust_index, thr);
+ switch (err) {
+ case DB_SUCCESS:
+ clust_rec = NULL;
+ break;
+ case DB_SUCCESS_LOCKED_REC:
+ break;
+ default:
+ goto err_exit;
+ }
}
err = DB_SUCCESS;
@@ -4091,6 +4089,10 @@ bool row_search_with_covering_prefix(
const dict_index_t* index = prebuilt->index;
ut_ad(!dict_index_is_clust(index));
+ if (dict_index_is_spatial(index)) {
+ return false;
+ }
+
if (!srv_prefix_index_cluster_optimization) {
return false;
}
@@ -4101,9 +4103,16 @@ bool row_search_with_covering_prefix(
return false;
}
+ /* We can avoid a clustered index lookup if
+ all of the following hold:
+ (1) all columns are in the secondary index
+ (2) all values for columns that are prefix-only
+ indexes are shorter than the prefix size
+ This optimization can avoid many IOs for certain schemas. */
for (ulint i = 0; i < prebuilt->n_template; i++) {
mysql_row_templ_t* templ = prebuilt->mysql_template + i;
ulint j = templ->rec_prefix_field_no;
+ ut_ad(!templ->mbminlen == !templ->mbmaxlen);
/** Condition (1) : is the field in the index. */
if (j == ULINT_UNDEFINED) {
@@ -4113,33 +4122,29 @@ bool row_search_with_covering_prefix(
/** Condition (2): If this is a prefix index then
row's value size shorter than prefix length. */
- if (!templ->rec_field_is_prefix) {
+ if (!templ->rec_field_is_prefix
+ || rec_offs_nth_sql_null(offsets, j)) {
continue;
}
- ulint rec_size = rec_offs_nth_size(offsets, j);
const dict_field_t* field = dict_index_get_nth_field(index, j);
- ulint max_chars = field->prefix_len / templ->mbmaxlen;
-
- ut_a(field->prefix_len > 0);
- if (rec_size < max_chars) {
- /* Record in bytes shorter than the index
- prefix length in char. */
+ if (!field->prefix_len) {
continue;
}
- if (rec_size * templ->mbminlen >= field->prefix_len) {
+ const ulint rec_size = rec_offs_nth_size(offsets, j);
+
+ if (rec_size >= field->prefix_len) {
/* Shortest representation string by the
byte length of the record is longer than the
maximum possible index prefix. */
return false;
}
- size_t num_chars = rec_field_len_in_chars(
- field->col, j, rec, offsets);
-
- if (num_chars >= max_chars) {
+ if (templ->mbminlen != templ->mbmaxlen
+ && rec_field_len_in_chars(field->col, j, rec, offsets)
+ >= field->prefix_len / templ->mbmaxlen) {
/* No of chars to store the record exceeds
the index prefix character length. */
return false;
diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc
index a119772f8e6..5ca101fdabd 100644
--- a/storage/innobase/row/row0upd.cc
+++ b/storage/innobase/row/row0upd.cc
@@ -1119,10 +1119,6 @@ row_upd_build_difference_binary(
for purge/mvcc purpose) */
if (n_v_fld > 0) {
row_ext_t* ext;
- mem_heap_t* v_heap = NULL;
- byte* record;
- VCOL_STORAGE* vcol_storage;
-
THD* thd;
if (trx == NULL) {
@@ -1133,9 +1129,8 @@ row_upd_build_difference_binary(
ut_ad(!update->old_vrow);
- innobase_allocate_row_for_vcol(thd, index, &v_heap,
- &mysql_table,
- &record, &vcol_storage);
+ ib_vcol_row vc(NULL);
+ uchar *record = vc.record(thd, index, &mysql_table);
for (ulint i = 0; i < n_v_fld; i++) {
const dict_v_col_t* col
@@ -1153,10 +1148,9 @@ row_upd_build_difference_binary(
dfield_t* vfield = innobase_get_computed_value(
update->old_vrow, col, index,
- &v_heap, heap, NULL, thd, mysql_table, record,
+ &vc.heap, heap, NULL, thd, mysql_table, record,
NULL, NULL, NULL);
if (vfield == NULL) {
- if (v_heap) mem_heap_free(v_heap);
*error = DB_COMPUTE_VALUE_FAILED;
return(NULL);
}
@@ -1177,12 +1171,6 @@ row_upd_build_difference_binary(
upd_field_set_v_field_no(uf, i, index);
}
}
-
- if (v_heap) {
- if (vcol_storage)
- innobase_free_row_for_vcol(vcol_storage);
- mem_heap_free(v_heap);
- }
}
update->n_fields = n_diff;
@@ -2116,23 +2104,19 @@ row_upd_eval_new_vals(
@param[in,out] node row update node
@param[in] update an update vector if it is update
@param[in] thd mysql thread handle
-@param[in,out] mysql_table mysql table object */
+@param[in,out] mysql_table mysql table object
+@return true if success
+ false if virtual column value computation fails. */
static
-void
+bool
row_upd_store_v_row(
upd_node_t* node,
const upd_t* update,
THD* thd,
TABLE* mysql_table)
{
- mem_heap_t* heap = NULL;
dict_index_t* index = dict_table_get_first_index(node->table);
- byte* record= 0;
- VCOL_STORAGE *vcol_storage= 0;
-
- if (!update)
- innobase_allocate_row_for_vcol(thd, index, &heap, &mysql_table,
- &record, &vcol_storage);
+ ib_vcol_row vc(NULL);
for (ulint col_no = 0; col_no < dict_table_get_n_v_cols(node->table);
col_no++) {
@@ -2182,33 +2166,37 @@ row_upd_store_v_row(
dfield_dup(dfield, node->heap);
}
} else {
+ uchar *record = vc.record(thd, index,
+ &mysql_table);
/* Need to compute, this happens when
deleting row */
- innobase_get_computed_value(
- node->row, col, index,
- &heap, node->heap, NULL,
- thd, mysql_table, record, NULL,
- NULL, NULL);
+ dfield_t* vfield =
+ innobase_get_computed_value(
+ node->row, col, index,
+ &vc.heap, node->heap,
+ NULL, thd, mysql_table,
+ record, NULL, NULL,
+ NULL);
+ if (vfield == NULL) {
+ return false;
+ }
}
}
}
}
- if (heap) {
- if (vcol_storage)
- innobase_free_row_for_vcol(vcol_storage);
- mem_heap_free(heap);
- }
-
+ return true;
}
/** Stores to the heap the row on which the node->pcur is positioned.
@param[in] node row update node
@param[in] thd mysql thread handle
@param[in,out] mysql_table NULL, or mysql table object when
- user thread invokes dml */
+ user thread invokes dml
+@return false if virtual column value computation fails
+ true otherwise. */
static
-void
+bool
row_upd_store_row(
upd_node_t* node,
THD* thd,
@@ -2252,8 +2240,12 @@ row_upd_store_row(
NULL, NULL, NULL, ext, node->heap);
if (node->table->n_v_cols) {
- row_upd_store_v_row(node, node->is_delete ? NULL : node->update,
+ bool ok = row_upd_store_v_row(node,
+ node->is_delete ? NULL : node->update,
thd, mysql_table);
+ if (!ok) {
+ return false;
+ }
}
if (node->is_delete == PLAIN_DELETE) {
@@ -2268,6 +2260,7 @@ row_upd_store_row(
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
+ return true;
}
/***********************************************************//**
@@ -2984,9 +2977,12 @@ row_upd_del_mark_clust_rec(
/* Store row because we have to build also the secondary index
entries */
- row_upd_store_row(node, trx->mysql_thd,
+ if (!row_upd_store_row(node, trx->mysql_thd,
thr->prebuilt && thr->prebuilt->table == node->table
- ? thr->prebuilt->m_mysql_table : NULL);
+ ? thr->prebuilt->m_mysql_table : NULL)) {
+ err = DB_COMPUTE_VALUE_FAILED;
+ return err;
+ }
/* Mark the clustered index record deleted; we do not have to check
locks, because we assume that we have an x-lock on the record */
@@ -3204,8 +3200,11 @@ row_upd_clust_step(
goto exit_func;
}
- row_upd_store_row(node, trx->mysql_thd,
- thr->prebuilt ? thr->prebuilt->m_mysql_table : NULL);
+ if(!row_upd_store_row(node, trx->mysql_thd,
+ thr->prebuilt ? thr->prebuilt->m_mysql_table : NULL)) {
+ err = DB_COMPUTE_VALUE_FAILED;
+ goto exit_func;
+ }
if (row_upd_changes_ord_field_binary(index, node->update, thr,
node->row, node->ext)) {
diff --git a/storage/innobase/row/row0vers.cc b/storage/innobase/row/row0vers.cc
index 6f070f7c7d8..aa2400a91ad 100644
--- a/storage/innobase/row/row0vers.cc
+++ b/storage/innobase/row/row0vers.cc
@@ -442,9 +442,11 @@ row_vers_impl_x_locked(
@param[in] clust_index clustered index
@param[in] index the secondary index
@param[in] heap heap used to build virtual dtuple
-@param[in,out] vcol_info virtual column information. */
+@param[in,out] vcol_info virtual column information.
+@return true in case of success
+ false if virtual column computation fails */
static
-void
+bool
row_vers_build_clust_v_col(
dtuple_t* row,
dict_index_t* clust_index,
@@ -452,11 +454,8 @@ row_vers_build_clust_v_col(
mem_heap_t* heap,
purge_vcol_info_t* vcol_info)
{
- mem_heap_t* local_heap = NULL;
- VCOL_STORAGE *vcol_storage= NULL;
THD* thd= current_thd;
TABLE* maria_table= 0;
- byte* record= 0;
ut_ad(dict_index_has_virtual(index));
ut_ad(index->table == clust_index->table);
@@ -466,15 +465,13 @@ row_vers_build_clust_v_col(
maria_table = vcol_info->table();
}
- innobase_allocate_row_for_vcol(thd, index,
- &local_heap,
- &maria_table,
- &record,
- &vcol_storage);
+ ib_vcol_row vc(NULL);
+ byte *record = vc.record(thd, index, &maria_table);
if (vcol_info && !vcol_info->table()) {
vcol_info->set_table(maria_table);
- goto func_exit;
+ // wait for second fetch
+ return true;
}
for (ulint i = 0; i < dict_index_get_n_fields(index); i++) {
@@ -487,19 +484,18 @@ row_vers_build_clust_v_col(
col = reinterpret_cast<const dict_v_col_t*>(
ind_field->col);
- innobase_get_computed_value(
- row, col, clust_index, &local_heap,
+ dfield_t *vfield = innobase_get_computed_value(
+ row, col, clust_index, &vc.heap,
heap, NULL, thd, maria_table, record, NULL,
NULL, NULL);
+ if (vfield == NULL) {
+ innobase_report_computed_value_failed(row);
+ ut_ad(0);
+ return false;
+ }
}
}
-
-func_exit:
- if (local_heap) {
- if (vcol_storage)
- innobase_free_row_for_vcol(vcol_storage);
- mem_heap_free(local_heap);
- }
+ return true;
}
/** Build latest virtual column data from undo log
@@ -834,8 +830,11 @@ row_vers_build_cur_vrow(
mtr->commit();
}
- row_vers_build_clust_v_col(
+ bool res = row_vers_build_clust_v_col(
row, clust_index, index, heap, vcol_info);
+ if (!res) {
+ return NULL;
+ }
if (vcol_info != NULL && vcol_info->is_first_fetch()) {
return NULL;
@@ -956,10 +955,14 @@ row_vers_old_has_index_entry(
mtr->commit();
}
- row_vers_build_clust_v_col(
+ bool res = row_vers_build_clust_v_col(
row, clust_index, index, heap,
vcol_info);
+ if (!res) {
+ goto unsafe_to_purge;
+ }
+
if (vcol_info && vcol_info->is_first_fetch()) {
goto unsafe_to_purge;
}