diff options
Diffstat (limited to 'storage/innobase/row/row0ins.cc')
-rw-r--r-- | storage/innobase/row/row0ins.cc | 175 |
1 files changed, 105 insertions, 70 deletions
diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index cdd12a10cf7..75a7238c1df 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -877,16 +877,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; @@ -895,10 +894,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; @@ -910,20 +906,16 @@ row_ins_foreign_fill_virtual( &ext, cascade->heap); n_diff = update->n_fields; - update->n_fields += n_v_fld; - if (index->table->vc_templ == NULL) { /** This can occur when there is a cascading delete or update after restart. */ 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 (uint16_t i = 0; i < n_v_fld; i++) { @@ -939,15 +931,14 @@ 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); + upd_field = update->fields + n_diff; upd_field->old_v_val = static_cast<dfield_t*>( mem_heap_alloc(cascade->heap, @@ -957,42 +948,31 @@ row_ins_foreign_fill_virtual( upd_field_set_v_field_no(upd_field, i, index); - if (node->is_delete - ? (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) - : (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL)) { - - dfield_set_null(&upd_field->new_val); - } - - if (!node->is_delete - && (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE)) { - - dfield_t* new_vfield = innobase_get_computed_value( - update->old_vrow, col, index, - &v_heap, update->heap, NULL, thd, - mysql_table, record, NULL, - node->update, foreign); + bool set_null = + node->is_delete + ? (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) + : (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL); - if (new_vfield == NULL) { - *err = DB_COMPUTE_VALUE_FAILED; - goto func_exit; - } + dfield_t* new_vfield = innobase_get_computed_value( + update->old_vrow, col, index, + &vc.heap, update->heap, NULL, thd, + mysql_table, record, NULL, + set_null ? update : node->update, foreign); - dfield_copy(&(upd_field->new_val), new_vfield); + if (new_vfield == NULL) { + return DB_COMPUTE_VALUE_FAILED; } - n_diff++; + dfield_copy(&upd_field->new_val, new_vfield); + + if (!dfield_datas_are_binary_equal( + upd_field->old_v_val, + &upd_field->new_val, 0)) + n_diff++; } 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 @@ -1279,9 +1259,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; @@ -1317,9 +1297,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; @@ -1377,21 +1357,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_SERVICE_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_SERVICE_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); @@ -1911,6 +1890,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, @@ -1929,9 +1941,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); @@ -1941,13 +1954,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; @@ -1975,7 +2011,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(); @@ -1988,15 +2024,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; } /***************************************************************//** |