summaryrefslogtreecommitdiff
path: root/innobase/row
diff options
context:
space:
mode:
Diffstat (limited to 'innobase/row')
-rw-r--r--innobase/row/row0ins.c231
-rw-r--r--innobase/row/row0mysql.c89
-rw-r--r--innobase/row/row0purge.c16
-rw-r--r--innobase/row/row0row.c112
-rw-r--r--innobase/row/row0sel.c490
-rw-r--r--innobase/row/row0umod.c2
-rw-r--r--innobase/row/row0undo.c13
-rw-r--r--innobase/row/row0upd.c166
-rw-r--r--innobase/row/row0vers.c117
9 files changed, 824 insertions, 412 deletions
diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c
index f8a98f74c09..4650db7abad 100644
--- a/innobase/row/row0ins.c
+++ b/innobase/row/row0ins.c
@@ -251,7 +251,7 @@ row_ins_sec_index_entry_by_modify(
rec = btr_cur_get_rec(cursor);
ut_ad((cursor->index->type & DICT_CLUSTERED) == 0);
- ut_ad(rec_get_deleted_flag(rec));
+ ut_ad(rec_get_deleted_flag(rec, cursor->index->table->comp));
/* We know that in the alphabetical ordering, entry and rec are
identified. But in their binary form there may be differences if
@@ -316,7 +316,7 @@ row_ins_clust_index_entry_by_modify(
rec = btr_cur_get_rec(cursor);
- ut_ad(rec_get_deleted_flag(rec));
+ ut_ad(rec_get_deleted_flag(rec, cursor->index->table->comp));
heap = mem_heap_create(1024);
@@ -473,6 +473,8 @@ row_ins_cascade_calc_update_vec(
if (parent_ufield->field_no == parent_field_no) {
+ ulint fixed_size;
+
/* A field in the parent index record is
updated. Let us make the update vector
field for the child table. */
@@ -512,22 +514,22 @@ row_ins_cascade_calc_update_vec(
need to pad with spaces the new value of the
child column */
- if (dtype_is_fixed_size(type)
+ fixed_size = dtype_get_fixed_size(type);
+
+ if (fixed_size
&& ufield->new_val.len != UNIV_SQL_NULL
- && ufield->new_val.len
- < dtype_get_fixed_size(type)) {
+ && ufield->new_val.len < fixed_size) {
ufield->new_val.data =
mem_heap_alloc(heap,
- dtype_get_fixed_size(type));
- ufield->new_val.len =
- dtype_get_fixed_size(type);
+ fixed_size);
+ ufield->new_val.len = fixed_size;
ut_a(dtype_get_pad_char(type)
!= ULINT_UNDEFINED);
memset(ufield->new_val.data,
(byte)dtype_get_pad_char(type),
- dtype_get_fixed_size(type));
+ fixed_size);
ut_memcpy(ufield->new_val.data,
parent_ufield->new_val.data,
parent_ufield->new_val.len);
@@ -589,7 +591,7 @@ row_ins_foreign_report_err(
ut_print_name(ef, trx, foreign->foreign_index->name);
if (rec) {
fputs(", there is a record:\n", ef);
- rec_print(ef, rec);
+ rec_print(ef, rec, foreign->foreign_index);
} else {
fputs(", the record is not available\n", ef);
}
@@ -644,7 +646,7 @@ row_ins_foreign_report_add_err(
}
if (rec) {
- rec_print(ef, rec);
+ rec_print(ef, rec, foreign->foreign_index);
}
putc('\n', ef);
@@ -706,7 +708,6 @@ row_ins_foreign_check_on_constraint(
dict_index_t* index;
dict_index_t* clust_index;
dtuple_t* ref;
- mem_heap_t* tmp_heap;
mem_heap_t* upd_vec_heap = NULL;
rec_t* rec;
rec_t* clust_rec;
@@ -715,14 +716,17 @@ row_ins_foreign_check_on_constraint(
ulint err;
ulint i;
trx_t* trx;
+ mem_heap_t* tmp_heap = NULL;
-
ut_a(thr && foreign && pcur && mtr);
trx = thr_get_trx(thr);
/* Since we are going to delete or update a row, we have to invalidate
- the MySQL query cache for table */
+ the MySQL query cache for table. A deadlock of threads is not possible
+ here because the caller of this function does not hold any latches with
+ the sync0sync.h rank above the kernel mutex. The query cache mutex has
+ a rank just above the kernel mutex. */
row_ins_invalidate_query_cache(thr, table->name);
@@ -816,7 +820,7 @@ row_ins_foreign_check_on_constraint(
err = DB_ROW_IS_REFERENCED;
row_ins_foreign_report_err(
-(char*)"Trying a too deep cascaded delete or update\n",
+"Trying a too deep cascaded delete or update\n",
thr, foreign, btr_pcur_get_rec(pcur), entry);
goto nonstandard_exit_func;
@@ -848,8 +852,6 @@ row_ins_foreign_check_on_constraint(
PAGE_CUR_LE, BTR_SEARCH_LEAF,
cascade->pcur, 0, mtr);
- mem_heap_free(tmp_heap);
-
clust_rec = btr_pcur_get_rec(cascade->pcur);
if (!page_rec_is_user_rec(clust_rec)
@@ -863,10 +865,10 @@ row_ins_foreign_check_on_constraint(
fputs("\n"
"InnoDB: record ", stderr);
- rec_print(stderr, rec);
+ rec_print(stderr, rec, index);
fputs("\n"
"InnoDB: clustered record ", stderr);
- rec_print(stderr, clust_rec);
+ rec_print(stderr, clust_rec, clust_index);
fputs("\n"
"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n", stderr);
@@ -884,9 +886,9 @@ row_ins_foreign_check_on_constraint(
/* Here it suffices to use a LOCK_REC_NOT_GAP type lock;
we already have a normal shared lock on the appropriate
gap if the search criterion was not unique */
-
- err = lock_clust_rec_read_check_and_lock(0, clust_rec,
- clust_index, LOCK_X, LOCK_REC_NOT_GAP, thr);
+
+ err = lock_clust_rec_read_check_and_lock_alt(0, clust_rec,
+ clust_index, LOCK_X, LOCK_REC_NOT_GAP, thr);
}
if (err != DB_SUCCESS) {
@@ -894,7 +896,7 @@ row_ins_foreign_check_on_constraint(
goto nonstandard_exit_func;
}
- if (rec_get_deleted_flag(clust_rec)) {
+ if (rec_get_deleted_flag(clust_rec, table->comp)) {
/* This can happen if there is a circular reference of
rows such that cascading delete comes to delete a row
already in the process of being delete marked */
@@ -1003,6 +1005,10 @@ row_ins_foreign_check_on_constraint(
btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, mtr);
+ if (tmp_heap) {
+ mem_heap_free(tmp_heap);
+ }
+
if (upd_vec_heap) {
mem_heap_free(upd_vec_heap);
}
@@ -1010,6 +1016,9 @@ row_ins_foreign_check_on_constraint(
return(err);
nonstandard_exit_func:
+ if (tmp_heap) {
+ mem_heap_free(tmp_heap);
+ }
if (upd_vec_heap) {
mem_heap_free(upd_vec_heap);
@@ -1037,16 +1046,19 @@ row_ins_set_shared_rec_lock(
LOCK_REC_NOT_GAP type lock */
rec_t* rec, /* in: record */
dict_index_t* index, /* in: index */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
que_thr_t* thr) /* in: query thread */
{
ulint err;
+ ut_ad(rec_offs_validate(rec, index, offsets));
+
if (index->type & DICT_CLUSTERED) {
- err = lock_clust_rec_read_check_and_lock(0, rec, index, LOCK_S,
- type, thr);
+ err = lock_clust_rec_read_check_and_lock(0,
+ rec, index, offsets, LOCK_S, type, thr);
} else {
- err = lock_sec_rec_read_check_and_lock(0, rec, index, LOCK_S,
- type, thr);
+ err = lock_sec_rec_read_check_and_lock(0,
+ rec, index, offsets, LOCK_S, type, thr);
}
return(err);
@@ -1064,16 +1076,19 @@ row_ins_set_exclusive_rec_lock(
LOCK_REC_NOT_GAP type lock */
rec_t* rec, /* in: record */
dict_index_t* index, /* in: index */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
que_thr_t* thr) /* in: query thread */
{
ulint err;
+ ut_ad(rec_offs_validate(rec, index, offsets));
+
if (index->type & DICT_CLUSTERED) {
- err = lock_clust_rec_read_check_and_lock(0, rec, index, LOCK_X,
- type, thr);
+ err = lock_clust_rec_read_check_and_lock(0,
+ rec, index, offsets, LOCK_X, type, thr);
} else {
- err = lock_sec_rec_read_check_and_lock(0, rec, index, LOCK_X,
- type, thr);
+ err = lock_sec_rec_read_check_and_lock(0,
+ rec, index, offsets, LOCK_X, type, thr);
}
return(err);
@@ -1113,7 +1128,10 @@ row_ins_check_foreign_constraint(
ulint err;
ulint i;
mtr_t mtr;
- trx_t* trx = thr_get_trx(thr);
+ trx_t* trx = thr_get_trx(thr);
+ mem_heap_t* heap = NULL;
+ ulint offsets_[100] = { 100, };
+ ulint* offsets = offsets_;
run_again:
#ifdef UNIV_SYNC_DEBUG
@@ -1125,8 +1143,7 @@ run_again:
if (trx->check_foreigns == FALSE) {
/* The user has suppressed foreign key checks currently for
this session */
-
- return(DB_SUCCESS);
+ goto exit_func;
}
/* If any of the foreign key fields in entry is SQL NULL, we
@@ -1137,7 +1154,7 @@ run_again:
if (UNIV_SQL_NULL == dfield_get_len(
dtuple_get_nth_field(entry, i))) {
- return(DB_SUCCESS);
+ goto exit_func;
}
}
@@ -1160,8 +1177,8 @@ run_again:
with each foreign key constraint, one after
another, and the user has problems predicting in
which order they are performed. */
-
- return(DB_SUCCESS);
+
+ goto exit_func;
}
}
@@ -1195,10 +1212,10 @@ run_again:
fputs("\nor its .ibd file does not currently exist!\n", ef);
mutex_exit(&dict_foreign_err_mutex);
- return(DB_NO_REFERENCED_ROW);
+ err = DB_NO_REFERENCED_ROW;
}
- return(DB_SUCCESS);
+ goto exit_func;
}
ut_a(check_table && check_index);
@@ -1244,10 +1261,13 @@ run_again:
goto next_rec;
}
+ offsets = rec_get_offsets(rec, check_index,
+ offsets, ULINT_UNDEFINED, &heap);
+
if (rec == page_get_supremum_rec(buf_frame_align(rec))) {
-
+
err = row_ins_set_shared_rec_lock(LOCK_ORDINARY, rec,
- check_index, thr);
+ check_index, offsets, thr);
if (err != DB_SUCCESS) {
break;
@@ -1256,29 +1276,30 @@ run_again:
goto next_rec;
}
- cmp = cmp_dtuple_rec(entry, rec);
+ cmp = cmp_dtuple_rec(entry, rec, offsets);
if (cmp == 0) {
- if (rec_get_deleted_flag(rec)) {
+ if (rec_get_deleted_flag(rec,
+ rec_offs_comp(offsets))) {
err = row_ins_set_shared_rec_lock(
- LOCK_ORDINARY,
- rec, check_index, thr);
+ LOCK_ORDINARY, rec,
+ check_index, offsets, thr);
if (err != DB_SUCCESS) {
break;
}
} else {
/* Found a matching record */
+ ulint lock_type;
if (unique_search) {
- err = row_ins_set_shared_rec_lock(
- LOCK_REC_NOT_GAP,
- rec, check_index, thr);
+ lock_type = LOCK_REC_NOT_GAP;
} else {
- err = row_ins_set_shared_rec_lock(
- LOCK_ORDINARY,
- rec, check_index, thr);
+ lock_type = LOCK_ORDINARY;
}
+
+ err = row_ins_set_shared_rec_lock(lock_type,
+ rec, check_index, offsets, thr);
if (err != DB_SUCCESS) {
@@ -1315,7 +1336,7 @@ run_again:
if (cmp < 0) {
err = row_ins_set_shared_rec_lock(LOCK_GAP,
- rec, check_index, thr);
+ rec, check_index, offsets, thr);
if (err != DB_SUCCESS) {
break;
@@ -1373,6 +1394,10 @@ do_possible_lock_wait:
err = trx->error_state;
}
+exit_func:
+ if (heap) {
+ mem_heap_free(heap);
+ }
return(err);
}
@@ -1470,19 +1495,23 @@ row_ins_dupl_error_with_rec(
that the caller already has a record lock on
the record! */
dtuple_t* entry, /* in: entry to insert */
- dict_index_t* index) /* in: index */
+ dict_index_t* index, /* in: index */
+ const ulint* offsets)/* in: rec_get_offsets(rec, index) */
{
ulint matched_fields;
ulint matched_bytes;
ulint n_unique;
ulint i;
-
+
+ ut_ad(rec_offs_validate(rec, index, offsets));
+
n_unique = dict_index_get_n_unique(index);
matched_fields = 0;
matched_bytes = 0;
- cmp_dtuple_rec_with_match(entry, rec, &matched_fields, &matched_bytes);
+ cmp_dtuple_rec_with_match(entry, rec, offsets,
+ &matched_fields, &matched_bytes);
if (matched_fields < n_unique) {
@@ -1503,7 +1532,7 @@ row_ins_dupl_error_with_rec(
}
}
- if (!rec_get_deleted_flag(rec)) {
+ if (!rec_get_deleted_flag(rec, index->table->comp)) {
return(TRUE);
}
@@ -1535,7 +1564,10 @@ row_ins_scan_sec_index_for_duplicate(
ibool moved;
mtr_t mtr;
trx_t* trx;
-
+ mem_heap_t* heap = NULL;
+ ulint offsets_[100] = { 100, };
+ ulint* offsets = offsets_;
+
n_unique = dict_index_get_n_unique(index);
/* If the secondary index is unique, but one of the fields in the
@@ -1575,6 +1607,9 @@ row_ins_scan_sec_index_for_duplicate(
trx = thr_get_trx(thr);
ut_ad(trx);
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+
if (innobase_query_is_replace()) {
/* The manual defines the REPLACE semantics that it
@@ -1582,12 +1617,12 @@ row_ins_scan_sec_index_for_duplicate(
+ INSERT. Therefore, we should take X-lock for
duplicates */
- err = row_ins_set_exclusive_rec_lock(
- LOCK_ORDINARY,rec,index,thr);
+ err = row_ins_set_exclusive_rec_lock(LOCK_ORDINARY,
+ rec, index, offsets, thr);
} else {
- err = row_ins_set_shared_rec_lock(
- LOCK_ORDINARY, rec, index,thr);
+ err = row_ins_set_shared_rec_lock(LOCK_ORDINARY,
+ rec, index, offsets, thr);
}
if (err != DB_SUCCESS) {
@@ -1600,10 +1635,11 @@ row_ins_scan_sec_index_for_duplicate(
goto next_rec;
}
- cmp = cmp_dtuple_rec(entry, rec);
+ cmp = cmp_dtuple_rec(entry, rec, offsets);
if (cmp == 0) {
- if (row_ins_dupl_error_with_rec(rec, entry, index)) {
+ if (row_ins_dupl_error_with_rec(rec, entry,
+ index, offsets)) {
err = DB_DUPLICATE_KEY;
thr_get_trx(thr)->error_info = index;
@@ -1625,6 +1661,9 @@ next_rec:
}
}
+ if (heap) {
+ mem_heap_free(heap);
+ }
mtr_commit(&mtr);
/* Restore old value */
@@ -1654,7 +1693,11 @@ row_ins_duplicate_error_in_clust(
rec_t* rec;
page_t* page;
ulint n_unique;
- trx_t* trx = thr_get_trx(thr);
+ trx_t* trx = thr_get_trx(thr);
+ mem_heap_t*heap = NULL;
+ ulint offsets_[100] = { 100, };
+ ulint* offsets = offsets_;
+
UT_NOT_USED(mtr);
@@ -1682,6 +1725,8 @@ row_ins_duplicate_error_in_clust(
page = buf_frame_align(rec);
if (rec != page_get_infimum_rec(page)) {
+ offsets = rec_get_offsets(rec, cursor->index, offsets,
+ ULINT_UNDEFINED, &heap);
/* We set a lock on the possible duplicate: this
is needed in logical logging of MySQL to make
@@ -1697,23 +1742,23 @@ row_ins_duplicate_error_in_clust(
err = row_ins_set_exclusive_rec_lock(
LOCK_REC_NOT_GAP,rec,cursor->index,
- thr);
+ offsets, thr);
} else {
err = row_ins_set_shared_rec_lock(
LOCK_REC_NOT_GAP,rec, cursor->index,
- thr);
+ offsets, thr);
}
if (err != DB_SUCCESS) {
-
- return(err);
+ goto func_exit;
}
if (row_ins_dupl_error_with_rec(rec, entry,
- cursor->index)) {
+ cursor->index, offsets)) {
trx->error_info = cursor->index;
- return(DB_DUPLICATE_KEY);
+ err = DB_DUPLICATE_KEY;
+ goto func_exit;
}
}
}
@@ -1724,7 +1769,8 @@ row_ins_duplicate_error_in_clust(
page = buf_frame_align(rec);
if (rec != page_get_supremum_rec(page)) {
-
+ offsets = rec_get_offsets(rec, cursor->index, offsets,
+ ULINT_UNDEFINED, &heap);
/* The manual defines the REPLACE semantics that it
is either an INSERT or DELETE(s) for duplicate key
@@ -1734,32 +1780,35 @@ row_ins_duplicate_error_in_clust(
if (innobase_query_is_replace()) {
err = row_ins_set_exclusive_rec_lock(
- LOCK_REC_NOT_GAP,
- rec,cursor->index,thr);
+ LOCK_REC_NOT_GAP, rec,
+ cursor->index, offsets, thr);
} else {
err = row_ins_set_shared_rec_lock(
- LOCK_REC_NOT_GAP,rec,
- cursor->index, thr);
+ LOCK_REC_NOT_GAP, rec,
+ cursor->index, offsets, thr);
}
if (err != DB_SUCCESS) {
-
- return(err);
+ goto func_exit;
}
if (row_ins_dupl_error_with_rec(rec, entry,
- cursor->index)) {
+ cursor->index, offsets)) {
trx->error_info = cursor->index;
- return(DB_DUPLICATE_KEY);
+ err = DB_DUPLICATE_KEY;
+ goto func_exit;
}
+ mem_heap_free(heap);
}
ut_a(!(cursor->index->type & DICT_CLUSTERED));
/* This should never happen */
}
- return(DB_SUCCESS);
+ err = DB_SUCCESS;
+func_exit:
+ return(err);
}
/*******************************************************************
@@ -1841,6 +1890,9 @@ row_ins_index_entry_low(
ulint n_unique;
big_rec_t* big_rec = NULL;
mtr_t mtr;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[100] = { 100, };
+ ulint* offsets = offsets_;
log_free_check();
@@ -1873,8 +1925,8 @@ row_ins_index_entry_low(
buf_frame_align(btr_cur_get_rec(&cursor))));
if (!page_rec_is_supremum(first_rec)) {
- ut_a((rec_get_n_fields(first_rec))
- == dtuple_get_n_fields(entry));
+ ut_a(rec_get_n_fields(first_rec, index)
+ == dtuple_get_n_fields(entry));
}
n_unique = dict_index_get_n_unique(index);
@@ -1952,7 +2004,7 @@ row_ins_index_entry_low(
if (err == DB_SUCCESS) {
if (ext_vec) {
- rec_set_field_extern_bits(insert_rec,
+ rec_set_field_extern_bits(insert_rec, index,
ext_vec, n_ext_vec, &mtr);
}
}
@@ -1962,14 +2014,18 @@ function_exit:
mtr_commit(&mtr);
if (big_rec) {
+ rec_t* rec;
mtr_start(&mtr);
btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE,
BTR_MODIFY_TREE, &cursor, 0, &mtr);
+ rec = btr_cur_get_rec(&cursor);
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+
+ err = btr_store_big_rec_extern_fields(index, rec,
+ offsets, big_rec, &mtr);
- err = btr_store_big_rec_extern_fields(index,
- btr_cur_get_rec(&cursor),
- big_rec, &mtr);
if (modify) {
dtuple_big_rec_free(big_rec);
} else {
@@ -1979,6 +2035,9 @@ function_exit:
mtr_commit(&mtr);
}
+ if (heap) {
+ mem_heap_free(heap);
+ }
return(err);
}
diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c
index b7cd730828a..380fcf236ed 100644
--- a/innobase/row/row0mysql.c
+++ b/innobase/row/row0mysql.c
@@ -784,7 +784,7 @@ row_lock_table_for_mysql(
table handle */
dict_table_t* table, /* in: table to lock, or NULL
if prebuilt->table should be
- locked as LOCK_TABLE_EXP |
+ locked or a
prebuilt->select_lock_type */
ulint mode) /* in: lock mode of table */
{
@@ -822,8 +822,14 @@ run_again:
if (table) {
err = lock_table(0, table, mode, thr);
} else {
- err = lock_table(LOCK_TABLE_EXP, prebuilt->table,
- prebuilt->select_lock_type, thr);
+ if (mode == LOCK_TABLE_TRANSACTIONAL) {
+ err = lock_table(LOCK_TABLE_TRANSACTIONAL,
+ prebuilt->table,
+ prebuilt->select_lock_type, thr);
+ } else {
+ err = lock_table(LOCK_TABLE_EXP, prebuilt->table,
+ prebuilt->select_lock_type, thr);
+ }
}
trx->error_state = err;
@@ -945,9 +951,10 @@ run_again:
if (err != DB_SUCCESS) {
que_thr_stop_for_mysql(thr);
-
+ thr->lock_state= QUE_THR_LOCK_ROW;
was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
&savept);
+ thr->lock_state= QUE_THR_LOCK_NOLOCK;
if (was_lock_wait) {
goto run_again;
}
@@ -1193,9 +1200,11 @@ run_again:
return((int) err);
}
-
+
+ thr->lock_state= QUE_THR_LOCK_ROW;
was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
&savept);
+ thr->lock_state= QUE_THR_LOCK_NOLOCK;;
if (was_lock_wait) {
goto run_again;
}
@@ -1224,6 +1233,57 @@ run_again:
return((int) err);
}
+/*************************************************************************
+Does an unlock of a row for MySQL. */
+
+int
+row_unlock_for_mysql(
+/*=================*/
+ /* out: error code or DB_SUCCESS */
+ row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
+ handle */
+{
+ rec_t* rec;
+ btr_pcur_t* cur = prebuilt->pcur;
+ trx_t* trx = prebuilt->trx;
+ mtr_t mtr;
+
+ ut_ad(prebuilt && trx);
+ ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
+
+ trx->op_info = "unlock_row";
+
+ if (srv_locks_unsafe_for_binlog) {
+ if (trx->trx_create_lock == TRUE) {
+
+ mtr_start(&mtr);
+
+ /* Restore a cursor position and find a record */
+ btr_pcur_restore_position(BTR_SEARCH_LEAF, cur, &mtr);
+ rec = btr_pcur_get_rec(cur);
+
+ if (rec) {
+
+ lock_rec_reset_and_release_wait(rec);
+ } else {
+ fputs("InnoDB: Error: "
+ "Record for the lock not found\n",
+ stderr);
+ mem_analyze_corruption((byte*) trx);
+ ut_error;
+ }
+
+ trx->trx_create_lock = FALSE;
+ mtr_commit(&mtr);
+ }
+
+ }
+
+ trx->op_info = "";
+
+ return(DB_SUCCESS);
+}
+
/**************************************************************************
Does a cascaded delete or set null in a foreign key operation. */
@@ -3292,18 +3352,20 @@ row_scan_and_check_index(
ulint* n_rows) /* out: number of entries seen in the
current consistent read */
{
- mem_heap_t* heap;
- dtuple_t* prev_entry = NULL;
+ dtuple_t* prev_entry = NULL;
ulint matched_fields;
ulint matched_bytes;
byte* buf;
ulint ret;
rec_t* rec;
- ibool is_ok = TRUE;
+ ibool is_ok = TRUE;
int cmp;
ibool contains_null;
ulint i;
-
+ mem_heap_t* heap = NULL;
+ ulint offsets_[100] = { 100, };
+ ulint* offsets = offsets_;
+
*n_rows = 0;
buf = mem_alloc(UNIV_PAGE_SIZE);
@@ -3343,8 +3405,10 @@ loop:
if (prev_entry != NULL) {
matched_fields = 0;
matched_bytes = 0;
-
- cmp = cmp_dtuple_rec_with_match(prev_entry, rec,
+
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+ cmp = cmp_dtuple_rec_with_match(prev_entry, rec, offsets,
&matched_fields,
&matched_bytes);
contains_null = FALSE;
@@ -3373,7 +3437,7 @@ loop:
dtuple_print(stderr, prev_entry);
fputs("\n"
"InnoDB: record ", stderr);
- rec_print(stderr, rec);
+ rec_print_new(stderr, rec, offsets);
putc('\n', stderr);
is_ok = FALSE;
} else if ((index->type & DICT_UNIQUE)
@@ -3387,6 +3451,7 @@ loop:
}
mem_heap_empty(heap);
+ offsets = offsets_;
prev_entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap);
diff --git a/innobase/row/row0purge.c b/innobase/row/row0purge.c
index f7e01169b9d..8897a1a872f 100644
--- a/innobase/row/row0purge.c
+++ b/innobase/row/row0purge.c
@@ -99,6 +99,9 @@ row_purge_remove_clust_if_poss_low(
ibool success;
ulint err;
mtr_t mtr;
+ rec_t* rec;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[100] = { 100, };
index = dict_table_get_first_index(node->table);
@@ -117,15 +120,24 @@ row_purge_remove_clust_if_poss_low(
return(TRUE);
}
+ rec = btr_pcur_get_rec(pcur);
+
if (0 != ut_dulint_cmp(node->roll_ptr,
- row_get_rec_roll_ptr(btr_pcur_get_rec(pcur), index))) {
-
+ row_get_rec_roll_ptr(rec, index, rec_get_offsets(
+ rec, index, offsets_, ULINT_UNDEFINED, &heap)))) {
+ if (heap) {
+ mem_heap_free(heap);
+ }
/* Someone else has modified the record later: do not remove */
btr_pcur_commit_specify_mtr(pcur, &mtr);
return(TRUE);
}
+ if (heap) {
+ mem_heap_free(heap);
+ }
+
if (mode == BTR_MODIFY_LEAF) {
success = btr_cur_optimistic_delete(btr_cur, &mtr);
} else {
diff --git a/innobase/row/row0row.c b/innobase/row/row0row.c
index 38714b0c49b..43d0cd41b0a 100644
--- a/innobase/row/row0row.c
+++ b/innobase/row/row0row.c
@@ -37,17 +37,18 @@ row_get_rec_sys_field(
/* out: value of the field */
ulint type, /* in: DATA_TRX_ID or DATA_ROLL_PTR */
rec_t* rec, /* in: record */
- dict_index_t* index) /* in: clustered index */
+ dict_index_t* index, /* in: clustered index */
+ const ulint* offsets)/* in: rec_get_offsets(rec, index) */
{
- ulint pos;
- byte* field;
- ulint len;
+ ulint pos;
+ byte* field;
+ ulint len;
ut_ad(index->type & DICT_CLUSTERED);
pos = dict_index_get_sys_col_pos(index, type);
- field = rec_get_nth_field(rec, pos, &len);
+ field = rec_get_nth_field(rec, offsets, pos, &len);
if (type == DATA_TRX_ID) {
@@ -70,6 +71,7 @@ row_set_rec_sys_field(
ulint type, /* in: DATA_TRX_ID or DATA_ROLL_PTR */
rec_t* rec, /* in: record */
dict_index_t* index, /* in: clustered index */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
dulint val) /* in: value to set */
{
ulint pos;
@@ -77,10 +79,11 @@ row_set_rec_sys_field(
ulint len;
ut_ad(index->type & DICT_CLUSTERED);
+ ut_ad(rec_offs_validate(rec, index, offsets));
pos = dict_index_get_sys_col_pos(index, type);
- field = rec_get_nth_field(rec, pos, &len);
+ field = rec_get_nth_field(rec, offsets, pos, &len);
if (type == DATA_TRX_ID) {
@@ -182,6 +185,9 @@ row_build(
the buffer page of this record must be
at least s-latched and the latch held
as long as the row dtuple is used! */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index)
+ or NULL, in which case this function
+ will invoke rec_get_offsets() */
mem_heap_t* heap) /* in: memory heap from which the memory
needed is allocated */
{
@@ -196,14 +202,25 @@ row_build(
ulint row_len;
byte* buf;
ulint i;
-
+ mem_heap_t* tmp_heap = NULL;
+ ulint offsets_[100] = { 100, };
+
ut_ad(index && rec && heap);
ut_ad(index->type & DICT_CLUSTERED);
+ if (!offsets) {
+ offsets = rec_get_offsets(rec, index, offsets_,
+ ULINT_UNDEFINED, &tmp_heap);
+ } else {
+ ut_ad(rec_offs_validate(rec, index, offsets));
+ }
+
if (type != ROW_COPY_POINTERS) {
/* Take a copy of rec to heap */
- buf = mem_heap_alloc(heap, rec_get_size(rec));
- rec = rec_copy(buf, rec);
+ buf = mem_heap_alloc(heap, rec_offs_size(offsets));
+ rec = rec_copy(buf, rec, offsets);
+ /* Avoid a debug assertion in rec_offs_validate(). */
+ rec_offs_make_valid(rec, index, (ulint*) offsets);
}
table = index->table;
@@ -211,11 +228,9 @@ row_build(
row = dtuple_create(heap, row_len);
- dtuple_set_info_bits(row, rec_get_info_bits(rec));
-
- n_fields = dict_index_get_n_fields(index);
+ dtuple_set_info_bits(row, rec_get_info_bits(rec, table->comp));
- ut_ad(n_fields == rec_get_n_fields(rec));
+ n_fields = rec_offs_n_fields(offsets);
dict_table_copy_types(row, table);
@@ -227,13 +242,13 @@ row_build(
col = dict_field_get_col(ind_field);
dfield = dtuple_get_nth_field(row,
dict_col_get_no(col));
- field = rec_get_nth_field(rec, i, &len);
+ field = rec_get_nth_field(rec, offsets, i, &len);
if (type == ROW_COPY_ALSO_EXTERNALS
- && rec_get_nth_field_extern_bit(rec, i)) {
+ && rec_offs_nth_extern(offsets, i)) {
field = btr_rec_copy_externally_stored_field(
- rec, i, &len, heap);
+ rec, offsets, i, &len, heap);
}
dfield_set_data(dfield, field, len);
@@ -242,6 +257,10 @@ row_build(
ut_ad(dtuple_check_typed(row));
+ if (tmp_heap) {
+ mem_heap_free(tmp_heap);
+ }
+
return(row);
}
@@ -276,16 +295,24 @@ row_rec_to_index_entry(
ulint len;
ulint rec_len;
byte* buf;
-
+ mem_heap_t* tmp_heap = NULL;
+ ulint offsets_[100] = { 100, };
+ ulint* offsets = offsets_;
+
ut_ad(rec && heap && index);
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, &tmp_heap);
+
if (type == ROW_COPY_DATA) {
/* Take a copy of rec to heap */
- buf = mem_heap_alloc(heap, rec_get_size(rec));
- rec = rec_copy(buf, rec);
+ buf = mem_heap_alloc(heap, rec_offs_size(offsets));
+ rec = rec_copy(buf, rec, offsets);
+ /* Avoid a debug assertion in rec_offs_validate(). */
+ rec_offs_make_valid(rec, index, offsets);
}
- rec_len = rec_get_n_fields(rec);
+ rec_len = rec_offs_n_fields(offsets);
entry = dtuple_create(heap, rec_len);
@@ -295,17 +322,21 @@ row_rec_to_index_entry(
dict_index_copy_types(entry, index, rec_len);
- dtuple_set_info_bits(entry, rec_get_info_bits(rec));
+ dtuple_set_info_bits(entry,
+ rec_get_info_bits(rec, rec_offs_comp(offsets)));
for (i = 0; i < rec_len; i++) {
dfield = dtuple_get_nth_field(entry, i);
- field = rec_get_nth_field(rec, i, &len);
+ field = rec_get_nth_field(rec, offsets, i, &len);
dfield_set_data(dfield, field, len);
}
ut_ad(dtuple_check_typed(entry));
+ if (tmp_heap) {
+ mem_heap_free(tmp_heap);
+ }
return(entry);
}
@@ -345,15 +376,23 @@ row_build_row_ref(
byte* buf;
ulint clust_col_prefix_len;
ulint i;
-
+ mem_heap_t* tmp_heap = NULL;
+ ulint offsets_[100] = { 100, };
+ ulint* offsets = offsets_;
+
ut_ad(index && rec && heap);
-
+
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, &tmp_heap);
+
if (type == ROW_COPY_DATA) {
/* Take a copy of rec to heap */
- buf = mem_heap_alloc(heap, rec_get_size(rec));
+ buf = mem_heap_alloc(heap, rec_offs_size(offsets));
- rec = rec_copy(buf, rec);
+ rec = rec_copy(buf, rec, offsets);
+ /* Avoid a debug assertion in rec_offs_validate(). */
+ rec_offs_make_valid(rec, index, offsets);
}
table = index->table;
@@ -373,7 +412,7 @@ row_build_row_ref(
ut_a(pos != ULINT_UNDEFINED);
- field = rec_get_nth_field(rec, pos, &len);
+ field = rec_get_nth_field(rec, offsets, pos, &len);
dfield_set_data(dfield, field, len);
@@ -397,6 +436,9 @@ row_build_row_ref(
}
ut_ad(dtuple_check_typed(ref));
+ if (tmp_heap) {
+ mem_heap_free(tmp_heap);
+ }
return(ref);
}
@@ -427,7 +469,10 @@ row_build_row_ref_in_tuple(
ulint pos;
ulint clust_col_prefix_len;
ulint i;
-
+ mem_heap_t* heap = NULL;
+ ulint offsets_[100] = { 100, };
+ ulint* offsets = offsets_;
+
ut_a(ref && index && rec);
if (!index->table) {
@@ -446,7 +491,9 @@ row_build_row_ref_in_tuple(
fputs("InnoDB: clust index for table ", stderr);
goto notfound;
}
-
+
+ offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
+
ref_len = dict_index_get_n_unique(clust_index);
ut_ad(ref_len == dtuple_get_n_fields(ref));
@@ -459,8 +506,8 @@ row_build_row_ref_in_tuple(
pos = dict_index_get_nth_field_pos(index, clust_index, i);
ut_a(pos != ULINT_UNDEFINED);
-
- field = rec_get_nth_field(rec, pos, &len);
+
+ field = rec_get_nth_field(rec, offsets, pos, &len);
dfield_set_data(dfield, field, len);
@@ -484,6 +531,9 @@ row_build_row_ref_in_tuple(
}
ut_ad(dtuple_check_typed(ref));
+ if (heap) {
+ mem_heap_free(heap);
+ }
}
/***********************************************************************
diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c
index 52228caccb0..8512e796a72 100644
--- a/innobase/row/row0sel.c
+++ b/innobase/row/row0sel.c
@@ -78,8 +78,19 @@ row_sel_sec_rec_is_for_clust_rec(
ulint n;
ulint i;
dtype_t* cur_type;
-
- UT_NOT_USED(clust_index);
+ mem_heap_t* heap = NULL;
+ ulint clust_offsets_[100]
+ = { 100, };
+ ulint sec_offsets_[10]
+ = { 10, };
+ ulint* clust_offs = clust_offsets_;
+ ulint* sec_offs = sec_offsets_;
+ ibool is_equal = TRUE;
+
+ clust_offs = rec_get_offsets(clust_rec, clust_index, clust_offs,
+ ULINT_UNDEFINED, &heap);
+ sec_offs = rec_get_offsets(sec_rec, sec_index, sec_offs,
+ ULINT_UNDEFINED, &heap);
n = dict_index_get_n_ordering_defined_by_user(sec_index);
@@ -87,10 +98,10 @@ row_sel_sec_rec_is_for_clust_rec(
ifield = dict_index_get_nth_field(sec_index, i);
col = dict_field_get_col(ifield);
- clust_field = rec_get_nth_field(clust_rec,
+ clust_field = rec_get_nth_field(clust_rec, clust_offs,
dict_col_get_clust_pos(col),
&clust_len);
- sec_field = rec_get_nth_field(sec_rec, i, &sec_len);
+ sec_field = rec_get_nth_field(sec_rec, sec_offs, i, &sec_len);
if (ifield->prefix_len > 0
&& clust_len != UNIV_SQL_NULL) {
@@ -107,11 +118,16 @@ row_sel_sec_rec_is_for_clust_rec(
if (0 != cmp_data_data(dict_col_get_type(col),
clust_field, clust_len,
sec_field, sec_len)) {
- return(FALSE);
+ is_equal = FALSE;
+ goto func_exit;
}
}
- return(TRUE);
+func_exit:
+ if (heap) {
+ mem_heap_free(heap);
+ }
+ return(is_equal);
}
/*************************************************************************
@@ -266,6 +282,7 @@ row_sel_fetch_columns(
dict_index_t* index, /* in: record index */
rec_t* rec, /* in: record in a clustered or non-clustered
index */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
sym_node_t* column) /* in: first column in a column list, or
NULL */
{
@@ -275,6 +292,8 @@ row_sel_fetch_columns(
byte* data;
ulint len;
+ ut_ad(rec_offs_validate(rec, index, offsets));
+
if (index->type & DICT_CLUSTERED) {
index_type = SYM_CLUST_FIELD_NO;
} else {
@@ -286,7 +305,7 @@ row_sel_fetch_columns(
if (field_no != ULINT_UNDEFINED) {
- data = rec_get_nth_field(rec, field_no, &len);
+ data = rec_get_nth_field(rec, offsets, field_no, &len);
if (column->copy_val) {
eval_node_copy_and_alloc_val(column, data,
@@ -601,8 +620,15 @@ row_sel_get_clust_rec(
rec_t* clust_rec;
rec_t* old_vers;
ulint err;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[100] = { 100, };
+ ulint* offsets = offsets_;
+
+ offsets = rec_get_offsets(rec,
+ btr_pcur_get_btr_cur(&plan->pcur)->index,
+ offsets, ULINT_UNDEFINED, &heap);
- row_build_row_ref_fast(plan->clust_ref, plan->clust_map, rec);
+ row_build_row_ref_fast(plan->clust_ref, plan->clust_map, rec, offsets);
index = dict_table_get_first_index(plan->table);
@@ -619,7 +645,7 @@ row_sel_get_clust_rec(
|| btr_pcur_get_low_match(&(plan->clust_pcur))
< dict_index_get_n_unique(index)) {
- ut_a(rec_get_deleted_flag(rec));
+ ut_a(rec_get_deleted_flag(rec, plan->table->comp));
ut_a(node->read_view);
/* In a rare case it is possible that no clust rec is found
@@ -636,29 +662,30 @@ row_sel_get_clust_rec(
goto func_exit;
}
+ offsets = rec_get_offsets(clust_rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+
if (!node->read_view) {
/* Try to place a lock on the index record */
/* If innodb_locks_unsafe_for_binlog option is used,
- we lock only the record, i.e. next-key locking is
- not used.
- */
+ we lock only the record, i.e., next-key locking is
+ not used. */
+ ulint lock_type;
if (srv_locks_unsafe_for_binlog) {
- err = lock_clust_rec_read_check_and_lock(0,
- clust_rec,
- index, node->row_lock_mode,
- LOCK_REC_NOT_GAP, thr);
+ lock_type = LOCK_REC_NOT_GAP;
} else {
- err = lock_clust_rec_read_check_and_lock(0,
- clust_rec,
- index, node->row_lock_mode,
- LOCK_ORDINARY, thr);
+ lock_type = LOCK_ORDINARY;
}
+ err = lock_clust_rec_read_check_and_lock(0,
+ clust_rec, index, offsets,
+ node->row_lock_mode, lock_type, thr);
+
if (err != DB_SUCCESS) {
- return(err);
+ goto err_exit;
}
} else {
/* This is a non-locking consistent read: if necessary, fetch
@@ -666,22 +693,20 @@ row_sel_get_clust_rec(
old_vers = NULL;
- if (!lock_clust_rec_cons_read_sees(clust_rec, index,
+ if (!lock_clust_rec_cons_read_sees(clust_rec, index, offsets,
node->read_view)) {
err = row_sel_build_prev_vers(node->read_view, plan,
clust_rec, &old_vers, mtr);
if (err != DB_SUCCESS) {
- return(err);
+ goto err_exit;
}
clust_rec = old_vers;
if (clust_rec == NULL) {
- *out_rec = clust_rec;
-
- return(DB_SUCCESS);
+ goto func_exit;
}
}
@@ -698,24 +723,26 @@ 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))
+ if ((old_vers || rec_get_deleted_flag(rec, plan->table->comp))
&& !row_sel_sec_rec_is_for_clust_rec(rec, plan->index,
clust_rec, index)) {
clust_rec = NULL;
- *out_rec = clust_rec;
-
- return(DB_SUCCESS);
+ goto func_exit;
}
}
/* Fetch the columns needed in test conditions */
-
- row_sel_fetch_columns(index, clust_rec,
+
+ row_sel_fetch_columns(index, clust_rec, offsets,
UT_LIST_GET_FIRST(plan->columns));
func_exit:
*out_rec = clust_rec;
-
- return(DB_SUCCESS);
+ err = DB_SUCCESS;
+err_exit:
+ if (heap) {
+ mem_heap_free(heap);
+ }
+ return(err);
}
/*************************************************************************
@@ -727,6 +754,7 @@ sel_set_rec_lock(
/* out: DB_SUCCESS or error code */
rec_t* rec, /* in: record */
dict_index_t* index, /* in: index */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
ulint mode, /* in: lock mode */
ulint type, /* in: LOCK_ORDINARY, LOCK_GAP, or LOC_REC_NOT_GAP */
que_thr_t* thr) /* in: query thread */
@@ -744,11 +772,11 @@ sel_set_rec_lock(
}
if (index->type & DICT_CLUSTERED) {
- err = lock_clust_rec_read_check_and_lock(0, rec, index, mode,
- type, thr);
+ err = lock_clust_rec_read_check_and_lock(0,
+ rec, index, offsets, mode, type, thr);
} else {
- err = lock_sec_rec_read_check_and_lock(0, rec, index, mode,
- type, thr);
+ err = lock_sec_rec_read_check_and_lock(0,
+ rec, index, offsets, mode, type, thr);
}
return(err);
@@ -956,6 +984,10 @@ row_sel_try_search_shortcut(
{
dict_index_t* index;
rec_t* rec;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[100] = { 100, };
+ ulint* offsets = offsets_;
+ ulint ret;
index = plan->index;
@@ -989,36 +1021,46 @@ row_sel_try_search_shortcut(
/* This is a non-locking consistent read: if necessary, fetch
a previous version of the record */
+ offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
+
if (index->type & DICT_CLUSTERED) {
- if (!lock_clust_rec_cons_read_sees(rec, index,
+ if (!lock_clust_rec_cons_read_sees(rec, index, offsets,
node->read_view)) {
- return(SEL_RETRY);
+ ret = SEL_RETRY;
+ goto func_exit;
}
} else if (!lock_sec_rec_cons_read_sees(rec, index, node->read_view)) {
- return(SEL_RETRY);
+ ret = SEL_RETRY;
+ goto func_exit;
}
/* Test deleted flag. Fetch the columns needed in test conditions. */
-
- row_sel_fetch_columns(index, rec, UT_LIST_GET_FIRST(plan->columns));
- if (rec_get_deleted_flag(rec)) {
+ row_sel_fetch_columns(index, rec, offsets,
+ UT_LIST_GET_FIRST(plan->columns));
- return(SEL_EXHAUSTED);
+ if (rec_get_deleted_flag(rec, plan->table->comp)) {
+
+ ret = SEL_EXHAUSTED;
+ goto func_exit;
}
/* Test the rest of search conditions */
if (!row_sel_test_other_conds(plan)) {
- return(SEL_EXHAUSTED);
+ ret = SEL_EXHAUSTED;
+ goto func_exit;
}
ut_ad(plan->pcur.latch_mode == node->latch_mode);
plan->n_rows_fetched++;
-
+func_exit:
+ if (heap) {
+ mem_heap_free(heap);
+ }
return(SEL_FOUND);
}
@@ -1067,7 +1109,10 @@ row_sel(
to the next non-clustered record */
ulint found_flag;
ulint err;
-
+ mem_heap_t* heap = NULL;
+ ulint offsets_[100] = { 100, };
+ ulint* offsets = offsets_;
+
ut_ad(thr->run_node == node);
search_latch_locked = FALSE;
@@ -1218,22 +1263,23 @@ rec_loop:
if (!consistent_read) {
/* If innodb_locks_unsafe_for_binlog option is used,
- we lock only the record, i.e. next-key locking is
- not used.
- */
+ we lock only the record, i.e., next-key locking is
+ not used. */
+
+ rec_t* next_rec = page_rec_get_next(rec);
+ ulint lock_type;
+ offsets = rec_get_offsets(next_rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
if (srv_locks_unsafe_for_binlog) {
- err = sel_set_rec_lock(page_rec_get_next(rec),
- index,
- node->row_lock_mode,
- LOCK_REC_NOT_GAP, thr);
+ lock_type = LOCK_REC_NOT_GAP;
} else {
- err = sel_set_rec_lock(page_rec_get_next(rec),
- index,
- node->row_lock_mode,
- LOCK_ORDINARY, thr);
+ lock_type = LOCK_ORDINARY;
}
+ err = sel_set_rec_lock(next_rec, index, offsets,
+ node->row_lock_mode, lock_type, thr);
+
if (err != DB_SUCCESS) {
/* Note that in this case we will store in pcur
the PREDECESSOR of the record we are waiting
@@ -1260,18 +1306,22 @@ rec_loop:
/* Try to place a lock on the index record */
/* If innodb_locks_unsafe_for_binlog option is used,
- we lock only the record, i.e. next-key locking is
- not used.
- */
+ we lock only the record, i.e., next-key locking is
+ not used. */
+
+ ulint lock_type;
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
if (srv_locks_unsafe_for_binlog) {
- err = sel_set_rec_lock(rec, index, node->row_lock_mode,
- LOCK_REC_NOT_GAP, thr);
+ lock_type = LOCK_REC_NOT_GAP;
} else {
- err = sel_set_rec_lock(rec, index, node->row_lock_mode,
- LOCK_ORDINARY, thr);
+ lock_type = LOCK_ORDINARY;
}
+ err = sel_set_rec_lock(rec, index, offsets,
+ node->row_lock_mode, lock_type, thr);
+
if (err != DB_SUCCESS) {
goto lock_wait_or_error;
@@ -1334,6 +1384,7 @@ rec_loop:
/* PHASE 3: Get previous version in a consistent read */
cons_read_requires_clust_rec = FALSE;
+ offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
if (consistent_read) {
/* This is a non-locking consistent read: if necessary, fetch
@@ -1341,7 +1392,7 @@ rec_loop:
if (index->type & DICT_CLUSTERED) {
- if (!lock_clust_rec_cons_read_sees(rec, index,
+ if (!lock_clust_rec_cons_read_sees(rec, index, offsets,
node->read_view)) {
err = row_sel_build_prev_vers(node->read_view,
@@ -1354,6 +1405,7 @@ rec_loop:
if (old_vers == NULL) {
row_sel_fetch_columns(index, rec,
+ offsets,
UT_LIST_GET_FIRST(plan->columns));
if (!row_sel_test_end_conds(plan)) {
@@ -1365,6 +1417,8 @@ rec_loop:
}
rec = old_vers;
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
}
} else if (!lock_sec_rec_cons_read_sees(rec, index,
node->read_view)) {
@@ -1376,7 +1430,8 @@ rec_loop:
/* Fetch the columns needed in test conditions */
- row_sel_fetch_columns(index, rec, UT_LIST_GET_FIRST(plan->columns));
+ row_sel_fetch_columns(index, rec, offsets,
+ UT_LIST_GET_FIRST(plan->columns));
/* Test the selection end conditions: these can only contain columns
which already are found in the index, even though the index might be
@@ -1391,7 +1446,8 @@ rec_loop:
goto table_exhausted;
}
- if (rec_get_deleted_flag(rec) && !cons_read_requires_clust_rec) {
+ if (rec_get_deleted_flag(rec, plan->table->comp)
+ && !cons_read_requires_clust_rec) {
/* The record is delete marked: we can skip it if this is
not a consistent read which might see an earlier version
@@ -1434,7 +1490,7 @@ rec_loop:
goto next_rec;
}
- if (rec_get_deleted_flag(clust_rec)) {
+ if (rec_get_deleted_flag(clust_rec, plan->table->comp)) {
/* The record is delete marked: we can skip it */
@@ -1592,8 +1648,9 @@ next_table_no_mtr:
if (search_latch_locked) {
rw_lock_s_unlock(&btr_search_latch);
}
-
- return(DB_SUCCESS);
+
+ err = DB_SUCCESS;
+ goto func_exit;
}
node->fetch_table++;
@@ -1626,6 +1683,7 @@ table_exhausted:
table_exhausted_no_mtr:
if (node->fetch_table == 0) {
+ err = DB_SUCCESS;
if (node->is_aggregate && !node->aggregate_already_fetched) {
@@ -1639,7 +1697,7 @@ table_exhausted_no_mtr:
rw_lock_s_unlock(&btr_search_latch);
}
- return(DB_SUCCESS);
+ goto func_exit;
}
node->state = SEL_NODE_NO_MORE_ROWS;
@@ -1650,7 +1708,7 @@ table_exhausted_no_mtr:
rw_lock_s_unlock(&btr_search_latch);
}
- return(DB_SUCCESS);
+ goto func_exit;
}
node->fetch_table--;
@@ -1674,8 +1732,8 @@ stop_for_a_while:
mtr_commit(&mtr);
ut_ad(sync_thread_levels_empty_gen(TRUE));
-
- return(DB_SUCCESS);
+ err = DB_SUCCESS;
+ goto func_exit;
commit_mtr_for_a_while:
/* Stores the cursor position and commits &mtr; this is used if
@@ -1710,6 +1768,10 @@ lock_wait_or_error:
ut_ad(sync_thread_levels_empty_gen(TRUE));
+func_exit:
+ if (heap) {
+ mem_heap_free(heap);
+ }
return(err);
}
@@ -2133,11 +2195,16 @@ row_sel_store_row_id_to_prebuilt(
/*=============================*/
row_prebuilt_t* prebuilt, /* in: prebuilt */
rec_t* index_rec, /* in: record */
- dict_index_t* index) /* in: index of the record */
+ dict_index_t* index, /* in: index of the record */
+ const ulint* offsets) /* in: rec_get_offsets
+ (index_rec, index) */
{
byte* data;
ulint len;
- data = rec_get_nth_field(index_rec,
+
+ ut_ad(rec_offs_validate(index_rec, index, offsets));
+
+ data = rec_get_nth_field(index_rec, offsets,
dict_index_get_sys_col_pos(index, DATA_ROW_ID), &len);
if (len != DATA_ROW_ID_LEN) {
@@ -2147,7 +2214,7 @@ row_sel_store_row_id_to_prebuilt(
fprintf(stderr, "\n"
"InnoDB: Field number %lu, record:\n",
(ulong) dict_index_get_sys_col_pos(index, DATA_ROW_ID));
- rec_print(stderr, index_rec);
+ rec_print_new(stderr, index_rec, offsets);
putc('\n', stderr);
ut_error;
}
@@ -2233,9 +2300,11 @@ row_sel_store_mysql_rec(
case) */
byte* mysql_rec, /* out: row in the MySQL format */
row_prebuilt_t* prebuilt, /* in: prebuilt struct */
- rec_t* rec) /* in: Innobase record in the index
+ rec_t* rec, /* in: Innobase record in the index
which was described in prebuilt's
template */
+ const ulint* offsets) /* in: array returned by
+ rec_get_offsets() */
{
mysql_row_templ_t* templ;
mem_heap_t* extern_field_heap = NULL;
@@ -2244,26 +2313,29 @@ row_sel_store_mysql_rec(
byte* blob_buf;
int pad_char;
ulint i;
+ dict_index_t* index;
ut_ad(prebuilt->mysql_template);
+ ut_ad(rec_offs_validate(rec, NULL, offsets));
+
+ index = prebuilt->index;
+ if (prebuilt->need_to_access_clustered) {
+ index = dict_table_get_first_index(index->table);
+ }
if (prebuilt->blob_heap != NULL) {
mem_heap_free(prebuilt->blob_heap);
prebuilt->blob_heap = NULL;
}
- /* MySQL assumes that all columns have the SQL NULL bit set unless it
- is a nullable column with a non-NULL value */
-
- memset(mysql_rec, 0xFF, prebuilt->null_bitmap_len);
-
for (i = 0; i < prebuilt->n_template; i++) {
templ = prebuilt->mysql_template + i;
- data = rec_get_nth_field(rec, templ->rec_field_no, &len);
+ data = rec_get_nth_field(rec, offsets,
+ templ->rec_field_no, &len);
- if (rec_get_nth_field_extern_bit(rec, templ->rec_field_no)) {
+ if (rec_offs_nth_extern(offsets, templ->rec_field_no)) {
/* Copy an externally stored field to the temporary
heap */
@@ -2277,7 +2349,7 @@ row_sel_store_mysql_rec(
causes an assert */
data = btr_rec_copy_externally_stored_field(rec,
- templ->rec_field_no, &len,
+ offsets, templ->rec_field_no, &len,
extern_field_heap);
ut_a(len != UNIV_SQL_NULL);
@@ -2389,6 +2461,8 @@ row_sel_store_mysql_rec(
bug number 154 in the MySQL bug database: GROUP BY
and DISTINCT could treat NULL values inequal. */
+ mysql_rec[templ->mysql_null_byte_offset] |=
+ (byte) (templ->mysql_null_bit_mask);
if (templ->type == DATA_VARCHAR
|| templ->type == DATA_CHAR
|| templ->type == DATA_BINARY
@@ -2492,6 +2566,9 @@ row_sel_get_clust_rec_for_mysql(
rec_t* old_vers;
ulint err;
trx_t* trx;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[100] = { 100, };
+ ulint* offsets = offsets_;
*out_rec = NULL;
trx = thr_get_trx(thr);
@@ -2522,9 +2599,8 @@ row_sel_get_clust_rec_for_mysql(
clustered index record did not exist in the read view of
trx. */
- if (!rec_get_deleted_flag(rec)
+ if (!rec_get_deleted_flag(rec, sec_index->table->comp)
|| prebuilt->select_lock_type != LOCK_NONE) {
-
ut_print_timestamp(stderr);
fputs(" InnoDB: error clustered record"
" for sec rec not found\n"
@@ -2532,10 +2608,10 @@ row_sel_get_clust_rec_for_mysql(
dict_index_name_print(stderr, trx, sec_index);
fputs("\n"
"InnoDB: sec index record ", stderr);
- rec_print(stderr, rec);
+ rec_print(stderr, rec, sec_index);
fputs("\n"
"InnoDB: clust index record ", stderr);
- rec_print(stderr, clust_rec);
+ rec_print(stderr, clust_rec, clust_index);
putc('\n', stderr);
trx_print(stderr, trx);
@@ -2548,18 +2624,21 @@ row_sel_get_clust_rec_for_mysql(
goto func_exit;
}
+ offsets = rec_get_offsets(clust_rec, clust_index, offsets,
+ ULINT_UNDEFINED, &heap);
+
if (prebuilt->select_lock_type != LOCK_NONE) {
/* Try to place a lock on the index record; we are searching
the clust rec with a unique condition, hence
we set a LOCK_REC_NOT_GAP type lock */
err = lock_clust_rec_read_check_and_lock(0, clust_rec,
- clust_index,
+ clust_index, offsets,
prebuilt->select_lock_type,
LOCK_REC_NOT_GAP, thr);
if (err != DB_SUCCESS) {
- return(err);
+ goto err_exit;
}
} else {
/* This is a non-locking consistent read: if necessary, fetch
@@ -2572,7 +2651,7 @@ row_sel_get_clust_rec_for_mysql(
if (trx->isolation_level > TRX_ISO_READ_UNCOMMITTED
&& !lock_clust_rec_cons_read_sees(clust_rec, clust_index,
- trx->read_view)) {
+ offsets, trx->read_view)) {
err = row_sel_build_prev_vers_for_mysql(
trx->read_view, clust_index,
@@ -2581,7 +2660,7 @@ row_sel_get_clust_rec_for_mysql(
if (err != DB_SUCCESS) {
- return(err);
+ goto err_exit;
}
clust_rec = old_vers;
@@ -2600,7 +2679,8 @@ row_sel_get_clust_rec_for_mysql(
visit through secondary index records that would not really
exist in our snapshot. */
- if (clust_rec && (old_vers || rec_get_deleted_flag(rec))
+ if (clust_rec && (old_vers
+ || rec_get_deleted_flag(rec, sec_index->table->comp))
&& !row_sel_sec_rec_is_for_clust_rec(rec, sec_index,
clust_rec, clust_index)) {
clust_rec = NULL;
@@ -2622,7 +2702,12 @@ func_exit:
btr_pcur_store_position(prebuilt->clust_pcur, mtr);
}
- return(DB_SUCCESS);
+ err = DB_SUCCESS;
+err_exit:
+ if (heap) {
+ mem_heap_free(heap);
+ }
+ return(err);
}
/************************************************************************
@@ -2699,10 +2784,40 @@ row_sel_pop_cached_row_for_mysql(
row */
row_prebuilt_t* prebuilt) /* in: prebuilt struct */
{
- ut_ad(prebuilt->n_fetch_cached > 0);
-
- ut_memcpy(buf, prebuilt->fetch_cache[prebuilt->fetch_cache_first],
- prebuilt->mysql_row_len);
+ ulint i;
+ mysql_row_templ_t* templ;
+ byte* cached_rec;
+ ut_ad(prebuilt->n_fetch_cached > 0);
+
+ if (prebuilt->keep_other_fields_on_keyread)
+ {
+ /* Copy cache record field by field, don't touch fields that
+ are not covered by current key */
+ cached_rec =
+ prebuilt->fetch_cache[prebuilt->fetch_cache_first];
+
+ for (i = 0; i < prebuilt->n_template; i++) {
+ templ = prebuilt->mysql_template + i;
+ ut_memcpy(
+ buf + templ->mysql_col_offset,
+ cached_rec + templ->mysql_col_offset,
+ templ->mysql_col_len);
+ /* Copy NULL bit of the current field from cached_rec
+ to buf */
+ if (templ->mysql_null_bit_mask)
+ {
+ buf[templ->mysql_null_byte_offset] ^=
+ (buf[templ->mysql_null_byte_offset] ^
+ cached_rec[templ->mysql_null_byte_offset]) &
+ (byte)templ->mysql_null_bit_mask;
+ }
+ }
+ }
+ else
+ {
+ ut_memcpy(buf, prebuilt->fetch_cache[prebuilt->fetch_cache_first],
+ prebuilt->mysql_row_len);
+ }
prebuilt->n_fetch_cached--;
prebuilt->fetch_cache_first++;
@@ -2718,12 +2833,14 @@ void
row_sel_push_cache_row_for_mysql(
/*=============================*/
row_prebuilt_t* prebuilt, /* in: prebuilt struct */
- rec_t* rec) /* in: record to push */
+ rec_t* rec, /* in: record to push */
+ const ulint* offsets) /* in: rec_get_offsets() */
{
byte* buf;
ulint i;
ut_ad(prebuilt->n_fetch_cached < MYSQL_FETCH_CACHE_SIZE);
+ ut_ad(rec_offs_validate(rec, NULL, offsets));
ut_a(!prebuilt->templ_contains_blob);
if (prebuilt->fetch_cache[0] == NULL) {
@@ -2749,7 +2866,7 @@ row_sel_push_cache_row_for_mysql(
ut_a(row_sel_store_mysql_rec(
prebuilt->fetch_cache[prebuilt->n_fetch_cached],
- prebuilt, rec));
+ prebuilt, rec, offsets));
prebuilt->n_fetch_cached++;
}
@@ -2766,6 +2883,8 @@ row_sel_try_search_shortcut_for_mysql(
/* out: SEL_FOUND, SEL_EXHAUSTED, SEL_RETRY */
rec_t** out_rec,/* out: record if found */
row_prebuilt_t* prebuilt,/* in: prebuilt struct */
+ ulint** offsets,/* in/out: for rec_get_offsets(*out_rec) */
+ mem_heap_t** heap, /* in/out: heap for rec_get_offsets() */
mtr_t* mtr) /* in: started mtr */
{
dict_index_t* index = prebuilt->index;
@@ -2803,13 +2922,17 @@ row_sel_try_search_shortcut_for_mysql(
/* This is a non-locking consistent read: if necessary, fetch
a previous version of the record */
-
- if (!lock_clust_rec_cons_read_sees(rec, index, trx->read_view)) {
+
+ *offsets = rec_get_offsets(rec, index, *offsets,
+ ULINT_UNDEFINED, heap);
+
+ if (!lock_clust_rec_cons_read_sees(rec, index,
+ *offsets, trx->read_view)) {
return(SEL_RETRY);
}
- if (rec_get_deleted_flag(rec)) {
+ if (rec_get_deleted_flag(rec, index->table->comp)) {
return(SEL_EXHAUSTED);
}
@@ -2866,7 +2989,6 @@ row_search_for_mysql(
ibool moved;
ibool cons_read_requires_clust_rec;
ibool was_lock_wait;
- ulint ret;
ulint shortcut;
ibool unique_search = FALSE;
ibool unique_search_from_clust_index = FALSE;
@@ -2878,9 +3000,13 @@ row_search_for_mysql(
level is <= TRX_ISO_READ_COMMITTED,
then this is set to FALSE */
ibool success;
+ ibool comp;
ulint cnt = 0;
ulint next_offs;
mtr_t mtr;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[100] = { 100, };
+ ulint* offsets = offsets_;
ut_ad(index && pcur && search_tuple);
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
@@ -2985,9 +3111,8 @@ row_search_for_mysql(
prebuilt->n_rows_fetched++;
srv_n_rows_read++;
- trx->op_info = "";
-
- return(DB_SUCCESS);
+ err = DB_SUCCESS;
+ goto func_exit;
}
if (prebuilt->fetch_cache_first > 0
@@ -2996,9 +3121,9 @@ row_search_for_mysql(
/* The previous returned row was popped from the fetch
cache, but the cache was not full at the time of the
popping: no more rows can exist in the result set */
-
- trx->op_info = "";
- return(DB_RECORD_NOT_FOUND);
+
+ err = DB_RECORD_NOT_FOUND;
+ goto func_exit;
}
prebuilt->n_rows_fetched++;
@@ -3042,8 +3167,8 @@ row_search_for_mysql(
if (direction != 0 && !prebuilt->used_in_HANDLER) {
- trx->op_info = "";
- return(DB_RECORD_NOT_FOUND);
+ err = DB_RECORD_NOT_FOUND;
+ goto func_exit;
}
}
@@ -3093,13 +3218,14 @@ row_search_for_mysql(
}
#endif
shortcut = row_sel_try_search_shortcut_for_mysql(&rec,
- prebuilt, &mtr);
+ prebuilt, &offsets, &heap, &mtr);
if (shortcut == SEL_FOUND) {
#ifdef UNIV_SEARCH_DEBUG
- ut_a(0 == cmp_dtuple_rec(search_tuple, rec));
+ ut_a(0 == cmp_dtuple_rec(search_tuple,
+ rec, offsets));
#endif
if (!row_sel_store_mysql_rec(buf, prebuilt,
- rec)) {
+ rec, offsets)) {
err = DB_TOO_BIG_RECORD;
/* We let the main loop to do the
@@ -3123,12 +3249,10 @@ row_search_for_mysql(
trx->has_search_latch = FALSE;
}
- trx->op_info = "";
-
/* NOTE that we do NOT store the cursor
position */
-
- return(DB_SUCCESS);
+ err = DB_SUCCESS;
+ goto func_exit;
} else if (shortcut == SEL_EXHAUSTED) {
@@ -3146,12 +3270,11 @@ row_search_for_mysql(
trx->has_search_latch = FALSE;
}
- trx->op_info = "";
-
/* NOTE that we do NOT store the cursor
position */
- return(DB_RECORD_NOT_FOUND);
+ err = DB_RECORD_NOT_FOUND;
+ goto func_exit;
}
shortcut_fails_too_big_rec:
mtr_commit(&mtr);
@@ -3264,6 +3387,8 @@ rec_loop:
/* PHASE 4: Look for matching records in a loop */
rec = btr_pcur_get_rec(pcur);
+ comp = index->table->comp;
+ ut_ad(comp == page_is_comp(buf_frame_align(rec)));
/*
fputs("Using ", stderr);
dict_index_name_print(stderr, index);
@@ -3291,8 +3416,10 @@ rec_loop:
we do not lock gaps. Supremum record is really
a gap and therefore we do not set locks there. */
- if (srv_locks_unsafe_for_binlog == FALSE) {
- err = sel_set_rec_lock(rec, index,
+ if (!srv_locks_unsafe_for_binlog) {
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+ err = sel_set_rec_lock(rec, index, offsets,
prebuilt->select_lock_type,
LOCK_ORDINARY, thr);
}
@@ -3312,9 +3439,11 @@ rec_loop:
/* Do sanity checks in case our cursor has bumped into page
corruption */
- next_offs = rec_get_next_offs(rec);
+ next_offs = rec_get_next_offs(rec, comp);
- if (next_offs >= UNIV_PAGE_SIZE || next_offs < PAGE_SUPREMUM) {
+ if (next_offs >= UNIV_PAGE_SIZE
+ || next_offs <
+ (ulint) (comp ? PAGE_NEW_SUPREMUM : PAGE_OLD_SUPREMUM)) {
if (srv_force_recovery == 0 || moves_up == FALSE) {
ut_print_timestamp(stderr);
@@ -3359,9 +3488,11 @@ rec_loop:
}
}
+ offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
+
if (srv_force_recovery > 0) {
- if (!rec_validate(rec) || !btr_index_rec_validate(rec, index,
- FALSE)) {
+ if (!rec_validate(rec, offsets)
+ || !btr_index_rec_validate(rec, index, FALSE)) {
fprintf(stderr,
"InnoDB: Index corruption: rec offs %lu next offs %lu, page no %lu,\n"
"InnoDB: ",
@@ -3389,7 +3520,7 @@ rec_loop:
/* fputs("Comparing rec and search tuple\n", stderr); */
- if (0 != cmp_dtuple_rec(search_tuple, rec)) {
+ if (0 != cmp_dtuple_rec(search_tuple, rec, offsets)) {
if (prebuilt->select_lock_type != LOCK_NONE
&& set_also_gap_locks) {
@@ -3401,6 +3532,7 @@ rec_loop:
if (srv_locks_unsafe_for_binlog == FALSE) {
err = sel_set_rec_lock(rec, index,
+ offsets,
prebuilt->select_lock_type,
LOCK_GAP, thr);
}
@@ -3413,7 +3545,7 @@ rec_loop:
btr_pcur_store_position(pcur, &mtr);
- ret = DB_RECORD_NOT_FOUND;
+ err = DB_RECORD_NOT_FOUND;
/* ut_print_name(stderr, index->name);
fputs(" record not found 3\n", stderr); */
@@ -3422,7 +3554,7 @@ rec_loop:
} else if (match_mode == ROW_SEL_EXACT_PREFIX) {
- if (!cmp_dtuple_is_prefix_of_rec(search_tuple, rec)) {
+ if (!cmp_dtuple_is_prefix_of_rec(search_tuple, rec, offsets)) {
if (prebuilt->select_lock_type != LOCK_NONE
&& set_also_gap_locks) {
@@ -3434,6 +3566,7 @@ rec_loop:
if (srv_locks_unsafe_for_binlog == FALSE) {
err = sel_set_rec_lock(rec, index,
+ offsets,
prebuilt->select_lock_type,
LOCK_GAP, thr);
}
@@ -3446,7 +3579,7 @@ rec_loop:
btr_pcur_store_position(pcur, &mtr);
- ret = DB_RECORD_NOT_FOUND;
+ err = DB_RECORD_NOT_FOUND;
/* ut_print_name(stderr, index->name);
fputs(" record not found 4\n", stderr); */
@@ -3465,27 +3598,27 @@ rec_loop:
is a non-delete marked record, then it is enough to lock its
existence with LOCK_REC_NOT_GAP. */
+ ulint lock_type;
+
if (!set_also_gap_locks
- || (unique_search && !rec_get_deleted_flag(rec))) {
- err = sel_set_rec_lock(rec, index,
- prebuilt->select_lock_type,
- LOCK_REC_NOT_GAP, thr);
+ || (unique_search && !rec_get_deleted_flag(rec, comp))) {
+ lock_type = LOCK_REC_NOT_GAP;
} else {
/* If innodb_locks_unsafe_for_binlog option is used,
- we lock only the record, i.e. next-key locking is
+ we lock only the record, i.e., next-key locking is
not used. */
- if (srv_locks_unsafe_for_binlog) {
- err = sel_set_rec_lock(rec, index,
- prebuilt->select_lock_type,
- LOCK_REC_NOT_GAP, thr);
+ if (srv_locks_unsafe_for_binlog) {
+ lock_type = LOCK_REC_NOT_GAP;
} else {
- err = sel_set_rec_lock(rec, index,
- prebuilt->select_lock_type,
- LOCK_ORDINARY, thr);
- }
+ lock_type = LOCK_ORDINARY;
+ }
}
-
+
+ err = sel_set_rec_lock(rec, index, offsets,
+ prebuilt->select_lock_type,
+ lock_type, thr);
+
if (err != DB_SUCCESS) {
goto lock_wait_or_error;
@@ -3508,7 +3641,7 @@ rec_loop:
if (srv_force_recovery < 5
&& !lock_clust_rec_cons_read_sees(rec, index,
- trx->read_view)) {
+ offsets, trx->read_view)) {
err = row_sel_build_prev_vers_for_mysql(
trx->read_view, clust_index,
@@ -3541,7 +3674,8 @@ rec_loop:
}
}
- if (rec_get_deleted_flag(rec) && !cons_read_requires_clust_rec) {
+ if (rec_get_deleted_flag(rec, comp)
+ && !cons_read_requires_clust_rec) {
/* The record is delete-marked: we can skip it if this is
not a consistent read which might see an earlier version
@@ -3577,7 +3711,7 @@ rec_loop:
goto next_rec;
}
- if (rec_get_deleted_flag(clust_rec)) {
+ if (rec_get_deleted_flag(clust_rec, comp)) {
/* The record is delete marked: we can skip it */
@@ -3589,6 +3723,15 @@ rec_loop:
}
}
+ if (prebuilt->need_to_access_clustered) {
+ ut_ad(rec == clust_rec || index == clust_index);
+ offsets = rec_get_offsets(rec, clust_index, offsets,
+ ULINT_UNDEFINED, &heap);
+ } else {
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+ }
+
/* We found a qualifying row */
if (prebuilt->n_rows_fetched >= MYSQL_FETCH_CACHE_THRESHOLD
@@ -3608,7 +3751,7 @@ rec_loop:
not cache rows because there the cursor is a scrollable
cursor. */
- row_sel_push_cache_row_for_mysql(prebuilt, rec);
+ row_sel_push_cache_row_for_mysql(prebuilt, rec, offsets);
if (prebuilt->n_fetch_cached == MYSQL_FETCH_CACHE_SIZE) {
@@ -3618,11 +3761,13 @@ rec_loop:
goto next_rec;
} else {
if (prebuilt->template_type == ROW_MYSQL_DUMMY_TEMPLATE) {
- ut_memcpy(buf + 4, rec - rec_get_extra_size(rec),
- rec_get_size(rec));
- mach_write_to_4(buf, rec_get_extra_size(rec) + 4);
+ memcpy(buf + 4, rec - rec_offs_extra_size(offsets),
+ rec_offs_size(offsets));
+ mach_write_to_4(buf,
+ rec_offs_extra_size(offsets) + 4);
} else {
- if (!row_sel_store_mysql_rec(buf, prebuilt, rec)) {
+ if (!row_sel_store_mysql_rec(buf, prebuilt,
+ rec, offsets)) {
err = DB_TOO_BIG_RECORD;
goto lock_wait_or_error;
@@ -3630,8 +3775,10 @@ rec_loop:
}
if (prebuilt->clust_index_was_generated) {
+ offsets = rec_get_offsets(index_rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
row_sel_store_row_id_to_prebuilt(prebuilt, index_rec,
- index);
+ index, offsets);
}
}
got_row:
@@ -3651,7 +3798,7 @@ got_row:
btr_pcur_store_position(pcur, &mtr);
}
- ret = DB_SUCCESS;
+ err = DB_SUCCESS;
goto normal_return;
@@ -3690,9 +3837,9 @@ next_rec:
btr_pcur_store_position(pcur, &mtr);
if (match_mode != 0) {
- ret = DB_RECORD_NOT_FOUND;
+ err = DB_RECORD_NOT_FOUND;
} else {
- ret = DB_END_OF_INDEX;
+ err = DB_END_OF_INDEX;
}
goto normal_return;
@@ -3716,8 +3863,10 @@ lock_wait_or_error:
que_thr_stop_for_mysql(thr);
+ thr->lock_state= QUE_THR_LOCK_ROW;
was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
-
+ thr->lock_state= QUE_THR_LOCK_NOLOCK;
+
if (was_lock_wait) {
mtr_start(&mtr);
@@ -3731,9 +3880,7 @@ lock_wait_or_error:
/* fputs("Using ", stderr);
dict_index_name_print(stderr, index);
fprintf(stderr, " cnt %lu ret value %lu err\n", cnt, err); */
- trx->op_info = "";
-
- return(err);
+ goto func_exit;
normal_return:
/*-------------------------------------------------------------*/
@@ -3744,19 +3891,22 @@ normal_return:
if (prebuilt->n_fetch_cached > 0) {
row_sel_pop_cached_row_for_mysql(buf, prebuilt);
- ret = DB_SUCCESS;
+ err = DB_SUCCESS;
}
/* fputs("Using ", stderr);
dict_index_name_print(stderr, index);
fprintf(stderr, " cnt %lu ret value %lu err\n", cnt, err); */
- if (ret == DB_SUCCESS) {
+ if (err == DB_SUCCESS) {
srv_n_rows_read++;
}
+func_exit:
trx->op_info = "";
-
- return(ret);
+ if (heap) {
+ mem_heap_free(heap);
+ }
+ return(err);
}
/***********************************************************************
diff --git a/innobase/row/row0umod.c b/innobase/row/row0umod.c
index e16d696314b..1cade0f304f 100644
--- a/innobase/row/row0umod.c
+++ b/innobase/row/row0umod.c
@@ -438,7 +438,7 @@ row_undo_mod_del_unmark_sec_and_undo_update(
dtuple_print(stderr, entry);
fputs("\n"
"InnoDB: record ", stderr);
- rec_print(stderr, btr_pcur_get_rec(&pcur));
+ rec_print(stderr, btr_pcur_get_rec(&pcur), index);
putc('\n', stderr);
trx_print(stderr, trx);
fputs("\n"
diff --git a/innobase/row/row0undo.c b/innobase/row/row0undo.c
index bc3cc8ea9f3..d994eab9873 100644
--- a/innobase/row/row0undo.c
+++ b/innobase/row/row0undo.c
@@ -151,6 +151,9 @@ row_undo_search_clust_to_pcur(
mtr_t mtr;
ibool ret;
rec_t* rec;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[100] = { 100, };
+ ulint* offsets = offsets_;
mtr_start(&mtr);
@@ -161,8 +164,11 @@ row_undo_search_clust_to_pcur(
rec = btr_pcur_get_rec(&(node->pcur));
+ offsets = rec_get_offsets(rec, clust_index, offsets,
+ ULINT_UNDEFINED, &heap);
+
if (!found || 0 != ut_dulint_cmp(node->roll_ptr,
- row_get_rec_roll_ptr(rec, clust_index))) {
+ row_get_rec_roll_ptr(rec, clust_index, offsets))) {
/* We must remove the reservation on the undo log record
BEFORE releasing the latch on the clustered index page: this
@@ -175,7 +181,7 @@ row_undo_search_clust_to_pcur(
ret = FALSE;
} else {
node->row = row_build(ROW_COPY_DATA, clust_index, rec,
- node->heap);
+ offsets, node->heap);
btr_pcur_store_position(&(node->pcur), &mtr);
ret = TRUE;
@@ -183,6 +189,9 @@ row_undo_search_clust_to_pcur(
btr_pcur_commit_specify_mtr(&(node->pcur), &mtr);
+ if (heap) {
+ mem_heap_free(heap);
+ }
return(ret);
}
diff --git a/innobase/row/row0upd.c b/innobase/row/row0upd.c
index 9192f6dc692..173912d6956 100644
--- a/innobase/row/row0upd.c
+++ b/innobase/row/row0upd.c
@@ -301,19 +301,20 @@ recovery. */
void
row_upd_rec_sys_fields_in_recovery(
/*===============================*/
- rec_t* rec, /* in: record */
- ulint pos, /* in: TRX_ID position in rec */
- dulint trx_id, /* in: transaction id */
- dulint roll_ptr)/* in: roll ptr of the undo log record */
+ rec_t* rec, /* in: record */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
+ ulint pos, /* in: TRX_ID position in rec */
+ dulint trx_id, /* in: transaction id */
+ dulint roll_ptr)/* in: roll ptr of the undo log record */
{
byte* field;
ulint len;
- field = rec_get_nth_field(rec, pos, &len);
+ field = rec_get_nth_field(rec, offsets, pos, &len);
ut_ad(len == DATA_TRX_ID_LEN);
trx_write_trx_id(field, trx_id);
- field = rec_get_nth_field(rec, pos + 1, &len);
+ field = rec_get_nth_field(rec, offsets, pos + 1, &len);
ut_ad(len == DATA_ROLL_PTR_LEN);
trx_write_roll_ptr(field, roll_ptr);
}
@@ -361,8 +362,8 @@ row_upd_changes_field_size_or_external(
/* out: TRUE if the update changes the size of
some field in index or the field is external
in rec or update */
- rec_t* rec, /* in: record in index */
dict_index_t* index, /* in: index */
+ const ulint* offsets,/* in: rec_get_offsets(rec, index) */
upd_t* update) /* in: update vector */
{
upd_field_t* upd_field;
@@ -372,6 +373,7 @@ row_upd_changes_field_size_or_external(
ulint n_fields;
ulint i;
+ ut_ad(rec_offs_validate(NULL, index, offsets));
n_fields = upd_get_n_fields(update);
for (i = 0; i < n_fields; i++) {
@@ -380,7 +382,7 @@ row_upd_changes_field_size_or_external(
new_val = &(upd_field->new_val);
new_len = new_val->len;
- if (new_len == UNIV_SQL_NULL) {
+ if (new_len == UNIV_SQL_NULL && !rec_offs_comp(offsets)) {
/* A bug fixed on Dec 31st, 2004: we looked at the
SQL NULL size from the wrong field! We may backport
this fix also to 4.0. The merge to 5.0 will be made
@@ -391,14 +393,14 @@ row_upd_changes_field_size_or_external(
upd_field->field_no));
}
- old_len = rec_get_nth_field_size(rec, upd_field->field_no);
-
+ old_len = rec_offs_nth_size(offsets, upd_field->field_no);
+
if (old_len != new_len) {
return(TRUE);
}
- if (rec_get_nth_field_extern_bit(rec, upd_field->field_no)) {
+ if (rec_offs_nth_extern(offsets, upd_field->field_no)) {
return(TRUE);
}
@@ -420,15 +422,18 @@ a clustered index */
void
row_upd_rec_in_place(
/*=================*/
- rec_t* rec, /* in/out: record where replaced */
- upd_t* update) /* in: update vector */
+ rec_t* rec, /* in/out: record where replaced */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
+ upd_t* update) /* in: update vector */
{
upd_field_t* upd_field;
dfield_t* new_val;
ulint n_fields;
ulint i;
- rec_set_info_bits(rec, update->info_bits);
+ ut_ad(rec_offs_validate(rec, NULL, offsets));
+
+ rec_set_info_bits(rec, rec_offs_comp(offsets), update->info_bits);
n_fields = upd_get_n_fields(update);
@@ -436,7 +441,7 @@ row_upd_rec_in_place(
upd_field = upd_get_nth_field(update, i);
new_val = &(upd_field->new_val);
- rec_set_nth_field(rec, upd_field->field_no,
+ rec_set_nth_field(rec, offsets, upd_field->field_no,
dfield_get_data(new_val),
dfield_get_len(new_val));
}
@@ -701,6 +706,8 @@ row_upd_build_sec_rec_difference_binary(
upd_t* update;
ulint n_diff;
ulint i;
+ ulint offsets_[10] = { 10, };
+ const ulint* offsets;
/* This function is used only for a secondary index */
ut_a(0 == (index->type & DICT_CLUSTERED));
@@ -708,10 +715,12 @@ row_upd_build_sec_rec_difference_binary(
update = upd_create(dtuple_get_n_fields(entry), heap);
n_diff = 0;
+ offsets = rec_get_offsets(rec, index, offsets_,
+ ULINT_UNDEFINED, &heap);
for (i = 0; i < dtuple_get_n_fields(entry); i++) {
- data = rec_get_nth_field(rec, i, &len);
+ data = rec_get_nth_field(rec, offsets, i, &len);
dfield = dtuple_get_nth_field(entry, i);
@@ -774,6 +783,8 @@ row_upd_build_difference_binary(
ulint trx_id_pos;
ibool extern_bit;
ulint i;
+ ulint offsets_[100] = { 100, };
+ const ulint* offsets;
/* This function is used only for a clustered index */
ut_a(index->type & DICT_CLUSTERED);
@@ -785,9 +796,12 @@ row_upd_build_difference_binary(
roll_ptr_pos = dict_index_get_sys_col_pos(index, DATA_ROLL_PTR);
trx_id_pos = dict_index_get_sys_col_pos(index, DATA_TRX_ID);
+ offsets = rec_get_offsets(rec, index, offsets_,
+ ULINT_UNDEFINED, &heap);
+
for (i = 0; i < dtuple_get_n_fields(entry); i++) {
- data = rec_get_nth_field(rec, i, &len);
+ data = rec_get_nth_field(rec, offsets, i, &len);
dfield = dtuple_get_nth_field(entry, i);
@@ -799,7 +813,7 @@ row_upd_build_difference_binary(
goto skip_compare;
}
- extern_bit = rec_get_nth_field_extern_bit(rec, i);
+ extern_bit = rec_offs_nth_extern(offsets, i);
if (extern_bit != upd_ext_vec_contains(ext_vec, n_ext_vec, i)
|| !dfield_data_is_binary_equal(dfield, len, data)) {
@@ -1123,6 +1137,7 @@ void
row_upd_copy_columns(
/*=================*/
rec_t* rec, /* in: record in a clustered index */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
sym_node_t* column) /* in: first column in a column list, or
NULL */
{
@@ -1130,7 +1145,7 @@ row_upd_copy_columns(
ulint len;
while (column) {
- data = rec_get_nth_field(rec,
+ data = rec_get_nth_field(rec, offsets,
column->field_nos[SYM_CLUST_FIELD_NO],
&len);
eval_node_copy_and_alloc_val(column, data, len);
@@ -1177,7 +1192,10 @@ row_upd_store_row(
dict_index_t* clust_index;
upd_t* update;
rec_t* rec;
-
+ mem_heap_t* heap = NULL;
+ ulint offsets_[100] = { 100, };
+ const ulint* offsets;
+
ut_ad(node->pcur->latch_mode != BTR_NO_LATCHES);
if (node->row != NULL) {
@@ -1189,10 +1207,12 @@ row_upd_store_row(
rec = btr_pcur_get_rec(node->pcur);
- node->row = row_build(ROW_COPY_DATA, clust_index, rec, node->heap);
-
+ offsets = rec_get_offsets(rec, clust_index, offsets_,
+ ULINT_UNDEFINED, &heap);
+ node->row = row_build(ROW_COPY_DATA, clust_index, rec, offsets,
+ node->heap);
node->ext_vec = mem_heap_alloc(node->heap, sizeof(ulint)
- * rec_get_n_fields(rec));
+ * rec_offs_n_fields(offsets));
if (node->is_delete) {
update = NULL;
} else {
@@ -1200,7 +1220,10 @@ row_upd_store_row(
}
node->n_ext_vec = btr_push_update_extern_fields(node->ext_vec,
- rec, update);
+ offsets, update);
+ if (heap) {
+ mem_heap_free(heap);
+ }
}
/***************************************************************
@@ -1253,7 +1276,7 @@ row_upd_sec_index_entry(
dtuple_print(stderr, entry);
fputs("\n"
"InnoDB: record ", stderr);
- rec_print(stderr, rec);
+ rec_print(stderr, rec, index);
putc('\n', stderr);
trx_print(stderr, trx);
@@ -1265,7 +1288,7 @@ row_upd_sec_index_entry(
delete marked if we return after a lock wait in
row_ins_index_entry below */
- if (!rec_get_deleted_flag(rec)) {
+ if (!rec_get_deleted_flag(rec, index->table->comp)) {
err = btr_cur_del_mark_set_sec_rec(0, btr_cur, TRUE,
thr, &mtr);
if (err == DB_SUCCESS && check_ref) {
@@ -1353,7 +1376,7 @@ row_upd_clust_rec_by_insert(
a foreign key constraint */
mtr_t* mtr) /* in: mtr; gets committed here */
{
- mem_heap_t* heap;
+ mem_heap_t* heap = NULL;
btr_pcur_t* pcur;
btr_cur_t* btr_cur;
trx_t* trx;
@@ -1370,12 +1393,12 @@ row_upd_clust_rec_by_insert(
btr_cur = btr_pcur_get_btr_cur(pcur);
if (node->state != UPD_NODE_INSERT_CLUSTERED) {
+ ulint offsets_[100] = { 100, };
err = btr_cur_del_mark_set_clust_rec(BTR_NO_LOCKING_FLAG,
btr_cur, TRUE, thr, mtr);
if (err != DB_SUCCESS) {
mtr_commit(mtr);
-
return(err);
}
@@ -1385,7 +1408,9 @@ row_upd_clust_rec_by_insert(
record is removed from the index tree, or updated. */
btr_cur_mark_extern_inherited_fields(btr_cur_get_rec(btr_cur),
- node->update, mtr);
+ rec_get_offsets(btr_cur_get_rec(btr_cur),
+ dict_table_get_first_index(table), offsets_,
+ ULINT_UNDEFINED, &heap), node->update, mtr);
if (check_ref) {
/* NOTE that the following call loses
the position of pcur ! */
@@ -1394,7 +1419,9 @@ row_upd_clust_rec_by_insert(
index, thr, mtr);
if (err != DB_SUCCESS) {
mtr_commit(mtr);
-
+ if (heap) {
+ mem_heap_free(heap);
+ }
return(err);
}
}
@@ -1403,10 +1430,11 @@ row_upd_clust_rec_by_insert(
mtr_commit(mtr);
+ if (!heap) {
+ heap = mem_heap_create(500);
+ }
node->state = UPD_NODE_INSERT_CLUSTERED;
- heap = mem_heap_create(500);
-
entry = row_build_index_entry(node->row, index, heap);
row_upd_index_replace_new_col_vals(entry, index, node->update, NULL);
@@ -1458,7 +1486,8 @@ row_upd_clust_rec(
pcur = node->pcur;
btr_cur = btr_pcur_get_btr_cur(pcur);
- ut_ad(FALSE == rec_get_deleted_flag(btr_pcur_get_rec(pcur)));
+ ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur),
+ index->table->comp));
/* Try optimistic updating of the record, keeping changes within
the page; we do not check locks because we assume the x-lock on the
@@ -1494,7 +1523,8 @@ row_upd_clust_rec(
ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr));
- ut_ad(FALSE == rec_get_deleted_flag(btr_pcur_get_rec(pcur)));
+ ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur),
+ index->table->comp));
err = btr_cur_pessimistic_update(BTR_NO_LOCKING_FLAG, btr_cur,
&big_rec, node->update,
@@ -1502,12 +1532,20 @@ row_upd_clust_rec(
mtr_commit(mtr);
if (err == DB_SUCCESS && big_rec) {
+ mem_heap_t* heap = NULL;
+ ulint offsets_[100] = { 100, };
+ rec_t* rec;
mtr_start(mtr);
+
ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr));
-
- err = btr_store_big_rec_extern_fields(index,
- btr_cur_get_rec(btr_cur),
- big_rec, mtr);
+ rec = btr_cur_get_rec(btr_cur);
+ err = btr_store_big_rec_extern_fields(index, rec,
+ rec_get_offsets(rec, index, offsets_,
+ ULINT_UNDEFINED, &heap),
+ big_rec, mtr);
+ if (heap) {
+ mem_heap_free(heap);
+ }
mtr_commit(mtr);
}
@@ -1591,7 +1629,11 @@ row_upd_clust_step(
ulint err;
mtr_t* mtr;
mtr_t mtr_buf;
-
+ rec_t* rec;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[100] = { 100, };
+ const ulint* offsets;
+
index = dict_table_get_first_index(node->table);
check_ref = row_upd_index_is_referenced(index, thr_get_trx(thr));
@@ -1647,14 +1689,16 @@ row_upd_clust_step(
}
}
+ rec = btr_pcur_get_rec(pcur);
+ offsets = rec_get_offsets(rec, index, offsets_,
+ ULINT_UNDEFINED, &heap);
+
if (!node->has_clust_rec_x_lock) {
err = lock_clust_rec_modify_check_and_lock(0,
- btr_pcur_get_rec(pcur),
- index, thr);
+ rec, index, offsets, thr);
if (err != DB_SUCCESS) {
mtr_commit(mtr);
-
- return(err);
+ goto exit_func;
}
}
@@ -1663,14 +1707,14 @@ row_upd_clust_step(
if (node->is_delete) {
err = row_upd_del_mark_clust_rec(node, index, thr, check_ref,
mtr);
- if (err != DB_SUCCESS) {
-
- return(err);
+ if (err == DB_SUCCESS) {
+ node->state = UPD_NODE_UPDATE_ALL_SEC;
+ node->index = dict_table_get_next_index(index);
+ }
+ exit_func:
+ if (heap) {
+ mem_heap_free(heap);
}
-
- node->state = UPD_NODE_UPDATE_ALL_SEC;
- node->index = dict_table_get_next_index(index);
-
return(err);
}
@@ -1680,16 +1724,18 @@ row_upd_clust_step(
if (!node->in_mysql_interface) {
/* Copy the necessary columns from clust_rec and calculate the
new values to set */
-
- row_upd_copy_columns(btr_pcur_get_rec(pcur),
+ row_upd_copy_columns(rec, offsets,
UT_LIST_GET_FIRST(node->columns));
row_upd_eval_new_vals(node->update);
}
+
+ if (heap) {
+ mem_heap_free(heap);
+ }
if (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE) {
err = row_upd_clust_rec(node, index, thr, mtr);
-
return(err);
}
@@ -1941,6 +1987,8 @@ row_upd_in_place_in_select(
btr_pcur_t* pcur;
btr_cur_t* btr_cur;
ulint err;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[100] = { 100, };
ut_ad(sel_node->select_will_do_update);
ut_ad(sel_node->latch_mode == BTR_MODIFY_LEAF);
@@ -1956,11 +2004,17 @@ row_upd_in_place_in_select(
/* Copy the necessary columns from clust_rec and calculate the new
values to set */
- row_upd_copy_columns(btr_pcur_get_rec(pcur),
- UT_LIST_GET_FIRST(node->columns));
+ row_upd_copy_columns(btr_pcur_get_rec(pcur), rec_get_offsets(
+ btr_pcur_get_rec(pcur), btr_cur->index, offsets_,
+ ULINT_UNDEFINED, &heap),
+ UT_LIST_GET_FIRST(node->columns));
+ if (heap) {
+ mem_heap_free(heap);
+ }
row_upd_eval_new_vals(node->update);
- ut_ad(FALSE == rec_get_deleted_flag(btr_pcur_get_rec(pcur)));
+ ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur),
+ btr_cur->index->table->comp));
ut_ad(node->cmpl_info & UPD_NODE_NO_SIZE_CHANGE);
ut_ad(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE);
diff --git a/innobase/row/row0vers.c b/innobase/row/row0vers.c
index bc17ede89e3..9ccaf32f2c2 100644
--- a/innobase/row/row0vers.c
+++ b/innobase/row/row0vers.c
@@ -41,10 +41,12 @@ row_vers_impl_x_locked_off_kernel(
transaction; NOTE that the kernel mutex is
temporarily released! */
rec_t* rec, /* in: record in a secondary index */
- dict_index_t* index) /* in: the secondary index */
+ dict_index_t* index, /* in: the secondary index */
+ const ulint* offsets)/* in: rec_get_offsets(rec, index) */
{
dict_index_t* clust_index;
rec_t* clust_rec;
+ ulint* clust_offsets;
rec_t* version;
rec_t* prev_version;
dulint trx_id;
@@ -59,6 +61,7 @@ row_vers_impl_x_locked_off_kernel(
ibool rec_del;
ulint err;
mtr_t mtr;
+ ibool comp;
#ifdef UNIV_SYNC_DEBUG
ut_ad(mutex_own(&kernel_mutex));
@@ -96,29 +99,33 @@ row_vers_impl_x_locked_off_kernel(
return(NULL);
}
- trx_id = row_get_rec_trx_id(clust_rec, clust_index);
+ heap = mem_heap_create(1024);
+ clust_offsets = rec_get_offsets(clust_rec, clust_index, NULL,
+ ULINT_UNDEFINED, &heap);
+ trx_id = row_get_rec_trx_id(clust_rec, clust_index, clust_offsets);
mtr_s_lock(&(purge_sys->latch), &mtr);
mutex_enter(&kernel_mutex);
+ trx = NULL;
if (!trx_is_active(trx_id)) {
/* The transaction that modified or inserted clust_rec is no
longer active: no implicit lock on rec */
-
- mtr_commit(&mtr);
-
- return(NULL);
+ goto exit_func;
}
- if (!lock_check_trx_id_sanity(trx_id, clust_rec, clust_index, TRUE)) {
+ if (!lock_check_trx_id_sanity(trx_id, clust_rec, clust_index,
+ clust_offsets, TRUE)) {
/* Corruption noticed: try to avoid a crash by returning */
-
- mtr_commit(&mtr);
-
- return(NULL);
+ goto exit_func;
}
+ comp = index->table->comp;
+ ut_ad(index->table == clust_index->table);
+ ut_ad(comp == page_is_comp(buf_frame_align(rec)));
+ ut_ad(comp == page_is_comp(buf_frame_align(clust_rec)));
+
/* We look up if some earlier version, which was modified by the trx_id
transaction, of the clustered index record would require rec to be in
a different state (delete marked or unmarked, or have different field
@@ -128,11 +135,10 @@ row_vers_impl_x_locked_off_kernel(
different state, then the trx_id transaction has not yet had time to
modify rec, and does not necessarily have an implicit x-lock on rec. */
- rec_del = rec_get_deleted_flag(rec);
+ rec_del = rec_get_deleted_flag(rec, comp);
trx = NULL;
version = clust_rec;
- heap = NULL;
for (;;) {
mutex_exit(&kernel_mutex);
@@ -146,18 +152,17 @@ row_vers_impl_x_locked_off_kernel(
heap2 = heap;
heap = mem_heap_create(1024);
-
err = trx_undo_prev_version_build(clust_rec, &mtr, version,
- clust_index, heap,
- &prev_version);
- if (heap2) {
- mem_heap_free(heap2); /* version was stored in heap2,
- if heap2 != NULL */
- }
+ clust_index, clust_offsets, heap,
+ &prev_version);
+ mem_heap_free(heap2); /* free version and clust_offsets */
if (prev_version) {
+ clust_offsets = rec_get_offsets(prev_version,
+ clust_index, NULL,
+ ULINT_UNDEFINED, &heap);
row = row_build(ROW_COPY_POINTERS, clust_index,
- prev_version, heap);
+ prev_version, clust_offsets, heap);
entry = row_build_index_entry(row, index, heap);
}
@@ -189,11 +194,11 @@ row_vers_impl_x_locked_off_kernel(
if prev_version would require rec to be in a different
state. */
- vers_del = rec_get_deleted_flag(prev_version);
+ vers_del = rec_get_deleted_flag(prev_version, comp);
/* We check if entry and rec are identified in the alphabetical
ordering */
- if (0 == cmp_dtuple_rec(entry, rec)) {
+ if (0 == cmp_dtuple_rec(entry, rec, offsets)) {
/* The delete marks of rec and prev_version should be
equal for rec to be in the state required by
prev_version */
@@ -211,7 +216,7 @@ row_vers_impl_x_locked_off_kernel(
dtuple_set_types_binary(entry,
dtuple_get_n_fields(entry));
- if (0 != cmp_dtuple_rec(entry, rec)) {
+ if (0 != cmp_dtuple_rec(entry, rec, offsets)) {
trx = trx_get_on_id(trx_id);
@@ -226,7 +231,8 @@ row_vers_impl_x_locked_off_kernel(
break;
}
- prev_trx_id = row_get_rec_trx_id(prev_version, clust_index);
+ prev_trx_id = row_get_rec_trx_id(prev_version, clust_index,
+ clust_offsets);
if (0 != ut_dulint_cmp(trx_id, prev_trx_id)) {
/* The versions modified by the trx_id transaction end
@@ -238,6 +244,7 @@ row_vers_impl_x_locked_off_kernel(
version = prev_version;
}/* for (;;) */
+exit_func:
mtr_commit(&mtr);
mem_heap_free(heap);
@@ -297,12 +304,14 @@ row_vers_old_has_index_entry(
rec_t* version;
rec_t* prev_version;
dict_index_t* clust_index;
+ ulint* clust_offsets;
mem_heap_t* heap;
mem_heap_t* heap2;
dtuple_t* row;
dtuple_t* entry;
ulint err;
-
+ ibool comp;
+
ut_ad(mtr_memo_contains(mtr, buf_block_align(rec), MTR_MEMO_PAGE_X_FIX)
|| mtr_memo_contains(mtr, buf_block_align(rec),
MTR_MEMO_PAGE_S_FIX));
@@ -313,10 +322,15 @@ row_vers_old_has_index_entry(
clust_index = dict_table_get_first_index(index->table);
- if (also_curr && !rec_get_deleted_flag(rec)) {
+ comp = index->table->comp;
+ ut_ad(comp == page_is_comp(buf_frame_align(rec)));
+ heap = mem_heap_create(1024);
+ clust_offsets = rec_get_offsets(rec, clust_index, NULL,
+ ULINT_UNDEFINED, &heap);
- heap = mem_heap_create(1024);
- row = row_build(ROW_COPY_POINTERS, clust_index, rec, heap);
+ if (also_curr && !rec_get_deleted_flag(rec, comp)) {
+ row = row_build(ROW_COPY_POINTERS, clust_index,
+ rec, clust_offsets, heap);
entry = row_build_index_entry(row, index, heap);
/* NOTE that we cannot do the comparison as binary
@@ -331,24 +345,17 @@ row_vers_old_has_index_entry(
return(TRUE);
}
-
- mem_heap_free(heap);
}
version = rec;
- heap = NULL;
for (;;) {
heap2 = heap;
heap = mem_heap_create(1024);
-
err = trx_undo_prev_version_build(rec, mtr, version,
- clust_index, heap,
- &prev_version);
- if (heap2) {
- mem_heap_free(heap2); /* version was stored in heap2,
- if heap2 != NULL */
- }
+ clust_index, clust_offsets, heap,
+ &prev_version);
+ mem_heap_free(heap2); /* free version and clust_offsets */
if (err != DB_SUCCESS || !prev_version) {
/* Versions end here */
@@ -358,9 +365,12 @@ row_vers_old_has_index_entry(
return(FALSE);
}
- if (!rec_get_deleted_flag(prev_version)) {
+ clust_offsets = rec_get_offsets(prev_version, clust_index,
+ NULL, ULINT_UNDEFINED, &heap);
+
+ if (!rec_get_deleted_flag(prev_version, comp)) {
row = row_build(ROW_COPY_POINTERS, clust_index,
- prev_version, heap);
+ prev_version, clust_offsets, heap);
entry = row_build_index_entry(row, index, heap);
/* NOTE that we cannot do the comparison as binary
@@ -412,6 +422,7 @@ row_vers_build_for_consistent_read(
mem_heap_t* heap2;
byte* buf;
ulint err;
+ ulint* offsets;
ut_ad(index->type & DICT_CLUSTERED);
ut_ad(mtr_memo_contains(mtr, buf_block_align(rec), MTR_MEMO_PAGE_X_FIX)
@@ -420,22 +431,23 @@ row_vers_build_for_consistent_read(
#ifdef UNIV_SYNC_DEBUG
ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED));
#endif /* UNIV_SYNC_DEBUG */
- ut_ad(!read_view_sees_trx_id(view, row_get_rec_trx_id(rec, index)));
+
+ heap = mem_heap_create(1024);
+ offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap);
+
+ ut_ad(!read_view_sees_trx_id(view,
+ row_get_rec_trx_id(rec, index, offsets)));
rw_lock_s_lock(&(purge_sys->latch));
version = rec;
- heap = NULL;
for (;;) {
heap2 = heap;
heap = mem_heap_create(1024);
err = trx_undo_prev_version_build(rec, mtr, version, index,
- heap, &prev_version);
- if (heap2) {
- mem_heap_free(heap2); /* version was stored in heap2,
- if heap2 != NULL */
- }
+ offsets, heap, &prev_version);
+ mem_heap_free(heap2); /* free version and offsets */
if (err != DB_SUCCESS) {
break;
@@ -449,16 +461,17 @@ row_vers_build_for_consistent_read(
break;
}
- prev_trx_id = row_get_rec_trx_id(prev_version, index);
+ offsets = rec_get_offsets(prev_version, index, NULL,
+ ULINT_UNDEFINED, &heap);
+ prev_trx_id = row_get_rec_trx_id(prev_version, index, offsets);
if (read_view_sees_trx_id(view, prev_trx_id)) {
/* The view already sees this version: we can copy
it to in_heap and return */
- buf = mem_heap_alloc(in_heap, rec_get_size(
- prev_version));
- *old_vers = rec_copy(buf, prev_version);
+ buf = mem_heap_alloc(in_heap, rec_offs_size(offsets));
+ *old_vers = rec_copy(buf, prev_version, offsets);
err = DB_SUCCESS;
break;