~ubuntu-branches/ubuntu/maverick/mysql-5.1/maverick-proposed

« back to all changes in this revision

Viewing changes to storage/innobase/row/row0sel.c

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2012-02-22 14:16:05 UTC
  • mto: This revision was merged to the branch mainline in revision 20.
  • Revision ID: package-import@ubuntu.com-20120222141605-nxlu9yzc6attylc2
Tags: upstream-5.1.61
ImportĀ upstreamĀ versionĀ 5.1.61

Show diffs side-by-side

added added

removed removed

Lines of Context:
2468
2468
 
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);
2471
2473
 
2472
2474
        if (templ->type == DATA_INT) {
2473
2475
                /* Convert integer data from Innobase to a little-endian
2502
2504
 
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);
 
2510
                        return;
2505
2511
                }
2506
2512
 
2507
2513
                /* Copy the actual data */
2508
2514
                ut_memcpy(dest, data, len);
2509
2515
 
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. */
2513
2517
 
2514
2518
                pad_ptr = dest + len;
2515
2519
 
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
2604
 
                                        template */
 
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) */
2607
2614
{
2608
 
        mysql_row_templ_t*      templ;
2609
2615
        mem_heap_t*             extern_field_heap       = NULL;
2610
2616
        mem_heap_t*             heap;
2611
 
        byte*                   data;
2612
 
        ulint                   len;
2613
2617
        ulint                   i;
2614
2618
 
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)));
2618
2623
 
2619
2624
        if (UNIV_LIKELY_NULL(prebuilt->blob_heap)) {
2620
2625
                mem_heap_free(prebuilt->blob_heap);
2621
2626
                prebuilt->blob_heap = NULL;
2622
2627
        }
2623
2628
 
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);
2629
 
 
2630
2629
        for (i = 0; i < prebuilt->n_template; i++) {
2631
2630
 
2632
 
                templ = prebuilt->mysql_template + i;
2633
 
 
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;
 
2632
                byte*                   data;
 
2633
                ulint                   len;
 
2634
                ulint                   field_no;
 
2635
 
 
2636
                field_no = rec_clust
 
2637
                        ? templ->clust_rec_field_no : templ->rec_field_no;
 
2638
 
 
2639
                if (UNIV_UNLIKELY(rec_offs_nth_extern(offsets, field_no))) {
2636
2640
 
2637
2641
                        /* Copy an externally stored field to the temporary
2638
2642
                        heap */
2658
2662
                        causes an assert */
2659
2663
 
2660
2664
                        data = btr_rec_copy_externally_stored_field(
2661
 
                                rec, offsets, templ->rec_field_no,
2662
 
                                &len, heap);
 
2665
                                rec, offsets, field_no, &len, heap);
2663
2666
 
2664
2667
                        ut_a(len != UNIV_SQL_NULL);
2665
2668
                } else {
2666
2669
                        /* Field is stored in the row. */
2667
2670
 
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);
2670
2672
 
2671
2673
                        if (UNIV_UNLIKELY(templ->type == DATA_BLOB)
2672
2674
                            && len != UNIV_SQL_NULL) {
3015
3017
}
3016
3018
 
3017
3019
/************************************************************************
 
3020
Copies a cached field for MySQL from the fetch cache. */
 
3021
static
 
3022
void
 
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 */
 
3028
{
 
3029
        ulint   len;
 
3030
 
 
3031
        buf += templ->mysql_col_offset;
 
3032
        cache += templ->mysql_col_offset;
 
3033
 
 
3034
        UNIV_MEM_ASSERT_W(buf, templ->mysql_col_len);
 
3035
 
 
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);
 
3045
        } else {
 
3046
                len = templ->mysql_col_len;
 
3047
        }
 
3048
 
 
3049
        ut_memcpy(buf, cache, len);
 
3050
}
 
3051
 
 
3052
/************************************************************************
3018
3053
Pops a cached row for MySQL from the fetch cache. */
3019
3054
UNIV_INLINE
3020
3055
void
3025
3060
        row_prebuilt_t* prebuilt)       /* in: prebuilt struct */
3026
3061
{
3027
3062
        ulint                   i;
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);
3032
3067
 
 
3068
        UNIV_MEM_ASSERT_W(buf, prebuilt->mysql_row_len);
 
3069
 
 
3070
        cached_rec = prebuilt->fetch_cache[prebuilt->fetch_cache_first];
 
3071
 
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];
3038
3075
 
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);
3045
 
#endif
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
3050
3081
                        to buf */
3051
3082
                        if (templ->mysql_null_bit_mask) {
3055
3086
                                        & (byte)templ->mysql_null_bit_mask;
3056
3087
                        }
3057
3088
                }
3058
 
        }
