summaryrefslogtreecommitdiff
path: root/storage/innobase/row
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/row')
-rw-r--r--storage/innobase/row/row0ftsort.cc19
-rw-r--r--storage/innobase/row/row0import.cc7
-rw-r--r--storage/innobase/row/row0ins.cc247
-rw-r--r--storage/innobase/row/row0log.cc12
-rw-r--r--storage/innobase/row/row0merge.cc21
-rw-r--r--storage/innobase/row/row0mysql.cc552
-rw-r--r--storage/innobase/row/row0quiesce.cc8
-rw-r--r--storage/innobase/row/row0row.cc9
-rw-r--r--storage/innobase/row/row0sel.cc79
-rw-r--r--storage/innobase/row/row0umod.cc10
-rw-r--r--storage/innobase/row/row0upd.cc139
-rw-r--r--storage/innobase/row/row0vers.cc214
12 files changed, 545 insertions, 772 deletions
diff --git a/storage/innobase/row/row0ftsort.cc b/storage/innobase/row/row0ftsort.cc
index 7ebf7af5dbf..b467f9d1615 100644
--- a/storage/innobase/row/row0ftsort.cc
+++ b/storage/innobase/row/row0ftsort.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2010, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2015, 2017, MariaDB Corporation.
+Copyright (c) 2015, 2018, 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
@@ -108,8 +108,9 @@ row_merge_create_fts_sort_index(
field->col->prtype = idx_field->col->prtype | DATA_NOT_NULL;
field->col->mtype = charset == &my_charset_latin1
? DATA_VARCHAR : DATA_VARMYSQL;
- field->col->mbminmaxlen = idx_field->col->mbminmaxlen;
- field->col->len = HA_FT_MAXCHARLEN * DATA_MBMAXLEN(field->col->mbminmaxlen);
+ field->col->mbminlen = idx_field->col->mbminlen;
+ field->col->mbmaxlen = idx_field->col->mbmaxlen;
+ field->col->len = HA_FT_MAXCHARLEN * field->col->mbmaxlen;
field->fixed_len = 0;
@@ -152,7 +153,8 @@ row_merge_create_fts_sort_index(
field->col->prtype = DATA_NOT_NULL | DATA_BINARY_TYPE;
- field->col->mbminmaxlen = 0;
+ field->col->mbminlen = 0;
+ field->col->mbmaxlen = 0;
/* The third field is on the word's position in the original doc */
field = dict_index_get_nth_field(new_index, 2);
@@ -164,7 +166,8 @@ row_merge_create_fts_sort_index(
field->col->len = 4 ;
field->fixed_len = 4;
field->col->prtype = DATA_NOT_NULL;
- field->col->mbminmaxlen = 0;
+ field->col->mbminlen = 0;
+ field->col->mbmaxlen = 0;
return(new_index);
}
@@ -658,7 +661,8 @@ row_merge_fts_doc_tokenize(
field->type.mtype = DATA_INT;
field->type.prtype = DATA_NOT_NULL | DATA_BINARY_TYPE;
field->type.len = len;
- field->type.mbminmaxlen = 0;
+ field->type.mbminlen = 0;
+ field->type.mbmaxlen = 0;
cur_len += len;
dfield_dup(field, buf->heap);
@@ -681,7 +685,8 @@ row_merge_fts_doc_tokenize(
field->type.mtype = DATA_INT;
field->type.prtype = DATA_NOT_NULL;
field->type.len = len;
- field->type.mbminmaxlen = 0;
+ field->type.mbminlen = 0;
+ field->type.mbmaxlen = 0;
cur_len += len;
dfield_dup(field, buf->heap);
diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc
index c2bf5e15036..6caffb8f0ab 100644
--- a/storage/innobase/row/row0import.cc
+++ b/storage/innobase/row/row0import.cc
@@ -1200,7 +1200,8 @@ row_import::match_table_columns(
err = DB_ERROR;
}
- if (cfg_col->mbminmaxlen != col->mbminmaxlen) {
+ if (cfg_col->mbminlen != col->mbminlen
+ || cfg_col->mbmaxlen != col->mbmaxlen) {
ib_errf(thd,
IB_LOG_LEVEL_ERROR,
ER_TABLE_SCHEMA_MISMATCH,
@@ -2809,7 +2810,9 @@ row_import_read_columns(
col->len = mach_read_from_4(ptr);
ptr += sizeof(ib_uint32_t);
- col->mbminmaxlen = mach_read_from_4(ptr);
+ ulint mbminmaxlen = mach_read_from_4(ptr);
+ col->mbmaxlen = mbminmaxlen / 5;
+ col->mbminlen = mbminmaxlen % 5;
ptr += sizeof(ib_uint32_t);
col->ind = mach_read_from_4(ptr);
diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc
index f4bac326359..49a05717f82 100644
--- a/storage/innobase/row/row0ins.cc
+++ b/storage/innobase/row/row0ins.cc
@@ -151,9 +151,11 @@ row_ins_alloc_sys_fields(
compile_time_assert(DATA_ROW_ID_LEN
+ DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN
== sizeof node->sys_buf);
- memset(node->sys_buf, 0, DATA_ROW_ID_LEN);
- memcpy(node->sys_buf + DATA_ROW_ID_LEN, reset_trx_id,
- sizeof reset_trx_id);
+ memset(node->sys_buf, 0, sizeof node->sys_buf);
+ /* Assign DB_ROLL_PTR to 1 << ROLL_PTR_INSERT_FLAG_POS */
+ node->sys_buf[DATA_ROW_ID_LEN + DATA_TRX_ID_LEN] = 0x80;
+ ut_ad(!memcmp(node->sys_buf + DATA_ROW_ID_LEN, reset_trx_id,
+ sizeof reset_trx_id));
/* 1. Populate row-id */
col = dict_table_get_sys_col(table, DATA_ROW_ID);
@@ -459,12 +461,9 @@ row_ins_cascade_n_ancestors(
/******************************************************************//**
Calculates the update vector node->cascade->update for a child table in
a cascaded update.
-@return number of fields in the calculated update vector; the value
-can also be 0 if no foreign key fields changed; the returned value is
-ULINT_UNDEFINED if the column type in the child table is too short to
-fit the new value in the parent table: that means the update fails */
+@return whether any FULLTEXT INDEX is affected */
static MY_ATTRIBUTE((nonnull, warn_unused_result))
-ulint
+bool
row_ins_cascade_calc_update_vec(
/*============================*/
upd_node_t* node, /*!< in: update node of the parent
@@ -473,11 +472,9 @@ row_ins_cascade_calc_update_vec(
type is != 0 */
mem_heap_t* heap, /*!< in: memory heap to use as
temporary storage */
- trx_t* trx, /*!< in: update transaction */
- ibool* fts_col_affected,
- /*!< out: is FTS column affected */
- upd_node_t* cascade) /*!< in: cascade update node */
+ trx_t* trx) /*!< in: update transaction */
{
+ upd_node_t* cascade = node->cascade_node;
dict_table_t* table = foreign->foreign_table;
dict_index_t* index = foreign->foreign_index;
upd_t* update;
@@ -488,7 +485,7 @@ row_ins_cascade_calc_update_vec(
ulint parent_field_no;
ulint i;
ulint j;
- ibool doc_id_updated = FALSE;
+ bool doc_id_updated = false;
ulint doc_id_pos = 0;
doc_id_t new_doc_id = FTS_NULL_DOC_ID;
ulint prefix_col;
@@ -515,7 +512,7 @@ row_ins_cascade_calc_update_vec(
n_fields_updated = 0;
- *fts_col_affected = FALSE;
+ bool affects_fulltext = false;
if (table->fts) {
doc_id_pos = dict_table_get_nth_col_pos(
@@ -567,8 +564,7 @@ row_ins_cascade_calc_update_vec(
if (dfield_is_null(&ufield->new_val)
&& (col->prtype & DATA_NOT_NULL)) {
-
- return(ULINT_UNDEFINED);
+ goto err_exit;
}
/* If the new value would not fit in the
@@ -576,15 +572,15 @@ row_ins_cascade_calc_update_vec(
if (!dfield_is_null(&ufield->new_val)
&& dtype_get_at_most_n_mbchars(
- col->prtype, col->mbminmaxlen,
+ col->prtype,
+ col->mbminlen, col->mbmaxlen,
col->len,
ufield_len,
static_cast<char*>(
dfield_get_data(
&ufield->new_val)))
< ufield_len) {
-
- return(ULINT_UNDEFINED);
+ goto err_exit;
}
/* If the parent column type has a different
@@ -628,7 +624,7 @@ row_ins_cascade_calc_update_vec(
col->prtype)
== DATA_MYSQL_BINARY_CHARSET_COLL) {
/* Do not pad BINARY columns */
- return(ULINT_UNDEFINED);
+ goto err_exit;
}
row_mysql_pad_col(mbminlen,
@@ -645,7 +641,7 @@ row_ins_cascade_calc_update_vec(
dict_col_get_no(col),
dict_col_is_virtual(col))
!= ULINT_UNDEFINED) {
- *fts_col_affected = TRUE;
+ affects_fulltext = true;
}
/* If Doc ID is updated, check whether the
@@ -662,11 +658,14 @@ row_ins_cascade_calc_update_vec(
dfield_get_data(
&ufield->new_val)));
+ affects_fulltext = true;
+ doc_id_updated = true;
+
if (new_doc_id <= 0) {
ib::error() << "FTS Doc ID"
" must be larger than"
" 0";
- return(ULINT_UNDEFINED);
+ goto err_exit;
}
if (new_doc_id < n_doc_id) {
@@ -675,12 +674,8 @@ row_ins_cascade_calc_update_vec(
<< n_doc_id - 1
<< " for table "
<< table->name;
-
- return(ULINT_UNDEFINED);
+ goto err_exit;
}
-
- *fts_col_affected = TRUE;
- doc_id_updated = TRUE;
}
n_fields_updated++;
@@ -688,8 +683,9 @@ row_ins_cascade_calc_update_vec(
}
}
- /* Generate a new Doc ID if FTS index columns get updated */
- if (table->fts && *fts_col_affected) {
+ if (affects_fulltext) {
+ ut_ad(table->fts);
+
if (DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID)) {
doc_id_t doc_id;
doc_id_t* next_doc_id;
@@ -703,24 +699,25 @@ row_ins_cascade_calc_update_vec(
fts_get_next_doc_id(table, next_doc_id);
doc_id = fts_update_doc_id(table, ufield, next_doc_id);
n_fields_updated++;
- cascade->fts_next_doc_id = doc_id;
+ fts_trx_add_op(trx, table, doc_id, FTS_INSERT, NULL);
} else {
if (doc_id_updated) {
ut_ad(new_doc_id);
- cascade->fts_next_doc_id = new_doc_id;
+ fts_trx_add_op(trx, table, new_doc_id,
+ FTS_INSERT, NULL);
} else {
- cascade->fts_next_doc_id = FTS_NULL_DOC_ID;
ib::error() << "FTS Doc ID must be updated"
" along with FTS indexed column for"
" table " << table->name;
- return(ULINT_UNDEFINED);
+err_exit:
+ n_fields_updated = ULINT_UNDEFINED;
}
}
}
update->n_fields = n_fields_updated;
- return(n_fields_updated);
+ return affects_fulltext;
}
/*********************************************************************//**
@@ -1070,13 +1067,10 @@ row_ins_foreign_check_on_constraint(
const rec_t* clust_rec;
const buf_block_t* clust_block;
upd_t* update;
- ulint n_to_update;
dberr_t err;
- ulint i;
trx_t* trx;
mem_heap_t* tmp_heap = NULL;
doc_id_t doc_id = FTS_NULL_DOC_ID;
- ibool fts_col_affacted = FALSE;
DBUG_ENTER("row_ins_foreign_check_on_constraint");
ut_a(thr);
@@ -1120,20 +1114,15 @@ row_ins_foreign_check_on_constraint(
DBUG_RETURN(DB_ROW_IS_REFERENCED);
}
- cascade = row_create_update_node_for_mysql(table, node->cascade_heap);
- que_node_set_parent(cascade, node);
-
- /* For the cascaded operation, all the update nodes are allocated in
- the same heap. All the update nodes will point to the same heap.
- This heap is owned by the first update node. And it must be freed
- only in the first update node */
- cascade->cascade_heap = node->cascade_heap;
- cascade->cascade_upd_nodes = node->cascade_upd_nodes;
- cascade->new_upd_nodes = node->new_upd_nodes;
- cascade->processed_cascades = node->processed_cascades;
+ if (node->cascade_node == NULL) {
+ node->cascade_heap = mem_heap_create(128);
+ node->cascade_node = row_create_update_node_for_mysql(
+ table, node->cascade_heap);
+ que_node_set_parent(node->cascade_node, node);
+ }
+ cascade = node->cascade_node;
cascade->table = table;
-
cascade->foreign = foreign;
if (node->is_delete
@@ -1149,31 +1138,32 @@ row_ins_foreign_check_on_constraint(
node->cascade_heap);
cascade->update_n_fields = foreign->n_fields;
}
- }
- /* We do not allow cyclic cascaded updating (DELETE is allowed,
- but not UPDATE) of the same table, as this can lead to an infinite
- cycle. Check that we are not updating the same table which is
- already being modified in this cascade chain. We have to check
- this also because the modification of the indexes of a 'parent'
- table may still be incomplete, and we must avoid seeing the indexes
- of the parent table in an inconsistent state! */
+ /* We do not allow cyclic cascaded updating (DELETE is
+ allowed, but not UPDATE) of the same table, as this
+ can lead to an infinite cycle. Check that we are not
+ updating the same table which is already being
+ modified in this cascade chain. We have to check this
+ also because the modification of the indexes of a
+ 'parent' table may still be incomplete, and we must
+ avoid seeing the indexes of the parent table in an
+ inconsistent state! */
- if (!cascade->is_delete
- && row_ins_cascade_ancestor_updates_table(cascade, table)) {
+ if (row_ins_cascade_ancestor_updates_table(cascade, table)) {
- /* We do not know if this would break foreign key
- constraints, but play safe and return an error */
+ /* We do not know if this would break foreign key
+ constraints, but play safe and return an error */
- err = DB_ROW_IS_REFERENCED;
+ err = DB_ROW_IS_REFERENCED;
- row_ins_foreign_report_err(
- "Trying an update, possibly causing a cyclic"
- " cascaded update\n"
- "in the child table,", thr, foreign,
- btr_pcur_get_rec(pcur), entry);
+ row_ins_foreign_report_err(
+ "Trying an update, possibly causing a cyclic"
+ " cascaded update\n"
+ "in the child table,", thr, foreign,
+ btr_pcur_get_rec(pcur), entry);
- goto nonstandard_exit_func;
+ goto nonstandard_exit_func;
+ }
}
if (row_ins_cascade_n_ancestors(cascade) >= FK_MAX_CASCADE_DEL) {
@@ -1278,17 +1268,8 @@ row_ins_foreign_check_on_constraint(
if (node->is_delete
? (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL)
: (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL)) {
-
/* Build the appropriate update vector which sets
foreign->n_fields first fields in rec to SQL NULL */
- if (table->fts) {
-
- /* For the clause ON DELETE SET NULL, the cascade
- operation is actually an update operation with the new
- values being null. For FTS, this means that the old
- values be deleted and no new values to be added.*/
- cascade->fts_next_doc_id = FTS_NULL_DOC_ID;
- }
update = cascade->update;
@@ -1297,7 +1278,9 @@ row_ins_foreign_check_on_constraint(
UNIV_MEM_INVALID(update->fields,
update->n_fields * sizeof *update->fields);
- for (i = 0; i < foreign->n_fields; i++) {
+ bool affects_fulltext = false;
+
+ for (ulint i = 0; i < foreign->n_fields; i++) {
upd_field_t* ufield = &update->fields[i];
ulint col_no = dict_index_get_nth_col_no(
index, i);
@@ -1313,18 +1296,19 @@ row_ins_foreign_check_on_constraint(
ufield->exp = NULL;
dfield_set_null(&ufield->new_val);
- if (table->fts && dict_table_is_fts_column(
- table->fts->indexes,
- dict_index_get_nth_col_no(index, i),
- dict_col_is_virtual(
- dict_index_get_nth_col(index, i)))
+ if (!affects_fulltext
+ && table->fts && dict_table_is_fts_column(
+ table->fts->indexes,
+ dict_index_get_nth_col_no(index, i),
+ dict_col_is_virtual(
+ dict_index_get_nth_col(index, i)))
!= ULINT_UNDEFINED) {
- fts_col_affacted = TRUE;
+ affects_fulltext = true;
}
}
- if (fts_col_affacted) {
- cascade->fts_doc_id = doc_id;
+ if (affects_fulltext) {
+ fts_trx_add_op(trx, table, doc_id, FTS_DELETE, NULL);
}
if (foreign->v_cols != NULL
@@ -1339,19 +1323,22 @@ row_ins_foreign_check_on_constraint(
}
} else if (table->fts && cascade->is_delete == PLAIN_DELETE) {
/* DICT_FOREIGN_ON_DELETE_CASCADE case */
- for (i = 0; i < foreign->n_fields; i++) {
- if (table->fts && dict_table_is_fts_column(
+ bool affects_fulltext = false;
+
+ for (ulint i = 0; i < foreign->n_fields; i++) {
+ if (dict_table_is_fts_column(
table->fts->indexes,
dict_index_get_nth_col_no(index, i),
dict_col_is_virtual(
dict_index_get_nth_col(index, i)))
!= ULINT_UNDEFINED) {
- fts_col_affacted = TRUE;
+ affects_fulltext = true;
+ break;
}
}
- if (fts_col_affacted) {
- cascade->fts_doc_id = doc_id;
+ if (affects_fulltext) {
+ fts_trx_add_op(trx, table, doc_id, FTS_DELETE, NULL);
}
}
@@ -1361,13 +1348,10 @@ row_ins_foreign_check_on_constraint(
/* Build the appropriate update vector which sets changing
foreign->n_fields first fields in rec to new values */
- n_to_update = row_ins_cascade_calc_update_vec(
- node, foreign, cascade->cascade_heap,
- trx, &fts_col_affacted, cascade);
+ bool affects_fulltext = row_ins_cascade_calc_update_vec(
+ node, foreign, tmp_heap, trx);
-
- if (foreign->v_cols != NULL
- && foreign->v_cols->size() > 0) {
+ if (foreign->v_cols && !foreign->v_cols->empty()) {
row_ins_foreign_fill_virtual(
cascade, clust_rec, clust_index,
node, foreign, &err);
@@ -1377,7 +1361,8 @@ row_ins_foreign_check_on_constraint(
}
}
- if (n_to_update == ULINT_UNDEFINED) {
+ switch (cascade->update->n_fields) {
+ case ULINT_UNDEFINED:
err = DB_ROW_IS_REFERENCED;
row_ins_foreign_report_err(
@@ -1390,10 +1375,7 @@ row_ins_foreign_check_on_constraint(
thr, foreign, btr_pcur_get_rec(pcur), entry);
goto nonstandard_exit_func;
- }
-
- if (cascade->update->n_fields == 0) {
-
+ case 0:
/* The update does not change any columns referred
to in this foreign key constraint: no need to do
anything */
@@ -1404,9 +1386,9 @@ row_ins_foreign_check_on_constraint(
}
/* Mark the old Doc ID as deleted */
- if (fts_col_affacted) {
+ if (affects_fulltext) {
ut_ad(table->fts);
- cascade->fts_doc_id = doc_id;
+ fts_trx_add_op(trx, table, doc_id, FTS_DELETE, NULL);
}
}
@@ -1428,20 +1410,15 @@ row_ins_foreign_check_on_constraint(
cascade->state = UPD_NODE_UPDATE_CLUSTERED;
#ifdef WITH_WSREP
- err = wsrep_append_foreign_key(
- thr_get_trx(thr),
- foreign,
- clust_rec,
- clust_index,
+ err = wsrep_append_foreign_key(trx, foreign, clust_rec, clust_index,
FALSE, FALSE);
if (err != DB_SUCCESS) {
fprintf(stderr,
"WSREP: foreign key append failed: %d\n", err);
} else
#endif /* WITH_WSREP */
- node->new_upd_nodes->push_back(cascade);
-
- table->inc_fk_checks();
+ err = row_update_cascade_for_mysql(thr, cascade,
+ foreign->foreign_table);
/* Release the data dictionary latch for a while, so that we do not
starve other threads from doing CREATE TABLE etc. if we have a huge
@@ -1466,7 +1443,6 @@ row_ins_foreign_check_on_constraint(
DBUG_RETURN(err);
nonstandard_exit_func:
- que_graph_free_recursive(cascade);
if (tmp_heap) {
mem_heap_free(tmp_heap);
@@ -1616,7 +1592,8 @@ row_ins_check_foreign_constraint(
if (que_node_get_type(thr->run_node) == QUE_NODE_UPDATE) {
upd_node = static_cast<upd_node_t*>(thr->run_node);
- if (!(upd_node->is_delete) && upd_node->foreign == foreign) {
+ if (upd_node->is_delete != PLAIN_DELETE
+ && upd_node->foreign == foreign) {
/* If a cascaded update is done as defined by a
foreign key constraint, do not check that
constraint for the child row. In ON UPDATE CASCADE
@@ -1905,9 +1882,10 @@ do_possible_lock_wait:
thr->lock_state = QUE_THR_LOCK_NOLOCK;
- err = check_table->to_be_dropped
- ? DB_LOCK_WAIT_TIMEOUT
- : trx->error_state;
+ if (check_table->to_be_dropped
+ || trx->error_state == DB_LOCK_WAIT_TIMEOUT) {
+ err = DB_LOCK_WAIT_TIMEOUT;
+ }
check_table->dec_fk_checks();
}
@@ -1970,6 +1948,10 @@ row_ins_check_foreign_constraints(
row_mysql_freeze_data_dictionary(trx);
}
+ if (referenced_table) {
+ foreign->foreign_table->inc_fk_checks();
+ }
+
/* NOTE that if the thread ends up waiting for a lock
we will release dict_operation_lock temporarily!
But the counter on the table protects the referenced
@@ -1978,6 +1960,10 @@ row_ins_check_foreign_constraints(
err = row_ins_check_foreign_constraint(
TRUE, foreign, table, entry, thr);
+ if (referenced_table) {
+ foreign->foreign_table->dec_fk_checks();
+ }
+
if (got_s_lock) {
row_mysql_unfreeze_data_dictionary(trx);
}
@@ -2893,21 +2879,18 @@ row_ins_sec_index_entry_low(
cursor.rtr_info = NULL;
ut_ad(thr_get_trx(thr)->id != 0);
- mtr_start(&mtr);
- mtr.set_named_space(index->space);
-
- if (dict_table_is_temporary(index->table)) {
- /* Disable REDO logging as the lifetime of temp-tables is
- limited to server or connection lifetime and so REDO
- information is not needed on restart for recovery.
- Disable locking as temp-tables are local to a connection. */
+ mtr.start();
+ if (index->table->is_temporary()) {
+ /* Disable locking, because temporary tables are never
+ shared between transactions or connections. */
ut_ad(flags & BTR_NO_LOCKING_FLAG);
mtr.set_log_mode(MTR_LOG_NO_REDO);
- } else if (!dict_index_is_spatial(index)) {
- /* Enable insert buffering if it's neither temp-table
- nor spatial index. */
- search_mode |= BTR_INSERT;
+ } else {
+ mtr.set_named_space(index->space);
+ if (!dict_index_is_spatial(index)) {
+ search_mode |= BTR_INSERT;
+ }
}
/* Ensure that we acquire index->lock when inserting into an
@@ -2979,10 +2962,8 @@ row_ins_sec_index_entry_low(
}
if (err != DB_SUCCESS) {
- trx_t* trx = thr_get_trx(thr);
-
if (err == DB_DECRYPTION_FAILED) {
- ib_push_warning(trx->mysql_thd,
+ ib_push_warning(thr_get_trx(thr)->mysql_thd,
DB_DECRYPTION_FAILED,
"Table %s is encrypted but encryption service or"
" used key_id is not available. "
@@ -3465,7 +3446,7 @@ row_ins_index_entry_set_vals(
= dict_field_get_col(ind_field);
len = dtype_get_at_most_n_mbchars(
- col->prtype, col->mbminmaxlen,
+ col->prtype, col->mbminlen, col->mbmaxlen,
ind_field->prefix_len,
len,
static_cast<const char*>(
diff --git a/storage/innobase/row/row0log.cc b/storage/innobase/row/row0log.cc
index 9b5c9873604..64ae384ec37 100644
--- a/storage/innobase/row/row0log.cc
+++ b/storage/innobase/row/row0log.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2011, 2017, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, MariaDB Corporation.
+Copyright (c) 2017, 2018, 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
@@ -1300,7 +1300,7 @@ row_log_table_get_pk(
dict_field_t* ifield;
dfield_t* dfield;
ulint prtype;
- ulint mbminmaxlen;
+ ulint mbminlen, mbmaxlen;
ifield = dict_index_get_nth_field(new_index, new_i);
dfield = dtuple_get_nth_field(tuple, new_i);
@@ -1329,7 +1329,8 @@ err_exit:
goto func_exit;
}
- mbminmaxlen = col->mbminmaxlen;
+ mbminlen = col->mbminlen;
+ mbmaxlen = col->mbmaxlen;
prtype = col->prtype;
} else {
/* No matching column was found in the old
@@ -1339,7 +1340,8 @@ err_exit:
dfield_copy(dfield, dtuple_get_nth_field(
log->add_cols, col_no));
- mbminmaxlen = dfield->type.mbminmaxlen;
+ mbminlen = dfield->type.mbminlen;
+ mbmaxlen = dfield->type.mbmaxlen;
prtype = dfield->type.prtype;
}
@@ -1348,7 +1350,7 @@ err_exit:
if (ifield->prefix_len) {
ulint len = dtype_get_at_most_n_mbchars(
- prtype, mbminmaxlen,
+ prtype, mbminlen, mbmaxlen,
ifield->prefix_len,
dfield_get_len(dfield),
static_cast<const char*>(
diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc
index 943db575948..a0b73c46703 100644
--- a/storage/innobase/row/row0merge.cc
+++ b/storage/innobase/row/row0merge.cc
@@ -450,8 +450,8 @@ row_merge_buf_redundant_convert(
const page_size_t& page_size,
mem_heap_t* heap)
{
- ut_ad(DATA_MBMINLEN(field->type.mbminmaxlen) == 1);
- ut_ad(DATA_MBMAXLEN(field->type.mbminmaxlen) > 1);
+ ut_ad(field->type.mbminlen == 1);
+ ut_ad(field->type.mbmaxlen > 1);
byte* buf = (byte*) mem_heap_alloc(heap, len);
ulint field_len = row_field->len;
@@ -593,7 +593,8 @@ row_merge_buf_add(
field->type.mtype = ifield->col->mtype;
field->type.prtype = ifield->col->prtype;
- field->type.mbminmaxlen = DATA_MBMINMAXLEN(0, 0);
+ field->type.mbminlen = 0;
+ field->type.mbmaxlen = 0;
field->type.len = ifield->col->len;
} else {
/* Use callback to get the virtual column value */
@@ -744,7 +745,7 @@ row_merge_buf_add(
if (ifield->prefix_len) {
len = dtype_get_at_most_n_mbchars(
col->prtype,
- col->mbminmaxlen,
+ col->mbminlen, col->mbmaxlen,
ifield->prefix_len,
len,
static_cast<char*>(dfield_get_data(field)));
@@ -756,8 +757,7 @@ row_merge_buf_add(
fixed_len = ifield->fixed_len;
if (fixed_len && !dict_table_is_comp(index->table)
- && DATA_MBMINLEN(col->mbminmaxlen)
- != DATA_MBMAXLEN(col->mbminmaxlen)) {
+ && col->mbminlen != col->mbmaxlen) {
/* CHAR in ROW_FORMAT=REDUNDANT is always
fixed-length, but in the temporary file it is
variable-length for variable-length character
@@ -767,14 +767,11 @@ row_merge_buf_add(
if (fixed_len) {
#ifdef UNIV_DEBUG
- ulint mbminlen = DATA_MBMINLEN(col->mbminmaxlen);
- ulint mbmaxlen = DATA_MBMAXLEN(col->mbminmaxlen);
-
/* len should be between size calcualted base on
mbmaxlen and mbminlen */
ut_ad(len <= fixed_len);
- ut_ad(!mbmaxlen || len >= mbminlen
- * (fixed_len / mbmaxlen));
+ ut_ad(!col->mbmaxlen || len >= col->mbminlen
+ * (fixed_len / col->mbmaxlen));
ut_ad(!dfield_is_ext(field));
#endif /* UNIV_DEBUG */
@@ -4663,6 +4660,8 @@ row_merge_build_indexes(
DBUG_RETURN(DB_OUT_OF_MEMORY);
}
+ TRASH_ALLOC(&crypt_pfx, sizeof crypt_pfx);
+
if (log_tmp_is_encrypted()) {
crypt_block = static_cast<row_merge_block_t*>(
alloc.allocate_large(3 * srv_sort_buf_size,
diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc
index d62ab03f094..efe5f763263 100644
--- a/storage/innobase/row/row0mysql.cc
+++ b/storage/innobase/row/row0mysql.cc
@@ -307,29 +307,6 @@ row_mysql_store_geometry(
mach_write_to_n_little_endian(dest, dest_len - 8, src_len);
memcpy(dest + dest_len - 8, &src, sizeof src);
-
- DBUG_EXECUTE_IF("row_print_geometry_data",
- {
- String res;
- Geometry_buffer buffer;
- String wkt;
-
- /** Show the meaning of geometry data. */
- Geometry* g = Geometry::construct(
- &buffer, (const char*)src, (uint32) src_len);
-
- if (g)
- {
- /*
- if (g->as_wkt(&wkt) == 0)
- {
- ib::info() << "Write geometry data to"
- " MySQL WKT format: "
- << wkt.c_ptr_safe() << ".";
- }
- */
- }
- });
}
/*******************************************************************//**
@@ -350,29 +327,6 @@ row_mysql_read_geometry(
memcpy(&data, ref + col_len - 8, sizeof data);
- DBUG_EXECUTE_IF("row_print_geometry_data",
- {
- String res;
- Geometry_buffer buffer;
- String wkt;
-
- /** Show the meaning of geometry data. */
- Geometry* g = Geometry::construct(
- &buffer, (const char*) data, (uint32) *len);
-
- if (g)
- {
- /*
- if (g->as_wkt(&wkt) == 0)
- {
- ib::info() << "Read geometry data in"
- " MySQL's WKT format: "
- << wkt.c_ptr_safe() << ".";
- }
- */
- }
- });
-
return(data);
}
@@ -1694,8 +1648,6 @@ row_create_update_node_for_mysql(
node->table_sym = NULL;
node->col_assign_list = NULL;
- node->fts_doc_id = FTS_NULL_DOC_ID;
- node->fts_next_doc_id = UINT64_UNDEFINED;
DBUG_RETURN(node);
}
@@ -1743,9 +1695,9 @@ row_fts_do_update(
doc_id_t old_doc_id, /* in: old document id */
doc_id_t new_doc_id) /* in: new document id */
{
- fts_trx_add_op(trx, table, old_doc_id, FTS_DELETE, NULL);
-
- if (new_doc_id != FTS_NULL_DOC_ID) {
+ if(trx->fts_next_doc_id) {
+ fts_trx_add_op(trx, table, old_doc_id, FTS_DELETE, NULL);
+ if(new_doc_id != FTS_NULL_DOC_ID)
fts_trx_add_op(trx, table, new_doc_id, FTS_INSERT, NULL);
}
}
@@ -1757,24 +1709,30 @@ static
dberr_t
row_fts_update_or_delete(
/*=====================*/
- trx_t* trx,
- upd_node_t* node) /* in: prebuilt struct in MySQL
+ row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
handle */
{
- dict_table_t* table = node->table;
- doc_id_t old_doc_id = node->fts_doc_id;
+ trx_t* trx = prebuilt->trx;
+ dict_table_t* table = prebuilt->table;
+ upd_node_t* node = prebuilt->upd_node;
+ doc_id_t old_doc_id = prebuilt->fts_doc_id;
+
DBUG_ENTER("row_fts_update_or_delete");
- ut_a(dict_table_has_fts_index(node->table));
+ ut_a(dict_table_has_fts_index(prebuilt->table));
/* Deletes are simple; get them out of the way first. */
if (node->is_delete == PLAIN_DELETE) {
/* A delete affects all FTS indexes, so we pass NULL */
fts_trx_add_op(trx, table, old_doc_id, FTS_DELETE, NULL);
} else {
- doc_id_t new_doc_id = node->fts_next_doc_id;
- ut_ad(new_doc_id != UINT64_UNDEFINED);
+ doc_id_t new_doc_id;
+ new_doc_id = fts_read_doc_id((byte*) &trx->fts_next_doc_id);
+ if (new_doc_id == 0) {
+ ib::error() << "InnoDB FTS: Doc ID cannot be 0";
+ return(DB_FTS_INVALID_DOCID);
+ }
row_fts_do_update(trx, table, old_doc_id, new_doc_id);
}
@@ -1823,14 +1781,6 @@ init_fts_doc_id_for_ref(
}
}
-struct dec_foreign_key_checks_running
-{
- void operator() (upd_node_t* node) {
- node->table->dec_fk_checks();
- }
-};
-
-
/** Does an update or delete of a row for MySQL.
@param[in,out] prebuilt prebuilt struct in MySQL handle
@return error code or DB_SUCCESS */
@@ -1840,15 +1790,11 @@ row_update_for_mysql(row_prebuilt_t* prebuilt)
trx_savept_t savept;
dberr_t err;
que_thr_t* thr;
- ibool was_lock_wait;
dict_index_t* clust_index;
upd_node_t* node;
dict_table_t* table = prebuilt->table;
trx_t* trx = prebuilt->trx;
ulint fk_depth = 0;
- upd_cascade_t* cascade_upd_nodes;
- upd_cascade_t* new_upd_nodes;
- upd_cascade_t* processed_cascades;
bool got_s_lock = false;
DBUG_ENTER("row_update_for_mysql");
@@ -1895,26 +1841,6 @@ row_update_for_mysql(row_prebuilt_t* prebuilt)
const bool is_delete = node->is_delete == PLAIN_DELETE;
ut_ad(node->table == table);
- if (node->cascade_heap) {
- mem_heap_empty(node->cascade_heap);
- } else {
- node->cascade_heap = mem_heap_create(128);
- }
-
- mem_heap_allocator<upd_node_t*> mem_heap_ator(node->cascade_heap);
-
- cascade_upd_nodes = new
- (mem_heap_ator.allocate(sizeof(upd_cascade_t)))
- upd_cascade_t(deque_mem_heap_t(mem_heap_ator));
-
- new_upd_nodes = new
- (mem_heap_ator.allocate(sizeof(upd_cascade_t)))
- upd_cascade_t(deque_mem_heap_t(mem_heap_ator));
-
- processed_cascades = new
- (mem_heap_ator.allocate(sizeof(upd_cascade_t)))
- upd_cascade_t(deque_mem_heap_t(mem_heap_ator));
-
clust_index = dict_table_get_first_index(table);
if (prebuilt->pcur->btr_cur.index == clust_index) {
@@ -1939,174 +1865,97 @@ row_update_for_mysql(row_prebuilt_t* prebuilt)
node->state = UPD_NODE_UPDATE_CLUSTERED;
- node->cascade_top = true;
- node->cascade_upd_nodes = cascade_upd_nodes;
- node->new_upd_nodes = new_upd_nodes;
- node->processed_cascades = processed_cascades;
- node->fts_doc_id = prebuilt->fts_doc_id;
-
- if (trx->fts_next_doc_id != UINT64_UNDEFINED) {
- node->fts_next_doc_id = fts_read_doc_id(
- (byte*) &trx->fts_next_doc_id);
- } else {
- node->fts_next_doc_id = UINT64_UNDEFINED;
- }
-
ut_ad(!prebuilt->sql_stat_start);
que_thr_move_to_run_state_for_mysql(thr, trx);
- thr->fk_cascade_depth = 0;
-
ut_ad(!prebuilt->versioned_write || node->table->versioned());
bool vers_set_fields = prebuilt->versioned_write
&& (node->is_delete ? node->is_delete == VERSIONED_DELETE
: node->update->affects_versioned());
-run_again:
- if (vers_set_fields) {
- /* System Versioning: modify update vector to set
- row_start (or row_end in case of DELETE)
- to current trx_id. */
- dict_table_t* table = node->table;
- dict_index_t* clust_index = dict_table_get_first_index(table);
- upd_t* uvect = node->update;
- upd_field_t* ufield;
- dict_col_t* col;
- unsigned col_idx;
- if (node->is_delete) {
- ufield = &uvect->fields[0];
- uvect->n_fields = 0;
- node->is_delete = VERSIONED_DELETE;
- col_idx = table->vers_end;
- } else {
- ut_ad(uvect->n_fields < table->n_cols);
- ufield = &uvect->fields[uvect->n_fields];
- col_idx = table->vers_start;
- }
- col = &table->cols[col_idx];
- UNIV_MEM_INVALID(ufield, sizeof *ufield);
- {
- ulint field_no = dict_col_get_clust_pos(col, clust_index);
- ut_ad(field_no != ULINT_UNDEFINED);
- ufield->field_no = field_no;
- }
- ufield->orig_len = 0;
- ufield->exp = NULL;
- mach_write_to_8(node->update->vers_sys_value, trx->id);
- dfield_t* dfield = &ufield->new_val;
- dfield_set_data(dfield, node->update->vers_sys_value, 8);
- dict_col_copy_type(col, &dfield->type);
+ for (;;) {
+ if (vers_set_fields) {
+ /* System Versioning: modify update vector to set
+ row_start (or row_end in case of DELETE)
+ to current trx_id. */
+ dict_table_t* table = node->table;
+ dict_index_t* clust_index = dict_table_get_first_index(table);
+ upd_t* uvect = node->update;
+ upd_field_t* ufield;
+ dict_col_t* col;
+ unsigned col_idx;
+ if (node->is_delete) {
+ ufield = &uvect->fields[0];
+ uvect->n_fields = 0;
+ node->is_delete = VERSIONED_DELETE;
+ col_idx = table->vers_end;
+ } else {
+ ut_ad(uvect->n_fields < table->n_cols);
+ ufield = &uvect->fields[uvect->n_fields];
+ col_idx = table->vers_start;
+ }
+ col = &table->cols[col_idx];
+ UNIV_MEM_INVALID(ufield, sizeof *ufield);
+ {
+ ulint field_no = dict_col_get_clust_pos(col, clust_index);
+ ut_ad(field_no != ULINT_UNDEFINED);
+ ufield->field_no = field_no;
+ }
+ ufield->orig_len = 0;
+ ufield->exp = NULL;
- uvect->n_fields++;
- ut_ad(node->in_mysql_interface); // otherwise needs to recalculate node->cmpl_info
- }
+ mach_write_to_8(node->update->vers_sys_value, trx->id);
+ dfield_t* dfield = &ufield->new_val;
+ dfield_set_data(dfield, node->update->vers_sys_value, 8);
+ dict_col_copy_type(col, &dfield->type);
- if (thr->fk_cascade_depth == 1 && trx->dict_operation_lock_mode == 0) {
- got_s_lock = true;
- row_mysql_freeze_data_dictionary(trx);
- }
+ uvect->n_fields++;
+ ut_ad(node->in_mysql_interface); // otherwise needs to recalculate node->cmpl_info
+ }
- thr->run_node = node;
- thr->prev_node = node;
+ thr->run_node = node;
+ thr->prev_node = node;
+ thr->fk_cascade_depth = 0;
- row_upd_step(thr);
+ row_upd_step(thr);
- DBUG_EXECUTE_IF("dml_cascade_only_once", node->check_cascade_only_once(););
+ err = trx->error_state;
- err = trx->error_state;
+ if (err == DB_SUCCESS) {
+ break;
+ }
- if (err != DB_SUCCESS) {
-handle_error:
que_thr_stop_for_mysql(thr);
if (err == DB_RECORD_NOT_FOUND) {
trx->error_state = DB_SUCCESS;
- trx->op_info = "";
-
- if (thr->fk_cascade_depth > 0) {
- que_graph_free_recursive(node);
- }
goto error;
}
- /* Since reporting a plain "duplicate key" error message to
- the user in cases where a long CASCADE operation would lead
- to a duplicate key in some other table is very confusing,
- map duplicate key errors resulting from FK constraints to a
- separate error code. */
- if (err == DB_DUPLICATE_KEY && thr->fk_cascade_depth > 0) {
- err = DB_FOREIGN_DUPLICATE_KEY;
- trx->error_state = err;
- }
-
thr->lock_state= QUE_THR_LOCK_ROW;
DEBUG_SYNC(trx->mysql_thd, "row_update_for_mysql_error");
- was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
- &savept);
+ bool was_lock_wait = row_mysql_handle_errors(
+ &err, trx, thr, &savept);
thr->lock_state= QUE_THR_LOCK_NOLOCK;
- if (was_lock_wait) {
- std::for_each(new_upd_nodes->begin(),
- new_upd_nodes->end(),
- dec_foreign_key_checks_running());
- std::for_each(new_upd_nodes->begin(),
- new_upd_nodes->end(),
- que_graph_free_recursive);
- node->new_upd_nodes->clear();
- goto run_again;
- }
-
- trx->op_info = "";
-
- if (thr->fk_cascade_depth > 0) {
- que_graph_free_recursive(node);
+ if (!was_lock_wait) {
+ goto error;
}
- goto error;
- } else {
-
- std::copy(node->new_upd_nodes->begin(),
- node->new_upd_nodes->end(),
- std::back_inserter(*node->cascade_upd_nodes));
-
- node->new_upd_nodes->clear();
}
- if (dict_table_has_fts_index(node->table)
- && node->fts_doc_id != FTS_NULL_DOC_ID
- && node->fts_next_doc_id != UINT64_UNDEFINED) {
- err = row_fts_update_or_delete(trx, node);
- ut_a(err == DB_SUCCESS);
- }
-
- if (thr->fk_cascade_depth > 0) {
- /* Processing cascade operation */
- dec_foreign_key_checks_running()(node);
- node->processed_cascades->push_back(node);
- }
-
- if (!cascade_upd_nodes->empty()) {
- DEBUG_SYNC_C("foreign_constraint_update_cascade");
- node = cascade_upd_nodes->front();
- node->cascade_upd_nodes = cascade_upd_nodes;
- cascade_upd_nodes->pop_front();
- thr->fk_cascade_depth++;
- vers_set_fields = node->table->versioned()
- && (node->is_delete == PLAIN_DELETE
- || node->update->affects_versioned());
-
- if (vers_set_fields && !prebuilt->versioned_write)
- {
- // FIXME: timestamp-based update of row_end in run_again
- err = DB_UNSUPPORTED;
- trx->error_state = err;
+ que_thr_stop_for_mysql_no_error(thr, trx);
- goto handle_error;
+ if (dict_table_has_fts_index(table)
+ && trx->fts_next_doc_id != UINT64_UNDEFINED) {
+ err = row_fts_update_or_delete(prebuilt);
+ if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
+ ut_ad(!"unexpected error");
+ goto error;
}
- goto run_again;
}
/* Completed cascading operations (if any) */
@@ -2114,43 +1963,8 @@ handle_error:
row_mysql_unfreeze_data_dictionary(trx);
}
- thr->fk_cascade_depth = 0;
-
- /* Update the statistics of each involved table
- only after completing all operations, including
- FOREIGN KEY...ON...CASCADE|SET NULL. */
bool update_statistics;
-
- for (upd_cascade_t::iterator i = processed_cascades->begin();
- i != processed_cascades->end();
- ++i) {
-
- node = *i;
-
- if (node->is_delete == PLAIN_DELETE) {
- /* Not protected by dict_table_stats_lock() for
- performance reasons, we would rather get garbage
- in stat_n_rows (which is just an estimate anyway)
- than protecting the following code with a latch. */
- dict_table_n_rows_dec(node->table);
-
- update_statistics = !srv_stats_include_delete_marked;
- srv_stats.n_rows_deleted.inc(size_t(trx->id));
- } else {
- update_statistics
- = !(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE);
- srv_stats.n_rows_updated.inc(size_t(trx->id));
- }
-
- if (update_statistics) {
- dict_stats_update_if_needed(node->table);
- } else {
- /* Always update the table modification counter. */
- node->table->stat_modified_counter++;
- }
-
- que_graph_free_recursive(node);
- }
+ ut_ad(is_delete == (node->is_delete == PLAIN_DELETE));
if (is_delete) {
/* Not protected by dict_table_stats_lock() for performance
@@ -2186,42 +2000,14 @@ handle_error:
trx->op_info = "";
- que_thr_stop_for_mysql_no_error(thr, trx);
-
- DBUG_ASSERT(cascade_upd_nodes->empty());
-
DBUG_RETURN(err);
error:
+ trx->op_info = "";
if (got_s_lock) {
row_mysql_unfreeze_data_dictionary(trx);
}
- if (thr->fk_cascade_depth > 0) {
- dec_foreign_key_checks_running()(node);
- thr->fk_cascade_depth = 0;
- }
-
- std::for_each(cascade_upd_nodes->begin(),
- cascade_upd_nodes->end(),
- dec_foreign_key_checks_running());
-
- std::for_each(new_upd_nodes->begin(),
- new_upd_nodes->end(),
- dec_foreign_key_checks_running());
-
- std::for_each(cascade_upd_nodes->begin(),
- cascade_upd_nodes->end(),
- que_graph_free_recursive);
-
- std::for_each(new_upd_nodes->begin(),
- new_upd_nodes->end(),
- que_graph_free_recursive);
-
- std::for_each(processed_cascades->begin(),
- processed_cascades->end(),
- que_graph_free_recursive);
-
DBUG_RETURN(err);
}
@@ -2388,6 +2174,141 @@ row_mysql_unfreeze_data_dictionary(
trx->dict_operation_lock_mode = 0;
}
+/**********************************************************************//**
+Does a cascaded delete or set null in a foreign key operation.
+@return error code or DB_SUCCESS */
+dberr_t
+row_update_cascade_for_mysql(
+/*=========================*/
+ que_thr_t* thr, /*!< in: query thread */
+ upd_node_t* node, /*!< in: update node used in the cascade
+ or set null operation */
+ dict_table_t* table) /*!< in: table where we do the operation */
+{
+ /* Increment fk_cascade_depth to record the recursive call depth on
+ a single update/delete that affects multiple tables chained
+ together with foreign key relations. */
+
+ if (++thr->fk_cascade_depth > FK_MAX_CASCADE_DEL) {
+ return(DB_FOREIGN_EXCEED_MAX_CASCADE);
+ }
+
+ trx_t* trx = thr_get_trx(thr);
+
+ bool vers_set_fields = node->table->versioned()
+ && (node->is_delete == PLAIN_DELETE
+ || node->update->affects_versioned());
+
+ if (vers_set_fields && !thr->prebuilt->versioned_write)
+ {
+ // FIXME: timestamp-based update of row_end in run_again
+ trx->error_state = DB_UNSUPPORTED;
+ thr->fk_cascade_depth = 0;
+ return trx->error_state;
+ }
+
+ for (;;) {
+ if (vers_set_fields) {
+ // FIXME: code duplication with row_update_for_mysql()
+ /* System Versioning: modify update vector to set
+ row_start (or row_end in case of DELETE)
+ to current trx_id. */
+ dict_table_t* table = node->table;
+ dict_index_t* clust_index = dict_table_get_first_index(table);
+ upd_t* uvect = node->update;
+ upd_field_t* ufield;
+ dict_col_t* col;
+ unsigned col_idx;
+ if (node->is_delete) {
+ ufield = &uvect->fields[0];
+ uvect->n_fields = 0;
+ node->is_delete = VERSIONED_DELETE;
+ col_idx = table->vers_end;
+ } else {
+ ut_ad(uvect->n_fields < table->n_cols);
+ ufield = &uvect->fields[uvect->n_fields];
+ col_idx = table->vers_start;
+ }
+ col = &table->cols[col_idx];
+ UNIV_MEM_INVALID(ufield, sizeof *ufield);
+ {
+ ulint field_no = dict_col_get_clust_pos(col, clust_index);
+ ut_ad(field_no != ULINT_UNDEFINED);
+ ufield->field_no = field_no;
+ }
+ ufield->orig_len = 0;
+ ufield->exp = NULL;
+
+ mach_write_to_8(node->update->vers_sys_value, trx->id);
+ dfield_t* dfield = &ufield->new_val;
+ dfield_set_data(dfield, node->update->vers_sys_value, 8);
+ dict_col_copy_type(col, &dfield->type);
+
+ uvect->n_fields++;
+ ut_ad(node->in_mysql_interface); // otherwise needs to recalculate node->cmpl_info
+ }
+
+ thr->run_node = node;
+ thr->prev_node = node;
+
+ DEBUG_SYNC_C("foreign_constraint_update_cascade");
+ {
+ TABLE *mysql_table = thr->prebuilt->m_mysql_table;
+ thr->prebuilt->m_mysql_table = NULL;
+ row_upd_step(thr);
+ thr->prebuilt->m_mysql_table = mysql_table;
+ }
+
+ switch (trx->error_state) {
+ case DB_LOCK_WAIT:
+ que_thr_stop_for_mysql(thr);
+ lock_wait_suspend_thread(thr);
+
+ if (trx->error_state == DB_SUCCESS) {
+ continue;
+ }
+
+ /* fall through */
+ default:
+ /* Other errors are handled for the parent node. */
+ thr->fk_cascade_depth = 0;
+ return trx->error_state;
+
+ case DB_SUCCESS:
+ thr->fk_cascade_depth = 0;
+ bool stats;
+
+ if (node->is_delete == PLAIN_DELETE) {
+ /* Not protected by
+ dict_table_stats_lock() for
+ performance reasons, we would rather
+ get garbage in stat_n_rows (which is
+ just an estimate anyway) than
+ protecting the following code with a
+ latch. */
+ dict_table_n_rows_dec(node->table);
+
+ stats = !srv_stats_include_delete_marked;
+ srv_stats.n_rows_deleted.inc(size_t(trx->id));
+ } else {
+ stats = !(node->cmpl_info
+ & UPD_NODE_NO_ORD_CHANGE);
+ srv_stats.n_rows_updated.inc(size_t(trx->id));
+ }
+
+ if (stats) {
+ dict_stats_update_if_needed(node->table);
+ } else {
+ /* Always update the table
+ modification counter. */
+ node->table->stat_modified_counter++;
+ }
+
+ return(DB_SUCCESS);
+ }
+ }
+}
+
/*********************************************************************//**
Locks the data dictionary exclusively for performing a table create or other
data dictionary modification operation. */
@@ -4923,6 +4844,8 @@ end:
DICT_ERR_IGNORE_NONE);
fk_tables.pop_front();
}
+
+ table->data_dir_path= NULL;
}
funct_exit:
@@ -4975,59 +4898,6 @@ funct_exit:
return(err);
}
-/** Renames a partitioned table for MySQL.
-@param[in] old_name Old table name.
-@param[in] new_name New table name.
-@param[in,out] trx Transaction.
-@return error code or DB_SUCCESS */
-dberr_t
-row_rename_partitions_for_mysql(
- const char* old_name,
- const char* new_name,
- trx_t* trx)
-{
- char from_name[FN_REFLEN];
- char to_name[FN_REFLEN];
- ulint from_len = strlen(old_name);
- ulint to_len = strlen(new_name);
- char* table_name;
- dberr_t error = DB_TABLE_NOT_FOUND;
-
- ut_a(from_len < (FN_REFLEN - 4));
- ut_a(to_len < (FN_REFLEN - 4));
- memcpy(from_name, old_name, from_len);
- from_name[from_len] = '#';
- from_name[from_len + 1] = 0;
- while ((table_name = dict_get_first_table_name_in_db(from_name))) {
- ut_a(memcmp(table_name, from_name, from_len) == 0);
- /* Must match #[Pp]#<partition_name> */
- if (strlen(table_name) <= (from_len + 3)
- || table_name[from_len] != '#'
- || table_name[from_len + 2] != '#'
- || (table_name[from_len + 1] != 'P'
- && table_name[from_len + 1] != 'p')) {
-
- ut_ad(0);
- ut_free(table_name);
- continue;
- }
- memcpy(to_name, new_name, to_len);
- memcpy(to_name + to_len, table_name + from_len,
- strlen(table_name) - from_len + 1);
- error = row_rename_table_for_mysql(table_name, to_name,
- trx, false);
- if (error != DB_SUCCESS) {
- /* Rollback and return. */
- trx_rollback_for_mysql(trx);
- ut_free(table_name);
- return(error);
- }
- ut_free(table_name);
- }
- trx_commit_for_mysql(trx);
- return(error);
-}
-
/*********************************************************************//**
Scans an index for either COUNT(*) or CHECK TABLE.
If CHECK TABLE; Checks that the index contains entries in an ascending order,
diff --git a/storage/innobase/row/row0quiesce.cc b/storage/innobase/row/row0quiesce.cc
index 77cb35b8f21..938f9156717 100644
--- a/storage/innobase/row/row0quiesce.cc
+++ b/storage/innobase/row/row0quiesce.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2012, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, MariaDB Corporation.
+Copyright (c) 2017, 2018, 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
@@ -239,7 +239,11 @@ row_quiesce_write_table(
mach_write_to_4(ptr, col->len);
ptr += sizeof(ib_uint32_t);
- mach_write_to_4(ptr, col->mbminmaxlen);
+ /* FIXME: This will not work if mbminlen>4.
+ This field is also redundant, because the lengths
+ are a property of the character set encoding, which
+ in turn is encodedin prtype above. */
+ mach_write_to_4(ptr, col->mbmaxlen * 5 + col->mbminlen);
ptr += sizeof(ib_uint32_t);
mach_write_to_4(ptr, col->ind);
diff --git a/storage/innobase/row/row0row.cc b/storage/innobase/row/row0row.cc
index 024c54cfe22..f9aa4fadacc 100644
--- a/storage/innobase/row/row0row.cc
+++ b/storage/innobase/row/row0row.cc
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2018, 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
@@ -333,7 +334,7 @@ row_build_index_entry_low(
/* If a column prefix index, take only the prefix. */
if (ind_field->prefix_len) {
len = dtype_get_at_most_n_mbchars(
- col->prtype, col->mbminmaxlen,
+ col->prtype, col->mbminlen, col->mbmaxlen,
ind_field->prefix_len, len,
static_cast<char*>(dfield_get_data(dfield)));
dfield_set_len(dfield, len);
@@ -876,7 +877,8 @@ row_build_row_ref(
dfield_set_len(dfield,
dtype_get_at_most_n_mbchars(
dtype->prtype,
- dtype->mbminmaxlen,
+ dtype->mbminlen,
+ dtype->mbmaxlen,
clust_col_prefix_len,
len, (char*) field));
}
@@ -977,7 +979,8 @@ row_build_row_ref_in_tuple(
dfield_set_len(dfield,
dtype_get_at_most_n_mbchars(
dtype->prtype,
- dtype->mbminmaxlen,
+ dtype->mbminlen,
+ dtype->mbmaxlen,
clust_col_prefix_len,
len, (char*) field));
}
diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc
index ccc2ab0c14c..f8507443100 100644
--- a/storage/innobase/row/row0sel.cc
+++ b/storage/innobase/row/row0sel.cc
@@ -87,8 +87,10 @@ row_sel_sec_rec_is_for_blob(
/*========================*/
ulint mtype, /*!< in: main type */
ulint prtype, /*!< in: precise type */
- ulint mbminmaxlen, /*!< in: minimum and maximum length of
- a multi-byte character */
+ ulint mbminlen, /*!< in: minimum length of
+ a character, in bytes */
+ ulint mbmaxlen, /*!< in: maximum length of
+ a character, in bytes */
const byte* clust_field, /*!< in: the locally stored part of
the clustered index column, including
the BLOB pointer; the clustered
@@ -136,7 +138,7 @@ row_sel_sec_rec_is_for_blob(
return(FALSE);
}
- len = dtype_get_at_most_n_mbchars(prtype, mbminmaxlen,
+ len = dtype_get_at_most_n_mbchars(prtype, mbminlen, mbmaxlen,
prefix_len, len, (const char*) buf);
return(!cmp_data_data(mtype, prtype, buf, len, sec_field, sec_len));
@@ -258,14 +260,14 @@ row_sel_sec_rec_is_for_clust_rec(
}
len = dtype_get_at_most_n_mbchars(
- col->prtype, col->mbminmaxlen,
+ col->prtype, col->mbminlen, col->mbmaxlen,
ifield->prefix_len, len, (char*) clust_field);
if (rec_offs_nth_extern(clust_offs, clust_pos)
&& len < sec_len) {
if (!row_sel_sec_rec_is_for_blob(
col->mtype, col->prtype,
- col->mbminmaxlen,
+ col->mbminlen, col->mbmaxlen,
clust_field, clust_len,
sec_field, sec_len,
ifield->prefix_len,
@@ -1026,7 +1028,7 @@ row_sel_get_clust_rec(
/* Fetch the columns needed in test conditions. The clustered
index record is protected by a page latch that was acquired
when plan->clust_pcur was positioned. The latch will not be
- released until mtr_commit(mtr). */
+ released until mtr->commit(). */
ut_ad(!rec_get_deleted_flag(clust_rec, rec_offs_comp(offsets)));
row_sel_fetch_columns(index, clust_rec, offsets,
@@ -1093,14 +1095,14 @@ retry:
if (err == DB_LOCK_WAIT) {
re_scan:
- mtr_commit(mtr);
+ mtr->commit();
trx->error_state = err;
que_thr_stop_for_mysql(thr);
thr->lock_state = QUE_THR_LOCK_ROW;
if (row_mysql_handle_errors(
&err, trx, thr, NULL)) {
thr->lock_state = QUE_THR_LOCK_NOLOCK;
- mtr_start(mtr);
+ mtr->start();
mutex_enter(&match->rtr_match_mutex);
if (!match->valid && match->matched_recs->empty()) {
@@ -1120,7 +1122,7 @@ re_scan:
RW_X_LATCH, NULL, BUF_GET,
__FILE__, __LINE__, mtr, &err);
} else {
- mtr_start(mtr);
+ mtr->start();
goto func_end;
}
@@ -1128,8 +1130,8 @@ re_scan:
if (!match->valid) {
/* Page got deleted */
- mtr_commit(mtr);
- mtr_start(mtr);
+ mtr->commit();
+ mtr->start();
err = DB_RECORD_NOT_FOUND;
goto func_end;
}
@@ -1147,8 +1149,8 @@ re_scan:
/* Page got splitted and promoted (only for
root page it is possible). Release the
page and ask for a re-search */
- mtr_commit(mtr);
- mtr_start(mtr);
+ mtr->commit();
+ mtr->start();
err = DB_RECORD_NOT_FOUND;
goto func_end;
}
@@ -1160,8 +1162,8 @@ re_scan:
/* No match record */
if (page_rec_is_supremum(rec) || !match->valid) {
- mtr_commit(mtr);
- mtr_start(mtr);
+ mtr->commit();
+ mtr->start();
err = DB_RECORD_NOT_FOUND;
goto func_end;
}
@@ -1517,7 +1519,7 @@ exhausted:
/* Fetch the columns needed in test conditions. The index
record is protected by a page latch that was acquired when
plan->pcur was positioned. The latch will not be released
- until mtr_commit(mtr). */
+ until mtr->commit(). */
row_sel_fetch_columns(index, rec, offsets,
UT_LIST_GET_FIRST(plan->columns));
@@ -1626,7 +1628,7 @@ table_loop:
/* Open a cursor to index, or restore an open cursor position */
- mtr_start(&mtr);
+ mtr.start();
#ifdef BTR_CUR_HASH_ADAPT
if (consistent_read && plan->unique_search && !plan->pcur_is_open
@@ -1645,8 +1647,8 @@ table_loop:
plan_reset_cursor(plan);
- mtr_commit(&mtr);
- mtr_start(&mtr);
+ mtr.commit();
+ mtr.start();
}
#endif /* BTR_CUR_HASH_ADAPT */
@@ -1910,7 +1912,7 @@ skip_lock:
by row_sel_open_pcur() or
row_sel_restore_pcur_pos().
The latch will not be released
- until mtr_commit(mtr). */
+ until mtr.commit(). */
row_sel_fetch_columns(
index, rec, offsets,
@@ -1940,7 +1942,7 @@ skip_lock:
/* Fetch the columns needed in test conditions. The record is
protected by a page latch that was acquired by
row_sel_open_pcur() or row_sel_restore_pcur_pos(). The latch
- will not be released until mtr_commit(mtr). */
+ will not be released until mtr.commit(). */
row_sel_fetch_columns(index, rec, offsets,
UT_LIST_GET_FIRST(plan->columns));
@@ -2102,7 +2104,7 @@ next_table:
btr_pcur_store_position(&(plan->pcur), &mtr);
}
- mtr_commit(&mtr);
+ mtr.commit();
mtr_has_extra_clust_latch = FALSE;
@@ -2142,7 +2144,7 @@ table_exhausted:
plan->cursor_at_end = TRUE;
- mtr_commit(&mtr);
+ mtr.commit();
mtr_has_extra_clust_latch = FALSE;
@@ -2190,7 +2192,7 @@ stop_for_a_while:
plan->stored_cursor_rec_processed = FALSE;
btr_pcur_store_position(&(plan->pcur), &mtr);
- mtr_commit(&mtr);
+ mtr.commit();
ut_ad(!sync_check_iterate(sync_check()));
err = DB_SUCCESS;
@@ -2205,7 +2207,7 @@ commit_mtr_for_a_while:
btr_pcur_store_position(&(plan->pcur), &mtr);
- mtr_commit(&mtr);
+ mtr.commit();
mtr_has_extra_clust_latch = FALSE;
ut_ad(!sync_check_iterate(dict_sync_check()));
@@ -2220,7 +2222,7 @@ lock_wait_or_error:
plan->stored_cursor_rec_processed = FALSE;
btr_pcur_store_position(&(plan->pcur), &mtr);
- mtr_commit(&mtr);
+ mtr.commit();
func_exit:
ut_ad(!sync_check_iterate(dict_sync_check()));
@@ -4240,7 +4242,7 @@ row_search_mvcc(
goto func_exit;
}
- mtr_start(&mtr);
+ mtr.start();
#ifdef BTR_CUR_HASH_ADAPT
/*-------------------------------------------------------------*/
@@ -4279,7 +4281,7 @@ row_search_mvcc(
a page latch that was acquired by
row_sel_try_search_shortcut_for_mysql().
The latch will not be released until
- mtr_commit(&mtr). */
+ mtr.commit(). */
ut_ad(!rec_get_deleted_flag(rec, comp));
if (prebuilt->idx_cond) {
@@ -4316,7 +4318,8 @@ row_search_mvcc(
}
shortcut_match:
- mtr_commit(&mtr);
+ mtr.commit();
+
/* NOTE that we do NOT store the cursor
position */
err = DB_SUCCESS;
@@ -4324,7 +4327,7 @@ row_search_mvcc(
case SEL_EXHAUSTED:
shortcut_mismatch:
- mtr_commit(&mtr);
+ mtr.commit();
/* NOTE that we do NOT store the cursor
position */
err = DB_RECORD_NOT_FOUND;
@@ -4337,8 +4340,8 @@ row_search_mvcc(
ut_ad(0);
}
- mtr_commit(&mtr);
- mtr_start(&mtr);
+ mtr.commit();
+ mtr.start();
}
}
#endif /* BTR_CUR_HASH_ADAPT */
@@ -5318,7 +5321,7 @@ requires_clust_rec:
/* Decide whether to prefetch extra rows.
At this point, the clustered index record is protected
by a page latch that was acquired when pcur was positioned.
- The latch will not be released until mtr_commit(&mtr). */
+ The latch will not be released until mtr.commit(). */
if ((match_mode == ROW_SEL_EXACT
|| prebuilt->n_rows_fetched >= MYSQL_FETCH_CACHE_THRESHOLD)
@@ -5510,10 +5513,10 @@ next_rec:
btr_pcur_store_position(pcur, &mtr);
}
- mtr_commit(&mtr);
+ mtr.commit();
mtr_has_extra_clust_latch = FALSE;
- mtr_start(&mtr);
+ mtr.start();
if (!spatial_search
&& sel_restore_position_for_mysql(&same_user_rec,
@@ -5571,7 +5574,7 @@ lock_wait_or_error:
}
lock_table_wait:
- mtr_commit(&mtr);
+ mtr.commit();
mtr_has_extra_clust_latch = FALSE;
trx->error_state = err;
@@ -5588,7 +5591,7 @@ lock_table_wait:
/* It was a lock wait, and it ended */
thr->lock_state = QUE_THR_LOCK_NOLOCK;
- mtr_start(&mtr);
+ mtr.start();
/* Table lock waited, go try to obtain table lock
again */
@@ -5647,7 +5650,7 @@ normal_return:
trx->lock.n_active_thrs= n_active_thrs - 1;
}
- mtr_commit(&mtr);
+ mtr.commit();
/* Rollback blocking transactions from hit list for high priority
transaction, if any. We should not be holding latches here as
diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc
index b4aec1f3c4d..1c2a97a3210 100644
--- a/storage/innobase/row/row0umod.cc
+++ b/storage/innobase/row/row0umod.cc
@@ -624,13 +624,13 @@ row_undo_mod_del_unmark_sec_and_undo_update(
ut_ad(trx->id != 0);
- /* FIXME: Currently we do a 2-pass search for the undo due to
- avoid undel-mark a wrong rec in rolling back in partial update.
- Later, we could log some info in secondary index updates to avoid
- this. */
if (dict_index_is_spatial(index)) {
+ /* FIXME: Currently we do a 2-pass search for the undo
+ due to avoid undel-mark a wrong rec in rolling back in
+ partial update. Later, we could log some info in
+ secondary index updates to avoid this. */
ut_ad(mode & BTR_MODIFY_LEAF);
- mode |= BTR_RTREE_DELETE_MARK;
+ mode |= BTR_RTREE_DELETE_MARK;
}
try_again:
diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc
index e204059dd04..e9002d6b41d 100644
--- a/storage/innobase/row/row0upd.cc
+++ b/storage/innobase/row/row0upd.cc
@@ -319,9 +319,16 @@ row_upd_check_references_constraints(
But the counter on the table protects 'foreign' from
being dropped while the check is running. */
+ if (foreign_table) {
+ foreign_table->inc_fk_checks();
+ }
+
err = row_ins_check_foreign_constraint(
FALSE, foreign, table, entry, thr);
+ if (foreign_table) {
+ foreign_table->dec_fk_checks();
+ }
if (ref_table != NULL) {
dict_table_close(ref_table, FALSE, FALSE);
}
@@ -342,11 +349,6 @@ func_exit:
mem_heap_free(heap);
DEBUG_SYNC_C("foreign_constraint_check_for_update_done");
-
- DBUG_EXECUTE_IF("row_upd_cascade_lock_wait_err",
- err = DB_LOCK_WAIT;
- DBUG_SET("-d,row_upd_cascade_lock_wait_err"););
-
DBUG_RETURN(err);
}
@@ -469,9 +471,8 @@ wsrep_must_process_fk(const upd_node_t* node, const trx_t* trx)
return false;
}
- const upd_node_t* parent = static_cast<const upd_node_t*>(node->common.parent);
-
- return parent->cascade_upd_nodes->empty();
+ return static_cast<upd_node_t*>(node->common.parent)->cascade_node
+ == node;
}
#endif /* WITH_WSREP */
@@ -1295,7 +1296,7 @@ row_upd_index_replace_new_col_val(
}
len = dtype_get_at_most_n_mbchars(col->prtype,
- col->mbminmaxlen,
+ col->mbminlen, col->mbmaxlen,
field->prefix_len, len,
(const char*) data);
@@ -1532,12 +1533,7 @@ row_upd_replace_vcol(
dfield_copy_data(dfield, upd_field->old_v_val);
}
- dfield_get_type(dfield)->mtype =
- upd_field->new_val.type.mtype;
- dfield_get_type(dfield)->prtype =
- upd_field->new_val.type.prtype;
- dfield_get_type(dfield)->mbminmaxlen =
- upd_field->new_val.type.mbminmaxlen;
+ dfield->type = upd_field->new_val.type;
break;
}
}
@@ -2129,6 +2125,7 @@ row_upd_eval_new_vals(
@param[in] update an update vector if it is update
@param[in] thd mysql thread handle
@param[in,out] mysql_table mysql table object */
+static
void
row_upd_store_v_row(
upd_node_t* node,
@@ -2176,7 +2173,6 @@ row_upd_store_v_row(
cascade update. And virtual
column can't be affected,
so it is Ok to set it to NULL */
- ut_ad(!node->cascade_top);
dfield_set_null(dfield);
} else {
dfield_t* vfield
@@ -2271,25 +2267,6 @@ row_upd_store_row(
}
/***********************************************************//**
-Print a MBR data from disk */
-static
-void
-srv_mbr_print(const byte* data)
-{
- double a, b, c, d;
- a = mach_double_read(data);
- data += sizeof(double);
- b = mach_double_read(data);
- data += sizeof(double);
- c = mach_double_read(data);
- data += sizeof(double);
- d = mach_double_read(data);
-
- ib::info() << "GIS MBR INFO: " << a << " and " << b << ", " << c
- << ", " << d << "\n";
-}
-
-/***********************************************************//**
Updates a secondary index entry of a row.
@return DB_SUCCESS if operation successfully completed, else error
code or DB_LOCK_WAIT */
@@ -2452,8 +2429,6 @@ row_upd_sec_index_entry(
<< " of table " << index->table->name
<< " was not found on update: " << *entry
<< " at: " << rec_index_print(rec, index);
- if (entry->fields[0].data)
- srv_mbr_print((unsigned char*)entry->fields[0].data);
#ifdef UNIV_DEBUG
mtr_commit(&mtr);
mtr_start(&mtr);
@@ -2684,7 +2659,9 @@ row_upd_clust_rec_by_insert(
que_thr_t* thr, /*!< in: query thread */
ibool referenced,/*!< in: TRUE if index may be referenced in
a foreign key constraint */
- ibool foreign, /*!< in: TRUE if index is foreign key index */
+#ifdef WITH_WSREP
+ bool foreign,/*!< in: whether this is a foreign key */
+#endif
mtr_t* mtr) /*!< in/out: mtr; gets committed here */
{
mem_heap_t* heap;
@@ -2897,15 +2874,14 @@ row_upd_clust_rec(
down the index tree */
mtr->start();
- mtr->set_named_space(index->space);
- /* Disable REDO logging as lifetime of temp-tables is limited to
- server or connection lifetime and so REDO information is not needed
- on restart for recovery.
- Disable locking as temp-tables are not shared across connection. */
- if (dict_table_is_temporary(index->table)) {
+ if (index->table->is_temporary()) {
+ /* Disable locking, because temporary tables are never
+ shared between transactions or connections. */
flags |= BTR_NO_LOCKING_FLAG;
mtr->set_log_mode(MTR_LOG_NO_REDO);
+ } else {
+ mtr->set_named_space(index->space);
}
/* NOTE: this transaction has an s-lock or x-lock on the record and
@@ -2974,7 +2950,9 @@ row_upd_del_mark_clust_rec(
ibool referenced,
/*!< in: TRUE if index may be referenced in
a foreign key constraint */
- ibool foreign,/*!< in: TRUE if index is foreign key index */
+#ifdef WITH_WSREP
+ bool foreign,/*!< in: whether this is a foreign key */
+#endif
mtr_t* mtr) /*!< in: mtr; gets committed here */
{
btr_pcur_t* pcur;
@@ -3066,7 +3044,6 @@ row_upd_clust_step(
ulint* offsets;
ibool referenced;
ulint flags;
- ibool foreign = FALSE;
trx_t* trx = thr_get_trx(thr);
rec_offs_init(offsets_);
@@ -3076,8 +3053,7 @@ row_upd_clust_step(
referenced = row_upd_index_is_referenced(index, trx);
#ifdef WITH_WSREP
- foreign = wsrep_row_upd_index_is_foreign(
- index, thr_get_trx(thr));
+ const bool foreign = wsrep_row_upd_index_is_foreign(index, trx);
#endif
pcur = node->pcur;
@@ -3085,7 +3061,6 @@ row_upd_clust_step(
/* We have to restore the cursor to its position */
mtr.start();
- mtr.set_named_space(index->space);
if (dict_table_is_temporary(node->table)) {
/* Disable locking, because temporary tables are
@@ -3097,6 +3072,7 @@ row_upd_clust_step(
mtr.set_log_mode(MTR_LOG_NO_REDO);
} else {
flags = node->table->no_rollback() ? BTR_NO_ROLLBACK : 0;
+ mtr.set_named_space(index->space);
}
/* If the restoration does not succeed, then the same
@@ -3184,7 +3160,11 @@ row_upd_clust_step(
if (node->is_delete == PLAIN_DELETE) {
err = row_upd_del_mark_clust_rec(
- node, index, offsets, thr, referenced, foreign, &mtr);
+ node, index, offsets, thr, referenced,
+#ifdef WITH_WSREP
+ foreign,
+#endif
+ &mtr);
if (err == DB_SUCCESS) {
node->state = UPD_NODE_UPDATE_ALL_SEC;
@@ -3230,7 +3210,11 @@ row_upd_clust_step(
externally! */
err = row_upd_clust_rec_by_insert(
- node, index, thr, referenced, foreign, &mtr);
+ node, index, thr, referenced,
+#ifdef WITH_WSREP
+ foreign,
+#endif
+ &mtr);
if (err != DB_SUCCESS) {
goto exit_func;
@@ -3470,56 +3454,3 @@ error_handling:
DBUG_RETURN(thr);
}
-
-#ifndef DBUG_OFF
-
-/** Ensure that the member cascade_upd_nodes has only one update node
-for each of the tables. This is useful for testing purposes. */
-void upd_node_t::check_cascade_only_once()
-{
- DBUG_ENTER("upd_node_t::check_cascade_only_once");
-
- dbug_trace();
-
- for (upd_cascade_t::const_iterator i = cascade_upd_nodes->begin();
- i != cascade_upd_nodes->end(); ++i) {
-
- const upd_node_t* update_node = *i;
- std::string table_name(update_node->table->name.m_name);
- ulint count = 0;
-
- for (upd_cascade_t::const_iterator j
- = cascade_upd_nodes->begin();
- j != cascade_upd_nodes->end(); ++j) {
-
- const upd_node_t* node = *j;
-
- if (table_name == node->table->name.m_name) {
- DBUG_ASSERT(count++ == 0);
- }
- }
- }
-
- DBUG_VOID_RETURN;
-}
-
-/** Print information about this object into the trace log file. */
-void upd_node_t::dbug_trace()
-{
- DBUG_ENTER("upd_node_t::dbug_trace");
-
- for (upd_cascade_t::const_iterator i = cascade_upd_nodes->begin();
- i != cascade_upd_nodes->end(); ++i) {
- DBUG_LOG("upd_node_t", "cascade_upd_nodes: Cascade to table: "
- << (*i)->table->name);
- }
-
- for (upd_cascade_t::const_iterator j = new_upd_nodes->begin();
- j != new_upd_nodes->end(); ++j) {
- DBUG_LOG("upd_node_t", "new_upd_nodes: Cascade to table: "
- << (*j)->table->name);
- }
-
- DBUG_VOID_RETURN;
-}
-#endif /* !DBUG_OFF */
diff --git a/storage/innobase/row/row0vers.cc b/storage/innobase/row/row0vers.cc
index c5663c0c828..648643ce932 100644
--- a/storage/innobase/row/row0vers.cc
+++ b/storage/innobase/row/row0vers.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
-Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, MariaDB Corporation.
+Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2017, 2018, 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
@@ -44,25 +44,31 @@ Created 2/6/1997 Heikki Tuuri
#include "lock0lock.h"
#include "row0mysql.h"
-/** Check whether all non-virtual columns in a virtual index match that of in
-the cluster index
-@param[in,out] caller_trx trx of current thread
-@param[in] index the secondary index
-@param[in] row the cluster index row in dtuple form
-@param[in] ext externally stored column prefix or NULL
-@param[in] ientry the secondary index entry
-@param[in,out] heap heap used to build virtual dtuple
-@param[in,out] n_non_v_col number of non-virtual columns in the index
-@return true if all matches, false otherwise */
+/** Check whether all non-virtual index fields are equal.
+@param[in] index the secondary index
+@param[in] a first index entry to compare
+@param[in] b second index entry to compare
+@return whether all non-virtual fields are equal */
static
bool
-row_vers_non_vc_match(
- dict_index_t* index,
- const dtuple_t* row,
- const row_ext_t* ext,
- const dtuple_t* ientry,
- mem_heap_t* heap,
- ulint* n_non_v_col);
+row_vers_non_virtual_fields_equal(
+ const dict_index_t* index,
+ const dfield_t* a,
+ const dfield_t* b)
+{
+ const dict_field_t* end = &index->fields[index->n_fields];
+
+ for (const dict_field_t* ifield = index->fields; ifield != end;
+ ifield++) {
+ if (!dict_col_is_virtual(ifield->col)
+ && cmp_dfield_dfield(a++, b++)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
/** Determine if an active transaction has inserted or modified a secondary
index record.
@param[in,out] caller_trx trx of current thread
@@ -242,15 +248,29 @@ row_vers_impl_x_locked_low(
}
if (!cur_vrow) {
- ulint n_non_v_col = 0;
+ /* Build index entry out of row */
+ entry = row_build_index_entry(row, ext, index,
+ heap);
+
+ /* entry could only be NULL (the
+ clustered index record could contain
+ BLOB pointers that are NULL) if we
+ were accessing a freshly inserted
+ record before it was fully inserted.
+ prev_version cannot possibly be such
+ an incomplete record, because its
+ transaction would have to be committed
+ in order for later versions of the
+ record to be able to exist. */
+ ut_ad(entry);
/* If the indexed virtual columns has changed,
there must be log record to generate vrow.
Otherwise, it is not changed, so no need
to compare */
- if (row_vers_non_vc_match(
- index, row, ext, ientry, heap,
- &n_non_v_col) == 0) {
+ if (!row_vers_non_virtual_fields_equal(
+ index,
+ ientry->fields, entry->fields)) {
if (rec_del != vers_del) {
break;
}
@@ -267,12 +287,14 @@ row_vers_impl_x_locked_low(
entry = row_build_index_entry(row, ext, index, heap);
- /* entry may be NULL if a record was inserted in place
- of a deleted record, and the BLOB pointers of the new
- record were not initialized yet. But in that case,
- prev_version should be NULL. */
-
- ut_a(entry != NULL);
+ /* entry could only be NULL (the clustered index
+ record could contain BLOB pointers that are NULL) if
+ we were accessing a freshly inserted record before it
+ was fully inserted. prev_version cannot possibly be
+ such an incomplete record, because its transaction
+ would have to be committed in order for later versions
+ of the record to be able to exist. */
+ ut_ad(entry);
/* If we get here, we know that the trx_id transaction
modified prev_version. Let us check if prev_version
@@ -421,61 +443,6 @@ row_vers_must_preserve_del_marked(
return(!purge_sys->view.changes_visible(trx_id, name));
}
-/** Check whether all non-virtual columns in a virtual index match that of in
-the cluster index
-@param[in] index the secondary index
-@param[in] row the cluster index row in dtuple form
-@param[in] ext externally stored column prefix or NULL
-@param[in] ientry the secondary index entry
-@param[in,out] heap heap used to build virtual dtuple
-@param[in,out] n_non_v_col number of non-virtual columns in the index
-@return true if all matches, false otherwise */
-static
-bool
-row_vers_non_vc_match(
- dict_index_t* index,
- const dtuple_t* row,
- const row_ext_t* ext,
- const dtuple_t* ientry,
- mem_heap_t* heap,
- ulint* n_non_v_col)
-{
- const dfield_t* field1;
- dfield_t* field2;
- ulint n_fields = dtuple_get_n_fields(ientry);
- ulint ret = true;
-
- *n_non_v_col = 0;
-
- /* Build index entry out of row */
- dtuple_t* nentry = row_build_index_entry(row, ext, index, heap);
-
- for (ulint i = 0; i < n_fields; i++) {
- const dict_field_t* ind_field = dict_index_get_nth_field(
- index, i);
-
- const dict_col_t* col = ind_field->col;
-
- /* Only check non-virtual columns */
- if (dict_col_is_virtual(col)) {
- continue;
- }
-
- if (ret) {
- field1 = dtuple_get_nth_field(ientry, i);
- field2 = dtuple_get_nth_field(nentry, i);
-
- if (cmp_dfield_dfield(field1, field2) != 0) {
- ret = false;
- }
- }
-
- (*n_non_v_col)++;
- }
-
- return(ret);
-}
-
/** build virtual column value from current cluster index record data
@param[in,out] row the cluster index row in dtuple form
@param[in] clust_index clustered index
@@ -626,8 +593,7 @@ that of current cluster index record, which is recreated from information
stored in undo log
@param[in] in_purge called by purge thread
@param[in] rec record in the clustered index
-@param[in] row the cluster index row in dtuple form
-@param[in] ext externally stored column prefix or NULL
+@param[in] icentry the index entry built from a cluster row
@param[in] clust_index cluster index
@param[in] clust_offsets offsets on the cluster record
@param[in] index the secondary index
@@ -643,8 +609,7 @@ bool
row_vers_vc_matches_cluster(
bool in_purge,
const rec_t* rec,
- const dtuple_t* row,
- row_ext_t* ext,
+ const dtuple_t* icentry,
dict_index_t* clust_index,
ulint* clust_offsets,
dict_index_t* index,
@@ -669,15 +634,27 @@ row_vers_vc_matches_cluster(
dfield_t* field2;
ulint i;
- tuple_heap = mem_heap_create(1024);
-
/* First compare non-virtual columns (primary keys) */
- if (!row_vers_non_vc_match(index, row, ext, ientry, tuple_heap,
- &n_non_v_col)) {
- mem_heap_free(tuple_heap);
- return(false);
+ ut_ad(index->n_fields == n_fields);
+ ut_ad(n_fields == dtuple_get_n_fields(icentry));
+ {
+ const dfield_t* a = ientry->fields;
+ const dfield_t* b = icentry->fields;
+
+ for (const dict_field_t *ifield = index->fields,
+ *const end = &index->fields[index->n_fields];
+ ifield != end; ifield++, a++, b++) {
+ if (!dict_col_is_virtual(ifield->col)) {
+ if (cmp_dfield_dfield(a, b)) {
+ return false;
+ }
+ n_non_v_col++;
+ }
+ }
}
+ tuple_heap = mem_heap_create(1024);
+
ut_ad(n_fields > n_non_v_col);
*vrow = dtuple_create_with_vcol(v_heap ? v_heap : tuple_heap, 0, num_v);
@@ -946,27 +923,28 @@ row_vers_old_has_index_entry(
entry = row_build_index_entry(
row, ext, index, heap);
if (entry && !dtuple_coll_cmp(ientry, entry)) {
-
- mem_heap_free(heap);
-
- if (v_heap) {
- mem_heap_free(v_heap);
- }
-
- return(TRUE);
+ goto safe_to_purge;
}
} else {
- if (row_vers_vc_matches_cluster(
- also_curr, rec, row, ext, clust_index,
- clust_offsets, index, ientry, roll_ptr,
- trx_id, NULL, &vrow, mtr)) {
- mem_heap_free(heap);
-
- if (v_heap) {
- mem_heap_free(v_heap);
- }
-
- return(TRUE);
+ /* Build index entry out of row */
+ entry = row_build_index_entry(row, ext, index, heap);
+ /* entry could only be NULL if
+ the clustered index record is an uncommitted
+ inserted record whose BLOBs have not been
+ written yet. The secondary index record
+ can be safely removed, because it cannot
+ possibly refer to this incomplete
+ clustered index record. (Insert would
+ always first be completed for the
+ clustered index record, then proceed to
+ secondary indexes.) */
+
+ if (entry && row_vers_vc_matches_cluster(
+ also_curr, rec, entry,
+ clust_index, clust_offsets,
+ index, ientry, roll_ptr,
+ trx_id, NULL, &vrow, mtr)) {
+ goto safe_to_purge;
}
}
clust_offsets = rec_get_offsets(rec, clust_index, NULL,
@@ -999,7 +977,7 @@ row_vers_old_has_index_entry(
a different binary value in a char field, but the
collation identifies the old and new value anyway! */
if (entry && !dtuple_coll_cmp(ientry, entry)) {
-
+safe_to_purge:
mem_heap_free(heap);
if (v_heap) {
@@ -1096,13 +1074,7 @@ row_vers_old_has_index_entry(
and new value anyway! */
if (entry && !dtuple_coll_cmp(ientry, entry)) {
-
- mem_heap_free(heap);
- if (v_heap) {
- mem_heap_free(v_heap);
- }
-
- return(TRUE);
+ goto safe_to_purge;
}
}