2469
2469
ut_ad(len != UNIV_SQL_NULL);
2470
2470
UNIV_MEM_ASSERT_RW(data, len);
2471
UNIV_MEM_ASSERT_W(dest, templ->mysql_col_len);
2472
UNIV_MEM_INVALID(dest, templ->mysql_col_len);
2472
2474
if (templ->type == DATA_INT) {
2473
2475
/* Convert integer data from Innobase to a little-endian
2503
2505
dest = row_mysql_store_true_var_len(
2504
2506
dest, len, templ->mysql_length_bytes);
2507
/* Copy the actual data. Leave the rest of the
2508
buffer uninitialized. */
2509
ut_memcpy(dest, data, len);
2507
2513
/* Copy the actual data */
2508
2514
ut_memcpy(dest, data, len);
2510
/* Pad with trailing spaces. We pad with spaces also the
2511
unused end of a >= 5.0.3 true VARCHAR column, just in case
2512
MySQL expects its contents to be deterministic. */
2516
/* Pad with trailing spaces. */
2514
2518
pad_ptr = dest + len;
2601
2605
row_prebuilt_t* prebuilt, /* in: prebuilt struct */
2602
2606
rec_t* rec, /* in: Innobase record in the index
2603
2607
which was described in prebuilt's
2608
template, or in the clustered index;
2609
must be protected by a page latch */
2610
ibool rec_clust, /* in: TRUE if rec is in the clustered
2611
index instead of prebuilt->index */
2605
2612
const ulint* offsets) /* in: array returned by
2606
rec_get_offsets() */
2613
rec_get_offsets(rec) */
2608
mysql_row_templ_t* templ;
2609
2615
mem_heap_t* extern_field_heap = NULL;
2610
2616
mem_heap_t* heap;
2615
2619
ut_ad(prebuilt->mysql_template);
2616
2620
ut_ad(prebuilt->default_rec);
2617
2621
ut_ad(rec_offs_validate(rec, NULL, offsets));
2622
ut_ad(!rec_get_deleted_flag(rec, rec_offs_comp(offsets)));
2619
2624
if (UNIV_LIKELY_NULL(prebuilt->blob_heap)) {
2620
2625
mem_heap_free(prebuilt->blob_heap);
2621
2626
prebuilt->blob_heap = NULL;
2624
/* init null bytes with default values as they might be
2625
left uninitialized in some cases and this uninited bytes
2626
might be copied into mysql record buffer that leads to
2627
valgrind warnings */
2628
memcpy(mysql_rec, prebuilt->default_rec, prebuilt->null_bitmap_len);
2630
2629
for (i = 0; i < prebuilt->n_template; i++) {
2632
templ = prebuilt->mysql_template + i;
2634
if (UNIV_UNLIKELY(rec_offs_nth_extern(offsets,
2635
templ->rec_field_no))) {
2631
const mysql_row_templ_t*templ = prebuilt->mysql_template + i;
2636
field_no = rec_clust
2637
? templ->clust_rec_field_no : templ->rec_field_no;
2639
if (UNIV_UNLIKELY(rec_offs_nth_extern(offsets, field_no))) {
2637
2641
/* Copy an externally stored field to the temporary
2658
2662
causes an assert */
2660
2664
data = btr_rec_copy_externally_stored_field(
2661
rec, offsets, templ->rec_field_no,
2665
rec, offsets, field_no, &len, heap);
2664
2667
ut_a(len != UNIV_SQL_NULL);
2666
2669
/* Field is stored in the row. */
2668
data = rec_get_nth_field(rec, offsets,
2669
templ->rec_field_no, &len);
2671
data = rec_get_nth_field(rec, offsets, field_no, &len);
2671
2673
if (UNIV_UNLIKELY(templ->type == DATA_BLOB)
2672
2674
&& len != UNIV_SQL_NULL) {
3017
3019
/************************************************************************
3020
Copies a cached field for MySQL from the fetch cache. */
3023
row_sel_copy_cached_field_for_mysql(
3024
/*================================*/
3025
byte* buf, /* in/out: row buffer */
3026
byte* cache, /* in: cached row */
3027
const mysql_row_templ_t*templ) /* in: column template */
3031
buf += templ->mysql_col_offset;
3032
cache += templ->mysql_col_offset;
3034
UNIV_MEM_ASSERT_W(buf, templ->mysql_col_len);
3036
if (templ->mysql_type == DATA_MYSQL_TRUE_VARCHAR
3037
&& templ->type != DATA_INT) {
3038
/* Check for != DATA_INT to make sure we do
3039
not treat MySQL ENUM or SET as a true VARCHAR!
3040
Find the actual length of the true VARCHAR field. */
3041
row_mysql_read_true_varchar(
3042
&len, cache, templ->mysql_length_bytes);
3043
len += templ->mysql_length_bytes;
3044
UNIV_MEM_INVALID(buf, templ->mysql_col_len);
3046
len = templ->mysql_col_len;
3049
ut_memcpy(buf, cache, len);
3052
/************************************************************************
3018
3053
Pops a cached row for MySQL from the fetch cache. */
3025
3060
row_prebuilt_t* prebuilt) /* in: prebuilt struct */
3028
mysql_row_templ_t* templ;
3063
const mysql_row_templ_t*templ;
3029
3064
byte* cached_rec;
3030
3065
ut_ad(prebuilt->n_fetch_cached > 0);
3031
3066
ut_ad(prebuilt->mysql_prefix_len <= prebuilt->mysql_row_len);
3068
UNIV_MEM_ASSERT_W(buf, prebuilt->mysql_row_len);
3070
cached_rec = prebuilt->fetch_cache[prebuilt->fetch_cache_first];
3033
3072
if (UNIV_UNLIKELY(prebuilt->keep_other_fields_on_keyread)) {
3034
3073
/* Copy cache record field by field, don't touch fields that
3035
3074
are not covered by current key */
3036
cached_rec = prebuilt->fetch_cache[
3037
prebuilt->fetch_cache_first];
3039
3076
for (i = 0; i < prebuilt->n_template; i++) {
3040
3077
templ = prebuilt->mysql_template + i;
3041
#if 0 /* Some of the cached_rec may legitimately be uninitialized. */
3042
UNIV_MEM_ASSERT_RW(cached_rec
3043
+ templ->mysql_col_offset,
3044
templ->mysql_col_len);
3046
ut_memcpy(buf + templ->mysql_col_offset,
3047
cached_rec + templ->mysql_col_offset,
3048
templ->mysql_col_len);
3078
row_sel_copy_cached_field_for_mysql(
3079
buf, cached_rec, templ);
3049
3080
/* Copy NULL bit of the current field from cached_rec
3051
3082
if (templ->mysql_null_bit_mask) {
3055
3086
& (byte)templ->mysql_null_bit_mask;
3060
#if 0 /* Some of the cached_rec may legitimately be uninitialized. */
3061
UNIV_MEM_ASSERT_RW(prebuilt->fetch_cache
3062
[prebuilt->fetch_cache_first],
3063
prebuilt->mysql_prefix_len);
3066
prebuilt->fetch_cache[prebuilt->fetch_cache_first],
3067
prebuilt->mysql_prefix_len);
3089
} else if (prebuilt->mysql_prefix_len > 63) {
3090
/* The record is long. Copy it field by field, in case
3091
there are some long VARCHAR column of which only a
3092
small length is being used. */
3093
UNIV_MEM_INVALID(buf, prebuilt->mysql_prefix_len);
3095
/* First copy the NULL bits. */
3096
ut_memcpy(buf, cached_rec, prebuilt->null_bitmap_len);
3097
/* Then copy the requested fields. */
3099
for (i = 0; i < prebuilt->n_template; i++) {
3100
row_sel_copy_cached_field_for_mysql(
3101
buf, cached_rec, prebuilt->mysql_template + i);
3104
ut_memcpy(buf, cached_rec, prebuilt->mysql_prefix_len);
3069
3107
prebuilt->n_fetch_cached--;
3070
3108
prebuilt->fetch_cache_first++;
3081
3119
row_sel_push_cache_row_for_mysql(
3082
3120
/*=============================*/
3083
3121
row_prebuilt_t* prebuilt, /* in: prebuilt struct */
3084
rec_t* rec, /* in: record to push */
3085
const ulint* offsets) /* in: rec_get_offsets() */
3122
rec_t* rec, /* in: Innobase record in the index
3123
which was described in prebuilt's
3124
template, or in the clustered index */
3125
ibool rec_clust, /* in: TRUE if rec is in the clustered
3126
index instead of prebuilt->index */
3127
const ulint* offsets) /* in: rec_get_offsets(rec) */
3090
3132
ut_ad(prebuilt->n_fetch_cached < MYSQL_FETCH_CACHE_SIZE);
3091
3133
ut_ad(rec_offs_validate(rec, NULL, offsets));
3134
ut_ad(!rec_get_deleted_flag(rec, rec_offs_comp(offsets)));
3092
3135
ut_a(!prebuilt->templ_contains_blob);
3094
3137
if (prebuilt->fetch_cache[0] == NULL) {
3117
3160
if (UNIV_UNLIKELY(!row_sel_store_mysql_rec(
3118
3161
prebuilt->fetch_cache[
3119
3162
prebuilt->n_fetch_cached],
3120
prebuilt, rec, offsets))) {
3163
prebuilt, rec, rec_clust, offsets))) {
3600
3645
clust_index = dict_table_get_first_index(index->table);
3647
/* Do some start-of-statement preparations */
3649
if (!prebuilt->sql_stat_start) {
3650
/* No need to set an intention lock or assign a read view */
3652
if (trx->read_view == NULL
3653
&& prebuilt->select_lock_type == LOCK_NONE) {
3655
fputs("InnoDB: Error: MySQL is trying to"
3656
" perform a consistent read\n"
3657
"InnoDB: but the read view is not assigned!\n",
3659
trx_print(stderr, trx, 600);
3660
fputc('\n', stderr);
3663
} else if (prebuilt->select_lock_type == LOCK_NONE) {
3664
/* This is a consistent read */
3665
/* Assign a read view for the query */
3667
trx_assign_read_view(trx);
3668
prebuilt->sql_stat_start = FALSE;
3671
err = lock_table(0, index->table,
3672
prebuilt->select_lock_type == LOCK_S
3673
? LOCK_IS : LOCK_IX, thr);
3675
if (err != DB_SUCCESS) {
3677
table_lock_waited = TRUE;
3678
goto lock_table_wait;
3680
prebuilt->sql_stat_start = FALSE;
3683
/* Open or restore index cursor position */
3602
3685
if (UNIV_LIKELY(direction != 0)) {
3603
3686
ibool need_to_process = sel_restore_position_for_mysql(
3604
3687
&same_user_rec, BTR_SEARCH_LEAF,
3677
if (!prebuilt->sql_stat_start) {
3678
/* No need to set an intention lock or assign a read view */
3680
if (trx->read_view == NULL
3681
&& prebuilt->select_lock_type == LOCK_NONE) {
3683
fputs("InnoDB: Error: MySQL is trying to"
3684
" perform a consistent read\n"
3685
"InnoDB: but the read view is not assigned!\n",
3687
trx_print(stderr, trx, 600);
3688
fputc('\n', stderr);
3691
} else if (prebuilt->select_lock_type == LOCK_NONE) {
3692
/* This is a consistent read */
3693
/* Assign a read view for the query */
3695
trx_assign_read_view(trx);
3696
prebuilt->sql_stat_start = FALSE;
3699
if (prebuilt->select_lock_type == LOCK_S) {
3700
lock_mode = LOCK_IS;
3702
lock_mode = LOCK_IX;
3704
err = lock_table(0, index->table, lock_mode, thr);
3706
if (err != DB_SUCCESS) {
3708
goto lock_wait_or_error;
3710
prebuilt->sql_stat_start = FALSE;
3714
3761
/*-------------------------------------------------------------*/
3715
3762
/* PHASE 4: Look for matching records in a loop */
4239
if (prebuilt->need_to_access_clustered) {
4241
result_rec = clust_rec;
4243
ut_ad(rec_offs_validate(result_rec, clust_index,
4246
/* We used 'offsets' for the clust rec, recalculate
4248
offsets = rec_get_offsets(rec, index, offsets,
4249
ULINT_UNDEFINED, &heap);
4286
result_rec = clust_rec;
4287
ut_ad(rec_offs_validate(result_rec, clust_index, offsets));
4253
4289
result_rec = rec;
4259
4295
ut_ad(rec_offs_validate(result_rec,
4260
4296
result_rec != rec ? clust_index : index,
4298
ut_ad(!rec_get_deleted_flag(result_rec, comp));
4263
4300
if ((match_mode == ROW_SEL_EXACT
4264
4301
|| prebuilt->n_rows_fetched >= MYSQL_FETCH_CACHE_THRESHOLD)
4281
4318
row_sel_push_cache_row_for_mysql(prebuilt, result_rec,
4319
result_rec != rec, offsets);
4283
4320
if (prebuilt->n_fetch_cached == MYSQL_FETCH_CACHE_SIZE) {
4290
if (prebuilt->template_type == ROW_MYSQL_DUMMY_TEMPLATE) {
4328
(prebuilt->template_type == ROW_MYSQL_DUMMY_TEMPLATE)) {
4329
/* CHECK TABLE: fetch the row */
4331
if (result_rec != rec
4332
&& !prebuilt->need_to_access_clustered) {
4333
/* We used 'offsets' for the clust
4334
rec, recalculate them for 'rec' */
4335
offsets = rec_get_offsets(rec, index, offsets,
4291
4341
memcpy(buf + 4, result_rec
4292
4342
- rec_offs_extra_size(offsets),
4293
4343
rec_offs_size(offsets));
4294
4344
mach_write_to_4(buf,
4295
4345
rec_offs_extra_size(offsets) + 4);
4297
if (!row_sel_store_mysql_rec(buf, prebuilt,
4298
result_rec, offsets)) {
4347
/* Returning a row to MySQL */
4349
if (!row_sel_store_mysql_rec(buf, prebuilt, result_rec,
4299
4352
err = DB_TOO_BIG_RECORD;
4301
4354
goto lock_wait_or_error;
4425
4479
thr->lock_state = QUE_THR_LOCK_NOLOCK;
4426
4480
mtr_start(&mtr);
4482
/* Table lock waited, go try to obtain table lock
4484
if (table_lock_waited) {
4485
table_lock_waited = FALSE;
4487
goto wait_table_again;
4428
4490
sel_restore_position_for_mysql(&same_user_rec,
4429
4491
BTR_SEARCH_LEAF, pcur,
4430
4492
moves_up, &mtr);