3059
 
        else {
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);
3064
 
#endif
3065
 
                ut_memcpy(buf,
3066
 
                          prebuilt->fetch_cache[prebuilt->fetch_cache_first],
3067
 
                          prebuilt->mysql_prefix_len);
3068
 
        }
 
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);
 
3094
 
 
3095
                /* First copy the NULL bits. */
 
3096
                ut_memcpy(buf, cached_rec, prebuilt->null_bitmap_len);
 
3097
                /* Then copy the requested fields. */
 
3098
 
 
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);
 
3102
                }
 
3103
        } else {
 
3104
                ut_memcpy(buf, cached_rec, prebuilt->mysql_prefix_len);
 
3105
        }
 
3106
 
3069
3107
        prebuilt->n_fetch_cached--;
3070
3108
        prebuilt->fetch_cache_first++;
3071
3109
 
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) */
3086
3128
{
3087
3129
        byte*   buf;
3088
3130
        ulint   i;
3089
3131
 
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);
3093
3136
 
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))) {
3121
3164
                ut_error;
3122
3165
        }
3123
3166
 
3259
3302
        mem_heap_t*     heap                            = NULL;
3260
3303
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
3261
3304
        ulint*          offsets                         = offsets_;
 
3305
        ibool           table_lock_waited               = FALSE;
3262
3306
 
3263
3307
        *offsets_ = (sizeof offsets_) / sizeof *offsets_;
3264
3308
 
3505
3549
                                                         rec, offsets));
3506
3550
#endif
3507
3551
                                if (!row_sel_store_mysql_rec(buf, prebuilt,
3508
 
                                                             rec, offsets)) {
 
3552
                                                             rec, FALSE,
 
3553
                                                             offsets)) {
3509
3554
                                        err = DB_TOO_BIG_RECORD;
3510
3555
 
3511
3556
                                        /* We let the main loop to do the
3599
3644
 
3600
3645
        clust_index = dict_table_get_first_index(index->table);
3601
3646
 
 
3647
        /* Do some start-of-statement preparations */
 
3648
 
 
3649
        if (!prebuilt->sql_stat_start) {
 
3650
                /* No need to set an intention lock or assign a read view */
 
3651
 
 
3652
                if (trx->read_view == NULL
 
3653
                    && prebuilt->select_lock_type == LOCK_NONE) {
 
3654
 
 
3655
                        fputs("InnoDB: Error: MySQL is trying to"
 
3656
                              " perform a consistent read\n"
 
3657
                              "InnoDB: but the read view is not assigned!\n",
 
3658
                              stderr);
 
3659
                        trx_print(stderr, trx, 600);
 
3660
                        fputc('\n', stderr);
 
3661
                        ut_error;
 
3662
                }
 
3663
        } else if (prebuilt->select_lock_type == LOCK_NONE) {
 
3664
                /* This is a consistent read */
 
3665
                /* Assign a read view for the query */
 
3666
 
 
3667
                trx_assign_read_view(trx);
 
3668
                prebuilt->sql_stat_start = FALSE;
 
3669
        } else {
 
3670
wait_table_again:
 
3671
                err = lock_table(0, index->table,
 
3672
                                 prebuilt->select_lock_type == LOCK_S
 
3673
                                 ? LOCK_IS : LOCK_IX, thr);
 
3674
 
 
3675
                if (err != DB_SUCCESS) {
 
3676
 
 
3677
                        table_lock_waited = TRUE;
 
3678
                        goto lock_table_wait;
 
3679
                }
 
3680
                prebuilt->sql_stat_start = FALSE;
 
3681
        }
 
3682
 
 
3683
        /* Open or restore index cursor position */
 
3684
 
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,
3674
3757
                }
3675
3758
        }
3676
3759
 
3677
 
        if (!prebuilt->sql_stat_start) {
3678
 
                /* No need to set an intention lock or assign a read view */
3679
 
 
3680
 
                if (trx->read_view == NULL
3681
 
                    && prebuilt->select_lock_type == LOCK_NONE) {
3682
 
 
3683
 
                        fputs("InnoDB: Error: MySQL is trying to"
3684
 
                              " perform a consistent read\n"
3685
 
                              "InnoDB: but the read view is not assigned!\n",
3686
 
                              stderr);
3687
 
                        trx_print(stderr, trx, 600);
3688
 
                        fputc('\n', stderr);
3689
 
                        ut_a(0);
3690
 
                }
3691
 
        } else if (prebuilt->select_lock_type == LOCK_NONE) {
3692
 
                /* This is a consistent read */
3693
 
                /* Assign a read view for the query */
3694
 
 
3695
 
                trx_assign_read_view(trx);
3696
 
                prebuilt->sql_stat_start = FALSE;
3697
 
        } else {
3698
 
                ulint   lock_mode;
3699
 
                if (prebuilt->select_lock_type == LOCK_S) {
3700
 
                        lock_mode = LOCK_IS;
3701
 
                } else {
3702
 
                        lock_mode = LOCK_IX;
3703
 
                }
3704
 
                err = lock_table(0, index->table, lock_mode, thr);
3705
 
 
3706
 
                if (err != DB_SUCCESS) {
3707
 
 
3708
 
                        goto lock_wait_or_error;
3709
 
                }
3710
 
                prebuilt->sql_stat_start = FALSE;
3711
 
        }
