diff options
Diffstat (limited to 'storage/innobase')
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 117 | ||||
-rw-r--r-- | storage/innobase/include/rem0rec.h | 8 | ||||
-rw-r--r-- | storage/innobase/include/row0mysql.h | 42 | ||||
-rw-r--r-- | storage/innobase/os/os0proc.cc | 1 | ||||
-rw-r--r-- | storage/innobase/row/row0ins.cc | 137 | ||||
-rw-r--r-- | storage/innobase/row/row0merge.cc | 52 | ||||
-rw-r--r-- | storage/innobase/row/row0sel.cc | 123 | ||||
-rw-r--r-- | storage/innobase/row/row0upd.cc | 83 | ||||
-rw-r--r-- | storage/innobase/row/row0vers.cc | 47 |
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; } |