diff options
Diffstat (limited to 'storage')
-rw-r--r-- | storage/innodb_plugin/ChangeLog | 10 | ||||
-rw-r--r-- | storage/innodb_plugin/btr/btr0cur.c | 3 | ||||
-rw-r--r-- | storage/innodb_plugin/include/data0data.h | 11 | ||||
-rw-r--r-- | storage/innodb_plugin/include/data0data.ic | 22 | ||||
-rw-r--r-- | storage/innodb_plugin/include/row0upd.h | 5 | ||||
-rw-r--r-- | storage/innodb_plugin/row/row0purge.c | 2 | ||||
-rw-r--r-- | storage/innodb_plugin/row/row0umod.c | 4 | ||||
-rw-r--r-- | storage/innodb_plugin/row/row0upd.c | 93 |
8 files changed, 110 insertions, 40 deletions
diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 347dc9a5183..13e2836dc98 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,8 +1,18 @@ +2010-12-21 The InnoDB Team + + * include/data0data.h, include/data0data.ic, include/row0upd.h, + btr/btr0cur.c, row/row0purge.c, row/row0umod.c, row/row0upd.c, + innodb.result, innodb.test: + Fix Bug#58912 InnoDB unnecessarily avoids update-in-place + on column prefix indexes + 2010-12-09 The InnoDB Team + * buf/buf0lru.c: Fix Bug#57600 output of I/O sum[%lu] can go negative 2010-11-11 The InnoDB Team + * thr/thr0loc.c, trx/trx0i_s.c: Fix Bug#57802 Empty ASSERTION parameter passed to the HASH_SEARCH macro diff --git a/storage/innodb_plugin/btr/btr0cur.c b/storage/innodb_plugin/btr/btr0cur.c index f9f0d156f52..2a26d8ffb33 100644 --- a/storage/innodb_plugin/btr/btr0cur.c +++ b/storage/innodb_plugin/btr/btr0cur.c @@ -1756,7 +1756,8 @@ btr_cur_update_in_place( NOT call it if index is secondary */ if (!dict_index_is_clust(index) - || row_upd_changes_ord_field_binary(NULL, index, update)) { + || row_upd_changes_ord_field_binary(NULL, NULL, + index, update)) { /* Remove possible hash index pointer to this record */ btr_search_update_hash_on_delete(cursor); diff --git a/storage/innodb_plugin/include/data0data.h b/storage/innodb_plugin/include/data0data.h index f9fce3f3657..cab8d790ac1 100644 --- a/storage/innodb_plugin/include/data0data.h +++ b/storage/innodb_plugin/include/data0data.h @@ -154,14 +154,19 @@ dfield_dup( dfield_t* field, /*!< in/out: data field */ mem_heap_t* heap); /*!< in: memory heap where allocated */ /*********************************************************************//** -Tests if data length and content is equal for two dfields. -@return TRUE if equal */ +Tests if two data fields are equal. +If len==0, tests the data length and content for equality. +If len>0, tests the first len bytes of the content for equality. +@return TRUE if both fields are NULL or if they are equal */ UNIV_INLINE ibool dfield_datas_are_binary_equal( /*==========================*/ const dfield_t* field1, /*!< in: field */ - const dfield_t* field2);/*!< in: field */ + const dfield_t* field2, /*!< in: field */ + ulint len) /*!< in: maximum prefix to compare, + or 0 to compare the whole field length */ + __attribute__((nonnull, warn_unused_result)); /*********************************************************************//** Tests if dfield data length and content is equal to the given. @return TRUE if equal */ diff --git a/storage/innodb_plugin/include/data0data.ic b/storage/innodb_plugin/include/data0data.ic index da79aa33702..74e0f7d09a0 100644 --- a/storage/innodb_plugin/include/data0data.ic +++ b/storage/innodb_plugin/include/data0data.ic @@ -229,20 +229,30 @@ dfield_dup( } /*********************************************************************//** -Tests if data length and content is equal for two dfields. -@return TRUE if equal */ +Tests if two data fields are equal. +If len==0, tests the data length and content for equality. +If len>0, tests the first len bytes of the content for equality. +@return TRUE if both fields are NULL or if they are equal */ UNIV_INLINE ibool dfield_datas_are_binary_equal( /*==========================*/ const dfield_t* field1, /*!< in: field */ - const dfield_t* field2) /*!< in: field */ + const dfield_t* field2, /*!< in: field */ + ulint len) /*!< in: maximum prefix to compare, + or 0 to compare the whole field length */ { - ulint len; + ulint len2 = len; - len = field1->len; + if (field1->len == UNIV_SQL_NULL || len == 0 || field1->len < len) { + len = field1->len; + } + + if (field2->len == UNIV_SQL_NULL || len2 == 0 || field2->len < len2) { + len2 = field2->len; + } - return(len == field2->len + return(len == len2 && (len == UNIV_SQL_NULL || !memcmp(field1->data, field2->data, len))); } diff --git a/storage/innodb_plugin/include/row0upd.h b/storage/innodb_plugin/include/row0upd.h index ea14cd64213..58d7ad15ecc 100644 --- a/storage/innodb_plugin/include/row0upd.h +++ b/storage/innodb_plugin/include/row0upd.h @@ -286,10 +286,13 @@ row_upd_changes_ord_field_binary( row and the data values in update are not known when this function is called, e.g., at compile time */ + const row_ext_t*ext, /*!< NULL, or prefixes of the externally + stored columns in the old row */ dict_index_t* index, /*!< in: index of the record */ - const upd_t* update);/*!< in: update vector for the row; NOTE: the + const upd_t* update) /*!< in: update vector for the row; NOTE: the field numbers in this MUST be clustered index positions! */ + __attribute__((nonnull(3,4), warn_unused_result)); /***********************************************************//** Checks if an update vector changes an ordering field of an index record. This function is fast if the update vector is short or the number of ordering diff --git a/storage/innodb_plugin/row/row0purge.c b/storage/innodb_plugin/row/row0purge.c index 31b255cf2d4..8bf2ae0f458 100644 --- a/storage/innodb_plugin/row/row0purge.c +++ b/storage/innodb_plugin/row/row0purge.c @@ -413,7 +413,7 @@ row_purge_upd_exist_or_extern( while (node->index != NULL) { index = node->index; - if (row_upd_changes_ord_field_binary(NULL, node->index, + if (row_upd_changes_ord_field_binary(NULL, NULL, node->index, node->update)) { /* Build the older version of the index entry */ entry = row_build_index_entry(node->row, NULL, diff --git a/storage/innodb_plugin/row/row0umod.c b/storage/innodb_plugin/row/row0umod.c index 5998dadd16d..49c51a75f18 100644 --- a/storage/innodb_plugin/row/row0umod.c +++ b/storage/innodb_plugin/row/row0umod.c @@ -668,8 +668,8 @@ row_undo_mod_upd_exist_sec( while (node->index != NULL) { index = node->index; - if (row_upd_changes_ord_field_binary(node->row, node->index, - node->update)) { + if (row_upd_changes_ord_field_binary( + node->row, node->ext, node->index, node->update)) { /* Build the newest version of the index entry */ entry = row_build_index_entry(node->row, node->ext, diff --git a/storage/innodb_plugin/row/row0upd.c b/storage/innodb_plugin/row/row0upd.c index 0dc550b93f5..20f31e15514 100644 --- a/storage/innodb_plugin/row/row0upd.c +++ b/storage/innodb_plugin/row/row0upd.c @@ -1198,20 +1198,21 @@ row_upd_changes_ord_field_binary( row and the data values in update are not known when this function is called, e.g., at compile time */ + const row_ext_t*ext, /*!< NULL, or prefixes of the externally + stored columns in the old row */ dict_index_t* index, /*!< in: index of the record */ const upd_t* update) /*!< in: update vector for the row; NOTE: the field numbers in this MUST be clustered index positions! */ { - ulint n_unique; - ulint n_upd_fields; - ulint i, j; - dict_index_t* clust_index; + ulint n_unique; + ulint i; + const dict_index_t* clust_index; - ut_ad(update && index); + ut_ad(update); + ut_ad(index); n_unique = dict_index_get_n_unique(index); - n_upd_fields = upd_get_n_fields(update); clust_index = dict_table_get_first_index(index->table); @@ -1219,33 +1220,72 @@ row_upd_changes_ord_field_binary( const dict_field_t* ind_field; const dict_col_t* col; - ulint col_pos; ulint col_no; + const upd_field_t* upd_field; + const dfield_t* dfield; + dfield_t dfield_ext; + ulint dfield_len; + const byte* buf; ind_field = dict_index_get_nth_field(index, i); col = dict_field_get_col(ind_field); - col_pos = dict_col_get_clust_pos(col, clust_index); col_no = dict_col_get_no(col); - for (j = 0; j < n_upd_fields; j++) { + upd_field = upd_get_field_by_field_no( + update, dict_col_get_clust_pos(col, clust_index)); - const upd_field_t* upd_field - = upd_get_nth_field(update, j); + if (upd_field == NULL) { + continue; + } - /* Note that if the index field is a column prefix - then it may be that row does not contain an externally - stored part of the column value, and we cannot compare - the datas */ + if (row == NULL) { + ut_ad(ext == NULL); + return(TRUE); + } - if (col_pos == upd_field->field_no - && (row == NULL - || ind_field->prefix_len > 0 - || !dfield_datas_are_binary_equal( - dtuple_get_nth_field(row, col_no), - &(upd_field->new_val)))) { + dfield = dtuple_get_nth_field(row, col_no); - return(TRUE); + /* This treatment of column prefix indexes is loosely + based on row_build_index_entry(). */ + + if (UNIV_LIKELY(ind_field->prefix_len == 0) + || dfield_is_null(dfield)) { + /* do nothing special */ + } else if (UNIV_LIKELY_NULL(ext)) { + /* See if the column is stored externally. */ + buf = row_ext_lookup(ext, col_no, &dfield_len); + + ut_ad(col->ord_part); + + if (UNIV_LIKELY_NULL(buf)) { + if (UNIV_UNLIKELY(buf == field_ref_zero)) { + /* This should never happen, but + we try to fail safe here. */ + ut_ad(0); + return(TRUE); + } + + goto copy_dfield; } + } else if (dfield_is_ext(dfield)) { + dfield_len = dfield_get_len(dfield); + ut_a(dfield_len > BTR_EXTERN_FIELD_REF_SIZE); + dfield_len -= BTR_EXTERN_FIELD_REF_SIZE; + ut_a(dict_index_is_clust(index) + || ind_field->prefix_len <= dfield_len); + buf = dfield_get_data(dfield); +copy_dfield: + ut_a(dfield_len > 0); + dfield_copy(&dfield_ext, dfield); + dfield_set_data(&dfield_ext, buf, dfield_len); + dfield = &dfield_ext; + } + + if (!dfield_datas_are_binary_equal( + dfield, &upd_field->new_val, + ind_field->prefix_len)) { + + return(TRUE); } } @@ -1329,7 +1369,7 @@ row_upd_changes_first_fields_binary( if (col_pos == upd_field->field_no && !dfield_datas_are_binary_equal( dtuple_get_nth_field(entry, i), - &(upd_field->new_val))) { + &upd_field->new_val, 0)) { return(TRUE); } @@ -1568,8 +1608,8 @@ row_upd_sec_step( ut_ad(!dict_index_is_clust(node->index)); if (node->state == UPD_NODE_UPDATE_ALL_SEC - || row_upd_changes_ord_field_binary(node->row, node->index, - node->update)) { + || row_upd_changes_ord_field_binary(node->row, node->ext, + node->index, node->update)) { return(row_upd_sec_index_entry(node, thr)); } @@ -1973,7 +2013,8 @@ exit_func: row_upd_store_row(node); - if (row_upd_changes_ord_field_binary(node->row, index, node->update)) { + if (row_upd_changes_ord_field_binary(node->row, node->ext, index, + node->update)) { /* Update causes an ordering field (ordering fields within the B-tree) of the clustered index record to change: perform |