3712
 
 
3713
3760
rec_loop:
3714
3761
        /*-------------------------------------------------------------*/
3715
3762
        /* PHASE 4: Look for matching records in a loop */
4236
4283
                        goto next_rec;
4237
4284
                }
4238
4285
 
4239
 
                if (prebuilt->need_to_access_clustered) {
4240
 
 
4241
 
                        result_rec = clust_rec;
4242
 
 
4243
 
                        ut_ad(rec_offs_validate(result_rec, clust_index,
4244
 
                                                offsets));
4245
 
                } else {
4246
 
                        /* We used 'offsets' for the clust rec, recalculate
4247
 
                        them for 'rec' */
4248
 
                        offsets = rec_get_offsets(rec, index, offsets,
4249
 
                                                  ULINT_UNDEFINED, &heap);
4250
 
                        result_rec = rec;
4251
 
                }
 
4286
                result_rec = clust_rec;
 
4287
                ut_ad(rec_offs_validate(result_rec, clust_index, offsets));
4252
4288
        } else {
4253
4289
                result_rec = rec;
4254
4290
        }
4259
4295
        ut_ad(rec_offs_validate(result_rec,
4260
4296
                                result_rec != rec ? clust_index : index,
4261
4297
                                offsets));
 
4298
        ut_ad(!rec_get_deleted_flag(result_rec, comp));
4262
4299
 
4263
4300
        if ((match_mode == ROW_SEL_EXACT
4264
4301
             || prebuilt->n_rows_fetched >= MYSQL_FETCH_CACHE_THRESHOLD)
4279
4316
                cursor. */
4280
4317
 
4281
4318
                row_sel_push_cache_row_for_mysql(prebuilt, result_rec,
4282
 
                                                 offsets);
 
4319
                                                 result_rec != rec, offsets);
4283
4320
                if (prebuilt->n_fetch_cached == MYSQL_FETCH_CACHE_SIZE) {
4284
4321
 
4285
4322
                        goto got_row;
4287
4324
 
4288
4325
                goto next_rec;
4289
4326
        } else {
4290
 
                if (prebuilt->template_type == ROW_MYSQL_DUMMY_TEMPLATE) {
 
4327
                if (UNIV_UNLIKELY
 
4328
                    (prebuilt->template_type == ROW_MYSQL_DUMMY_TEMPLATE)) {
 
4329
                        /* CHECK TABLE: fetch the row */
 
4330
 
 
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,
 
4336
                                                          ULINT_UNDEFINED,
 
4337
                                                          &heap);
 
4338
                                result_rec = rec;
 
4339
                        }
 
4340
 
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);
4296
4346
                } else {
4297
 
                        if (!row_sel_store_mysql_rec(buf, prebuilt,
4298
 
                                                     result_rec, offsets)) {
 
4347
                        /* Returning a row to MySQL */
 
4348
 
 
4349
                        if (!row_sel_store_mysql_rec(buf, prebuilt, result_rec,
 
4350
                                                     result_rec != rec,
 
4351
                                                     offsets)) {
4299
4352
                                err = DB_TOO_BIG_RECORD;
4300
4353
 
4301
4354
                                goto lock_wait_or_error;
4408
4461
 
4409
4462
        btr_pcur_store_position(pcur, &mtr);
4410
4463
 
 
4464
lock_table_wait:
4411
4465
        mtr_commit(&mtr);
4412
4466
        mtr_has_extra_clust_latch = FALSE;
4413
4467
 
4425
4479
                thr->lock_state = QUE_THR_LOCK_NOLOCK;
4426
4480
                mtr_start(&mtr);
4427
4481
 
 
4482
                /* Table lock waited, go try to obtain table lock
 
4483
                again */
 
4484
                if (table_lock_waited) {
 
4485
                        table_lock_waited = FALSE;
 
4486
 
 
4487
                        goto wait_table_again;
 
4488
                }
 
4489
 
4428
4490
                sel_restore_position_for_mysql(&same_user_rec,
4429
4491
                                               BTR_SEARCH_LEAF, pcur,
4430
4492
                                               moves_up, &mtr);