51
51
#define SEL_RETRY 2
53
53
/************************************************************************
54
Returns TRUE if the user-defined column in a secondary index record
55
is alphabetically the same as the corresponding BLOB column in the clustered
57
NOTE: the comparison is NOT done as a binary comparison, but character
58
fields are compared with collation! */
61
row_sel_sec_rec_is_for_blob(
62
/*========================*/
63
/* out: TRUE if the columns
65
ulint mtype, /* in: main type */
66
ulint prtype, /* in: precise type */
67
ulint mbminlen, /* in: minimum length of a
68
multi-byte character */
69
ulint mbmaxlen, /* in: maximum length of a
70
multi-byte character */
71
const byte* clust_field, /* in: the locally stored part of
72
the clustered index column, including
73
the BLOB pointer; the clustered
74
index record must be covered by
75
a lock or a page latch to protect it
76
against deletion (rollback or purge) */
77
ulint clust_len, /* in: length of clust_field */
78
const byte* sec_field, /* in: column in secondary index */
79
ulint sec_len, /* in: length of sec_field */
80
ulint zip_size) /* in: compressed page size, or 0 */
83
byte buf[DICT_MAX_INDEX_COL_LEN];
85
len = btr_copy_externally_stored_field_prefix(buf, sizeof buf,
87
clust_field, clust_len);
88
len = dtype_get_at_most_n_mbchars(prtype, mbminlen, mbmaxlen,
89
sec_len, len, (const char*) buf);
91
return(!cmp_data_data(mtype, prtype, buf, len, sec_field, sec_len));
94
/************************************************************************
54
95
Returns TRUE if the user-defined column values in a secondary index record
55
96
are alphabetically the same as the corresponding columns in the clustered
64
105
record is equal to the corresponding
65
106
fields in the clustered record,
66
107
when compared with collation */
67
rec_t* sec_rec, /* in: secondary index record */
108
const rec_t* sec_rec, /* in: secondary index record */
68
109
dict_index_t* sec_index, /* in: secondary index */
69
rec_t* clust_rec, /* in: clustered index record */
110
const rec_t* clust_rec, /* in: clustered index record;
111
must be protected by a lock or
112
a page latch against deletion
113
in rollback or purge */
70
114
dict_index_t* clust_index) /* in: clustered index */
116
const byte* sec_field;
118
const byte* clust_field;
78
121
mem_heap_t* heap = NULL;
82
125
ulint* sec_offs = sec_offsets_;
83
126
ibool is_equal = TRUE;
85
*clust_offsets_ = (sizeof clust_offsets_) / sizeof *clust_offsets_;
86
*sec_offsets_ = (sizeof sec_offsets_) / sizeof *sec_offsets_;
128
rec_offs_init(clust_offsets_);
129
rec_offs_init(sec_offsets_);
131
if (rec_get_deleted_flag(clust_rec,
132
dict_table_is_comp(clust_index->table))) {
134
/* The clustered index record is delete-marked;
135
it is not visible in the read view. Besides,
136
if there are any externally stored columns,
137
some of them may have already been purged. */
88
141
clust_offs = rec_get_offsets(clust_rec, clust_index, clust_offs,
89
142
ULINT_UNDEFINED, &heap);
95
148
for (i = 0; i < n; i++) {
96
149
const dict_field_t* ifield;
97
150
const dict_col_t* col;
99
155
ifield = dict_index_get_nth_field(sec_index, i);
100
156
col = dict_field_get_col(ifield);
157
clust_pos = dict_col_get_clust_pos(col, clust_index);
102
159
clust_field = rec_get_nth_field(
103
clust_rec, clust_offs,
104
dict_col_get_clust_pos(col, clust_index), &clust_len);
160
clust_rec, clust_offs, clust_pos, &clust_len);
105
161
sec_field = rec_get_nth_field(sec_rec, sec_offs, i, &sec_len);
107
if (ifield->prefix_len > 0 && clust_len != UNIV_SQL_NULL) {
109
clust_len = dtype_get_at_most_n_mbchars(
165
if (ifield->prefix_len > 0 && len != UNIV_SQL_NULL) {
167
if (rec_offs_nth_extern(clust_offs, clust_pos)) {
168
len -= BTR_EXTERN_FIELD_REF_SIZE;
171
len = dtype_get_at_most_n_mbchars(
110
172
col->prtype, col->mbminlen, col->mbmaxlen,
112
clust_len, (char*) clust_field);
173
ifield->prefix_len, len, (char*) clust_field);
175
if (rec_offs_nth_extern(clust_offs, clust_pos)
177
if (!row_sel_sec_rec_is_for_blob(
178
col->mtype, col->prtype,
179
col->mbminlen, col->mbmaxlen,
180
clust_field, clust_len,
183
clust_index->table))) {
115
191
if (0 != cmp_data_data(col->mtype, col->prtype,
116
clust_field, clust_len,
117
193
sec_field, sec_len)) {
118
195
is_equal = FALSE;
277
354
row_sel_fetch_columns(
278
355
/*==================*/
279
356
dict_index_t* index, /* in: record index */
280
rec_t* rec, /* in: record in a clustered or non-clustered
357
const rec_t* rec, /* in: record in a clustered or non-clustered
358
index; must be protected by a page latch */
282
359
const ulint* offsets,/* in: rec_get_offsets(rec, index) */
283
360
sym_node_t* column) /* in: first column in a column list, or
287
364
ulint index_type;
292
369
ut_ad(rec_offs_validate(rec, index, offsets));
294
if (index->type & DICT_CLUSTERED) {
371
if (dict_index_is_clust(index)) {
295
372
index_type = SYM_CLUST_FIELD_NO;
297
374
index_type = SYM_SEC_FIELD_NO;
314
391
heap = mem_heap_create(1);
316
393
data = btr_rec_copy_externally_stored_field(
317
rec, offsets, field_no, &len, heap);
395
dict_table_zip_size(index->table),
396
field_no, &len, heap);
319
398
ut_a(len != UNIV_SQL_NULL);
370
453
/*************************************************************************
371
454
Frees a prefetch buffer for a column, including the dynamically allocated
372
455
memory for data stored there. */
375
458
sel_col_prefetch_buf_free(
376
459
/*======================*/
419
502
ut_ad(!column->prefetch_buf);
420
503
ut_ad(que_node_get_val_buf_size(column) == 0);
422
dfield_set_data(val, NULL, 0);
504
ut_d(dfield_set_null(val));
427
509
ut_ad(column->prefetch_buf);
510
ut_ad(!dfield_is_ext(val));
429
512
sel_buf = column->prefetch_buf + plan->first_prefetched;
568
651
/* out: DB_SUCCESS or error code */
569
652
dict_index_t* clust_index, /* in: clustered index */
570
653
row_prebuilt_t* prebuilt, /* in: prebuilt struct */
571
rec_t* rec, /* in: record in a clustered index */
654
const rec_t* rec, /* in: record in a clustered index */
572
655
ulint** offsets, /* in/out: offsets returned by
573
656
rec_get_offsets(rec, clust_index) */
574
657
mem_heap_t** offset_heap, /* in/out: memory heap from which
575
658
the offsets are allocated */
576
rec_t** old_vers, /* out: old version, or NULL if the
659
const rec_t** old_vers, /* out: old version, or NULL if the
577
660
record does not exist in the view:
578
661
i.e., it was freshly inserted
752
835
err = lock_clust_rec_read_check_and_lock(
753
0, clust_rec, index, offsets,
836
0, btr_pcur_get_block(&plan->clust_pcur),
837
clust_rec, index, offsets,
754
838
node->row_lock_mode, lock_type, thr);
756
840
if (err != DB_SUCCESS) {
808
/* Fetch the columns needed in test conditions */
892
/* Fetch the columns needed in test conditions. The clustered
893
index record is protected by a page latch that was acquired
894
when plan->clust_pcur was positioned. The latch will not be
895
released until mtr_commit(mtr). */
810
897
row_sel_fetch_columns(index, clust_rec, offsets,
811
898
UT_LIST_GET_FIRST(plan->columns));
826
913
sel_set_rec_lock(
827
914
/*=============*/
828
/* out: DB_SUCCESS or error code */
829
rec_t* rec, /* in: record */
830
dict_index_t* index, /* in: index */
831
const ulint* offsets,/* in: rec_get_offsets(rec, index) */
832
ulint mode, /* in: lock mode */
833
ulint type, /* in: LOCK_ORDINARY, LOCK_GAP, or
835
que_thr_t* thr) /* in: query thread */
915
/* out: DB_SUCCESS or error code */
916
const buf_block_t* block, /* in: buffer block of rec */
917
const rec_t* rec, /* in: record */
918
dict_index_t* index, /* in: index */
919
const ulint* offsets,/* in: rec_get_offsets(rec, index) */
920
ulint mode, /* in: lock mode */
921
ulint type, /* in: LOCK_ORDINARY, LOCK_GAP, or
923
que_thr_t* thr) /* in: query thread */
849
if (index->type & DICT_CLUSTERED) {
937
if (dict_index_is_clust(index)) {
850
938
err = lock_clust_rec_read_check_and_lock(
851
0, rec, index, offsets, mode, type, thr);
939
0, block, rec, index, offsets, mode, type, thr);
853
941
err = lock_sec_rec_read_check_and_lock(
854
0, rec, index, offsets, mode, type, thr);
942
0, block, rec, index, offsets, mode, type, thr);
1100
1188
offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
1102
if (index->type & DICT_CLUSTERED) {
1190
if (dict_index_is_clust(index)) {
1103
1191
if (!lock_clust_rec_cons_read_sees(rec, index, offsets,
1104
1192
node->read_view)) {
1105
1193
ret = SEL_RETRY;
1106
1194
goto func_exit;
1108
} else if (!lock_sec_rec_cons_read_sees(rec, index, node->read_view)) {
1196
} else if (!lock_sec_rec_cons_read_sees(rec, node->read_view)) {
1110
1198
ret = SEL_RETRY;
1111
1199
goto func_exit;
1114
/* Test deleted flag. Fetch the columns needed in test conditions. */
1116
row_sel_fetch_columns(index, rec, offsets,
1117
UT_LIST_GET_FIRST(plan->columns));
1202
/* Test the deleted flag. */
1119
1204
if (rec_get_deleted_flag(rec, dict_table_is_comp(plan->table))) {
1122
1207
goto func_exit;
1210
/* Fetch the columns needed in test conditions. The index
1211
record is protected by a page latch that was acquired when
1212
plan->pcur was positioned. The latch will not be released
1213
until mtr_commit(mtr). */
1215
row_sel_fetch_columns(index, rec, offsets,
1216
UT_LIST_GET_FIRST(plan->columns));
1125
1218
/* Test the rest of search conditions */
1127
1220
if (!row_sel_test_other_conds(plan)) {
1369
1462
lock_type = LOCK_ORDINARY;
1372
err = sel_set_rec_lock(next_rec, index, offsets,
1465
err = sel_set_rec_lock(btr_pcur_get_block(&plan->pcur),
1466
next_rec, index, offsets,
1373
1467
node->row_lock_mode,
1374
1468
lock_type, thr);
1425
1519
lock_type = LOCK_ORDINARY;
1428
err = sel_set_rec_lock(rec, index, offsets,
1522
err = sel_set_rec_lock(btr_pcur_get_block(&plan->pcur),
1523
rec, index, offsets,
1429
1524
node->row_lock_mode, lock_type, thr);
1431
1526
if (err != DB_SUCCESS) {
1488
1583
/* This is a non-locking consistent read: if necessary, fetch
1489
1584
a previous version of the record */
1491
if (index->type & DICT_CLUSTERED) {
1586
if (dict_index_is_clust(index)) {
1493
1588
if (!lock_clust_rec_cons_read_sees(rec, index, offsets,
1494
1589
node->read_view)) {
1507
1602
offsets = rec_get_offsets(
1508
1603
rec, index, offsets,
1509
1604
ULINT_UNDEFINED, &heap);
1606
/* Fetch the columns needed in
1607
test conditions. The clustered
1608
index record is protected by a
1609
page latch that was acquired
1610
by row_sel_open_pcur() or
1611
row_sel_restore_pcur_pos().
1612
The latch will not be released
1613
until mtr_commit(mtr). */
1510
1615
row_sel_fetch_columns(
1511
1616
index, rec, offsets,
1512
1617
UT_LIST_GET_FIRST(
1531
1636
/* PHASE 4: Test search end conditions and deleted flag */
1533
/* Fetch the columns needed in test conditions */
1638
/* Fetch the columns needed in test conditions. The record is
1639
protected by a page latch that was acquired by
1640
row_sel_open_pcur() or row_sel_restore_pcur_pos(). The latch
1641
will not be released until mtr_commit(mtr). */
1535
1643
row_sel_fetch_columns(index, rec, offsets,
1536
1644
UT_LIST_GET_FIRST(plan->columns));
1683
1792
if (leaf_contains_updates
1684
&& btr_pcur_is_after_last_on_page(&(plan->pcur), &mtr)) {
1793
&& btr_pcur_is_after_last_on_page(&plan->pcur)) {
1686
1795
/* We must commit &mtr if we are moving to a different page,
1687
1796
because we have done updates to the x-latched leaf page, and
1714
1823
/* We found a record which satisfies the conditions: we can move to
1715
1824
the next table or return a row in the result set */
1717
ut_ad(btr_pcur_is_on_user_rec(&(plan->pcur), &mtr));
1826
ut_ad(btr_pcur_is_on_user_rec(&plan->pcur));
1719
1828
if (plan->unique_search && !node->can_get_updated) {
1796
1901
sel_assign_into_var_values(node->into_list, node);
1798
1903
thr->run_node = que_node_get_parent(node);
1800
if (search_latch_locked) {
1801
rw_lock_s_unlock(&btr_search_latch);
1807
node->state = SEL_NODE_NO_MORE_ROWS;
1809
thr->run_node = que_node_get_parent(node);
1811
if (search_latch_locked) {
1812
rw_lock_s_unlock(&btr_search_latch);
1905
node->state = SEL_NODE_NO_MORE_ROWS;
1907
thr->run_node = que_node_get_parent(node);
1815
1910
goto func_exit;
1865
1960
lock_wait_or_error:
1866
1961
/* See the note at stop_for_a_while: the same holds for this case */
1868
ut_ad(!btr_pcur_is_before_first_on_page(&(plan->pcur), &mtr)
1963
ut_ad(!btr_pcur_is_before_first_on_page(&plan->pcur) || !node->asc);
1870
1964
ut_ad(!search_latch_locked);
1872
1966
plan->stored_cursor_rec_processed = FALSE;
2074
2171
dfield_t* dfield = que_node_get_val(exp);
2075
dtype_t* type = dfield_get_type(dfield);
2172
const dtype_t* type = dfield_get_type(dfield);
2077
2174
fprintf(stderr, " column %lu:\n", (ulong)i);
2114
2211
dfield_t* dfield = que_node_get_val(node->select_list);
2115
dtype_t* type = dfield_get_type(dfield);
2212
const dtype_t* type = dfield_get_type(dfield);
2116
2213
ulint len = dfield_get_len(dfield);
2118
2215
ut_a(dtype_get_mtype(type) == DATA_INT);
2195
2292
last field is only a prefix of the full key field len and print a warning if
2196
2293
such appears. A counterpart of this function is
2197
2294
ha_innobase::store_key_val_for_row() in ha_innodb.cc. */
2200
2297
row_sel_convert_mysql_key_to_innobase(
2201
2298
/*==================================*/
2202
dtuple_t* tuple, /* in: tuple where to build;
2299
dtuple_t* tuple, /* in/out: tuple where to build;
2203
2300
NOTE: we assume that the type info
2204
2301
in the tuple is already according
2208
2305
ulint buf_len, /* in: buffer length */
2209
2306
dict_index_t* index, /* in: index of the key value */
2210
byte* key_ptr, /* in: MySQL key value */
2307
const byte* key_ptr, /* in: MySQL key value */
2211
2308
ulint key_len, /* in: MySQL key value length */
2212
2309
trx_t* trx) /* in: transaction */
2214
2311
byte* original_buf = buf;
2215
byte* original_key_ptr = key_ptr;
2312
const byte* original_key_ptr = key_ptr;
2216
2313
dict_field_t* field;
2217
2314
dfield_t* dfield;
2218
2315
ulint data_offset;
2219
2316
ulint data_len;
2220
2317
ulint data_field_len;
2319
const byte* key_end;
2223
2320
ulint n_fields = 0;
2226
2322
/* For documentation of the key value storage format in MySQL, see
2227
2323
ha_innobase::store_key_val_for_row() in ha_innodb.cc. */
2235
2331
dfield = dtuple_get_nth_field(tuple, 0);
2236
2332
field = dict_index_get_nth_field(index, 0);
2238
if (dfield_get_type(dfield)->mtype == DATA_SYS) {
2334
if (UNIV_UNLIKELY(dfield_get_type(dfield)->mtype == DATA_SYS)) {
2239
2335
/* A special case: we are looking for a position in the
2240
2336
generated clustered index which InnoDB automatically added
2241
2337
to a table with no primary key: the first and the only
2318
2413
data_field_len = data_offset + data_len;
2321
if (dtype_get_mysql_type(dfield_get_type(dfield))
2322
== DATA_DRIZZLE_TRUE_VARCHAR
2323
&& dfield_get_type(dfield)->mtype != DATA_INT) {
2417
(dtype_get_mysql_type(dfield_get_type(dfield))
2418
== DATA_MYSQL_TRUE_VARCHAR)
2419
&& UNIV_LIKELY(type != DATA_INT)) {
2324
2420
/* In a MySQL key value format, a true VARCHAR is
2325
2421
always preceded by 2 bytes of a length field.
2326
2422
dfield_get_type(dfield)->len returns the maximum
2398
2496
row_sel_store_row_id_to_prebuilt(
2399
2497
/*=============================*/
2400
row_prebuilt_t* prebuilt, /* in: prebuilt */
2401
rec_t* index_rec, /* in: record */
2402
dict_index_t* index, /* in: index of the record */
2403
const ulint* offsets) /* in: rec_get_offsets
2404
(index_rec, index) */
2498
row_prebuilt_t* prebuilt, /* in/out: prebuilt */
2499
const rec_t* index_rec, /* in: record */
2500
const dict_index_t* index, /* in: index of the record */
2501
const ulint* offsets) /* in: rec_get_offsets
2502
(index_rec, index) */
2409
2507
ut_ad(rec_offs_validate(index_rec, index, offsets));
2412
2510
index_rec, offsets,
2413
2511
dict_index_get_sys_col_pos(index, DATA_ROW_ID), &len);
2415
if (len != DATA_ROW_ID_LEN) {
2513
if (UNIV_UNLIKELY(len != DATA_ROW_ID_LEN)) {
2416
2514
fprintf(stderr,
2417
2515
"InnoDB: Error: Row id field is"
2418
2516
" wrong length %lu in ", (ulong) len);
2437
2535
row_sel_field_store_in_mysql_format(
2438
2536
/*================================*/
2439
byte* dest, /* in/out: buffer where to store; NOTE that BLOBs
2440
are not in themselves stored here: the caller must
2441
allocate and copy the BLOB into buffer before, and pass
2442
the pointer to the BLOB in 'data' */
2443
const mysql_row_templ_t* templ, /* in: MySQL column template.
2444
Its following fields are referenced:
2445
type, is_unsigned, mysql_col_len, mbminlen, mbmaxlen */
2446
byte* data, /* in: data to store */
2447
ulint len) /* in: length of the data */
2537
byte* dest, /* in/out: buffer where to store; NOTE
2538
that BLOBs are not in themselves
2539
stored here: the caller must allocate
2540
and copy the BLOB into buffer before,
2541
and pass the pointer to the BLOB in
2543
const mysql_row_templ_t* templ,
2544
/* in: MySQL column template.
2545
Its following fields are referenced:
2546
type, is_unsigned, mysql_col_len,
2547
mbminlen, mbmaxlen */
2548
const byte* data, /* in: data to store */
2549
ulint len) /* in: length of the data */
2450
2552
byte* field_end;
2474
2577
ut_ad(templ->mysql_col_len == len);
2475
} else if (templ->type == DATA_VARCHAR
2476
|| templ->type == DATA_VARMYSQL
2477
|| templ->type == DATA_BINARY) {
2479
2583
field_end = dest + templ->mysql_col_len;
2481
if (templ->mysql_type == DATA_DRIZZLE_TRUE_VARCHAR) {
2585
if (templ->mysql_type == DATA_MYSQL_TRUE_VARCHAR) {
2482
2586
/* This is a >= 5.0.3 type true VARCHAR. Store the
2483
2587
length of the data to the first byte or the first
2484
2588
two bytes of dest. */
2527
2631
memset(pad_ptr, 0x20, field_end - pad_ptr);
2529
} else if (templ->type == DATA_BLOB) {
2530
2636
/* Store a pointer to the BLOB buffer to dest: the BLOB was
2531
2637
already copied to the buffer in row_sel_store_mysql_rec */
2533
2639
row_mysql_store_blob_ref(dest, templ->mysql_col_len, data,
2535
} else if (templ->type == DATA_MYSQL) {
2536
2644
memcpy(dest, data, len);
2538
2646
ut_ad(templ->mysql_col_len >= len);
2554
2662
memset(dest + len, 0x20, templ->mysql_col_len - len);
2557
ut_ad(templ->type == DATA_CHAR
2558
|| templ->type == DATA_FIXBINARY
2559
/*|| templ->type == DATA_SYS_CHILD
2560
|| templ->type == DATA_SYS*/
2561
|| templ->type == DATA_FLOAT
2562
|| templ->type == DATA_DOUBLE
2563
|| templ->type == DATA_DECIMAL);
2668
case DATA_SYS_CHILD:
2670
/* These column types should never be shipped to MySQL. */
2674
case DATA_FIXBINARY:
2678
/* Above are the valid column types for MySQL data. */
2679
#endif /* UNIV_DEBUG */
2564
2680
ut_ad(templ->mysql_col_len == len);
2566
2681
memcpy(dest, data, len);
2583
2698
byte* mysql_rec, /* out: row in the MySQL format */
2584
2699
row_prebuilt_t* prebuilt, /* in: prebuilt struct */
2585
rec_t* rec, /* in: Innobase record in the index
2700
const rec_t* rec, /* in: Innobase record in the index
2586
2701
which was described in prebuilt's
2588
const ulint* offsets, /* in: array returned by
2702
template; must be protected by
2704
const ulint* offsets, /* in: array returned by
2589
2705
rec_get_offsets() */
2590
ulint start_field_no,
2706
ulint start_field_no,
2593
2709
mysql_row_templ_t* templ;
2594
2710
mem_heap_t* extern_field_heap = NULL;
2595
2711
mem_heap_t* heap;
2636
2752
causes an assert */
2638
2754
data = btr_rec_copy_externally_stored_field(
2639
rec, offsets, templ->rec_field_no,
2756
dict_table_zip_size(prebuilt->table),
2757
templ->rec_field_no, &len, heap);
2642
2759
ut_a(len != UNIV_SQL_NULL);
2712
2829
BLOB, TEXT and true VARCHAR) with space. */
2713
2830
if (UNIV_UNLIKELY(templ->mbminlen == 2)) {
2714
2831
/* Treat UCS2 as a special case. */
2716
2833
+ templ->mysql_col_offset;
2717
2834
len = templ->mysql_col_len;
2718
2835
/* There are two UCS2 bytes per char,
2752
2869
read_view_t* read_view, /* in: read view */
2753
2870
dict_index_t* clust_index, /* in: clustered index */
2754
2871
row_prebuilt_t* prebuilt, /* in: prebuilt struct */
2755
rec_t* rec, /* in: record in a clustered index */
2872
const rec_t* rec, /* in: record in a clustered index */
2756
2873
ulint** offsets, /* in/out: offsets returned by
2757
2874
rec_get_offsets(rec, clust_index) */
2758
2875
mem_heap_t** offset_heap, /* in/out: memory heap from which
2788
2905
/* out: DB_SUCCESS or error code */
2789
2906
row_prebuilt_t* prebuilt,/* in: prebuilt struct in the handle */
2790
2907
dict_index_t* sec_index,/* in: secondary index where rec resides */
2791
rec_t* rec, /* in: record in a non-clustered index; if
2908
const rec_t* rec, /* in: record in a non-clustered index; if
2792
2909
this is a locking read, then rec is not
2793
2910
allowed to be delete-marked, and that would
2794
2911
not make sense either */
2795
2912
que_thr_t* thr, /* in: query thread */
2796
rec_t** out_rec,/* out: clustered record or an old version of
2913
const rec_t** out_rec,/* out: clustered record or an old version of
2797
2914
it, NULL if the old version did not exist
2798
2915
in the read view, i.e., it was a fresh
2799
2916
inserted version */
2800
ulint** offsets,/* out: offsets returned by
2917
ulint** offsets,/* in: offsets returned by
2918
rec_get_offsets(rec, sec_index);
2919
out: offsets returned by
2801
2920
rec_get_offsets(out_rec, clust_index) */
2802
2921
mem_heap_t** offset_heap,/* in/out: memory heap from which
2803
2922
the offsets are allocated */
2814
2933
*out_rec = NULL;
2815
2934
trx = thr_get_trx(thr);
2817
row_build_row_ref_in_tuple(prebuilt->clust_ref, sec_index, rec, trx);
2936
row_build_row_ref_in_tuple(prebuilt->clust_ref, rec,
2937
sec_index, *offsets, trx);
2819
2939
clust_index = dict_table_get_first_index(sec_index->table);
2878
2998
we set a LOCK_REC_NOT_GAP type lock */
2880
3000
err = lock_clust_rec_read_check_and_lock(
2881
0, clust_rec, clust_index, *offsets,
3001
0, btr_pcur_get_block(prebuilt->clust_pcur),
3002
clust_rec, clust_index, *offsets,
2882
3003
prebuilt->select_lock_type, LOCK_REC_NOT_GAP, thr);
2883
3004
if (err != DB_SUCCESS) {
2926
3047
visit through secondary index records that would not really
2927
3048
exist in our snapshot. */
2929
if (clust_rec && (old_vers || rec_get_deleted_flag(
3052
|| rec_get_deleted_flag(rec, dict_table_is_comp(
2933
3054
&& !row_sel_sec_rec_is_for_clust_rec(
2934
3055
rec, sec_index, clust_rec, clust_index)) {
2935
3056
clust_rec = NULL;
3057
#ifdef UNIV_SEARCH_DEBUG
2937
#ifdef UNIV_SEARCH_DEBUG
2938
3059
ut_a(clust_rec == NULL
2939
3060
|| row_sel_sec_rec_is_for_clust_rec(
2940
3061
rec, sec_index, clust_rec, clust_index));
3019
3140
ut_ad(relative_position == BTR_PCUR_BEFORE
3020
3141
|| relative_position == BTR_PCUR_BEFORE_FIRST_IN_TREE);
3022
if (moves_up && btr_pcur_is_on_user_rec(pcur, mtr)) {
3143
if (moves_up && btr_pcur_is_on_user_rec(pcur)) {
3023
3144
btr_pcur_move_to_next(pcur, mtr);
3083
3204
row_sel_push_cache_row_for_mysql(
3084
3205
/*=============================*/
3085
3206
row_prebuilt_t* prebuilt, /* in: prebuilt struct */
3086
rec_t* rec, /* in: record to push */
3207
const rec_t* rec, /* in: record to push; must
3208
be protected by a page latch */
3087
3209
const ulint* offsets, /* in: rec_get_offsets() */
3088
ulint start_field_no, /* psergey: start from this field */
3089
byte* remainder_buf) /* if above !=0 -> where to take prev fields */
3210
ulint start_field_no, /* psergy: start from this field */
3211
byte* remainder_buf) /* if above !=0 -> where to take
3094
ut_ad(prebuilt->n_fetch_cached < DRIZZLE_FETCH_CACHE_SIZE);
3217
ut_ad(prebuilt->n_fetch_cached < MYSQL_FETCH_CACHE_SIZE);
3095
3218
ut_ad(rec_offs_validate(rec, NULL, offsets));
3096
3219
ut_a(!prebuilt->templ_contains_blob);
3098
3221
if (prebuilt->fetch_cache[0] == NULL) {
3099
3222
/* Allocate memory for the fetch cache */
3101
for (i = 0; i < DRIZZLE_FETCH_CACHE_SIZE; i++) {
3224
for (i = 0; i < MYSQL_FETCH_CACHE_SIZE; i++) {
3103
3226
/* A user has reported memory corruption in these
3104
3227
buffers in Linux. Put magic numbers there to help
3120
3243
prebuilt->fetch_cache[
3121
3244
prebuilt->n_fetch_cached],
3122
3245
prebuilt, rec, offsets, start_field_no,
3123
prebuilt->n_template))) {
3246
prebuilt->n_template))) {
3126
3250
if (start_field_no) {
3127
3251
for (i=0; i < start_field_no; i++) {
3128
3252
register ulint offs;
3129
mysql_row_templ_t* templ;
3253
mysql_row_templ_t* templ;
3130
3254
templ = prebuilt->mysql_template + i;
3132
3256
if (templ->mysql_null_bit_mask) {
3133
3257
offs= templ->mysql_null_byte_offset;
3134
*(prebuilt->fetch_cache[prebuilt->n_fetch_cached] + offs) ^=
3135
(*(remainder_buf + offs) & templ->mysql_null_bit_mask);
3258
if (*(remainder_buf + offs) & templ->mysql_null_bit_mask)
3259
*(prebuilt->fetch_cache[prebuilt->n_fetch_cached] + offs) |=
3260
/* (*(remainder_buf + offs) &*/( templ->mysql_null_bit_mask);
3262
*(prebuilt->fetch_cache[prebuilt->n_fetch_cached] + offs) &=
3263
~templ->mysql_null_bit_mask;
3137
3266
offs= templ->mysql_col_offset;
3138
3267
memcpy(prebuilt->fetch_cache[prebuilt->n_fetch_cached] + offs,
3154
3284
row_sel_try_search_shortcut_for_mysql(
3155
3285
/*==================================*/
3156
3286
/* out: SEL_FOUND, SEL_EXHAUSTED, SEL_RETRY */
3157
rec_t** out_rec,/* out: record if found */
3287
const rec_t** out_rec,/* out: record if found */
3158
3288
row_prebuilt_t* prebuilt,/* in: prebuilt struct */
3159
3289
ulint** offsets,/* in/out: for rec_get_offsets(*out_rec) */
3160
3290
mem_heap_t** heap, /* in/out: heap for rec_get_offsets() */
3161
3291
mtr_t* mtr) /* in: started mtr */
3163
3293
dict_index_t* index = prebuilt->index;
3164
dtuple_t* search_tuple = prebuilt->search_tuple;
3294
const dtuple_t* search_tuple = prebuilt->search_tuple;
3165
3295
btr_pcur_t* pcur = prebuilt->pcur;
3166
3296
trx_t* trx = prebuilt->trx;
3169
ut_ad(index->type & DICT_CLUSTERED);
3299
ut_ad(dict_index_is_clust(index));
3170
3300
ut_ad(!prebuilt->templ_contains_blob);
3172
3302
btr_pcur_open_with_no_init(index, search_tuple, PAGE_CUR_GE,
3251
3381
dict_index_t* index = prebuilt->index;
3252
3382
ibool comp = dict_table_is_comp(index->table);
3253
dtuple_t* search_tuple = prebuilt->search_tuple;
3383
const dtuple_t* search_tuple = prebuilt->search_tuple;
3254
3384
btr_pcur_t* pcur = prebuilt->pcur;
3255
3385
trx_t* trx = prebuilt->trx;
3256
3386
dict_index_t* clust_index;
3257
3387
que_thr_t* thr;
3389
const rec_t* result_rec;
3390
const rec_t* clust_rec;
3261
3391
ulint err = DB_SUCCESS;
3262
3392
ibool unique_search = FALSE;
3263
3393
ibool unique_search_from_clust_index = FALSE;
3279
3409
mem_heap_t* heap = NULL;
3280
3410
ulint offsets_[REC_OFFS_NORMAL_SIZE];
3281
3411
ulint* offsets = offsets_;
3282
ibool some_fields_in_buffer;
3283
ibool get_clust_rec= 0;
3412
ibool some_fields_in_buffer;
3413
ibool get_clust_rec= 0;
3285
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
3415
rec_offs_init(offsets_);
3287
3417
ut_ad(index && pcur && search_tuple);
3288
3418
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
3424
3554
if (prebuilt->fetch_cache_first > 0
3425
&& prebuilt->fetch_cache_first < DRIZZLE_FETCH_CACHE_SIZE) {
3555
&& prebuilt->fetch_cache_first < MYSQL_FETCH_CACHE_SIZE) {
3427
3557
/* The previous returned row was popped from the fetch
3428
3558
cache, but the cache was not full at the time of the
3452
3582
locks when locking delete-marked records. */
3454
3584
if (match_mode == ROW_SEL_EXACT
3455
&& index->type & DICT_UNIQUE
3585
&& dict_index_is_unique(index)
3456
3586
&& dtuple_get_n_fields(search_tuple)
3457
3587
== dict_index_get_n_unique(index)
3458
&& (index->type & DICT_CLUSTERED
3588
&& (dict_index_is_clust(index)
3459
3589
|| !dtuple_contains_null(search_tuple))) {
3461
3591
/* Note above that a UNIQUE secondary index can contain many
3493
3623
if (UNIV_UNLIKELY(direction == 0)
3494
3624
&& unique_search
3495
&& index->type & DICT_CLUSTERED
3625
&& dict_index_is_clust(index)
3496
3626
&& !prebuilt->templ_contains_blob
3497
3627
&& !prebuilt->used_in_HANDLER
3498
3628
&& (prebuilt->mysql_row_len < UNIV_PAGE_SIZE / 8)) {
3532
3662
ut_a(0 == cmp_dtuple_rec(search_tuple,
3533
3663
rec, offsets));
3665
/* At this point, rec is protected by
3666
a page latch that was acquired by
3667
row_sel_try_search_shortcut_for_mysql().
3668
The latch will not be released until
3669
mtr_commit(&mtr). */
3535
3671
if (!row_sel_store_mysql_rec(buf, prebuilt,
3537
prebuilt->n_template)) {
3673
prebuilt->n_template)) {
3538
3674
err = DB_TOO_BIG_RECORD;
3540
3676
/* We let the main loop to do the
3550
3686
srv_n_rows_read++;
3552
if (trx->search_latch_timeout > 0
3553
&& trx->has_search_latch) {
3555
trx->search_latch_timeout--;
3557
rw_lock_s_unlock(&btr_search_latch);
3558
trx->has_search_latch = FALSE;
3561
/* NOTE that we do NOT store the cursor
3563
3688
err = DB_SUCCESS;
3689
goto release_search_latch_if_needed;
3566
3691
case SEL_EXHAUSTED:
3567
3692
mtr_commit(&mtr);
3569
3694
/* ut_print_name(stderr, index->name);
3570
3695
fputs(" record not found 2\n", stderr); */
3697
err = DB_RECORD_NOT_FOUND;
3698
release_search_latch_if_needed:
3572
3699
if (trx->search_latch_timeout > 0
3573
3700
&& trx->has_search_latch) {
3603
3734
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
3604
3735
&& prebuilt->select_lock_type != LOCK_NONE
3736
#ifdef BUILD_DRIZZLE
3737
&& trx->mysql_session != NULL
3739
&& trx->mysql_thd != NULL
3605
3741
&& trx->mysql_query_str != NULL
3606
&& *trx->mysql_query_str != NULL
3607
&& trx->mysql_session != NULL) {
3742
&& *trx->mysql_query_str != NULL) {
3609
3744
/* Scan the MySQL query string; check if SELECT is the first
3682
3817
/* Try to place a gap lock on the next index record
3683
3818
to prevent phantoms in ORDER BY ... DESC queries */
3819
const rec_t* next = page_rec_get_next_const(rec);
3685
offsets = rec_get_offsets(page_rec_get_next(rec),
3821
offsets = rec_get_offsets(next, index, offsets,
3687
3822
ULINT_UNDEFINED, &heap);
3688
err = sel_set_rec_lock(page_rec_get_next(rec),
3823
err = sel_set_rec_lock(btr_pcur_get_block(pcur),
3824
next, index, offsets,
3690
3825
prebuilt->select_lock_type,
3691
3826
LOCK_GAP, thr);
3754
3889
fputs("Using ", stderr);
3755
3890
dict_index_name_print(stderr, index);
3756
3891
fprintf(stderr, " cnt %lu ; Page no %lu\n", cnt,
3757
buf_frame_get_page_no(buf_frame_align(rec)));
3892
page_get_page_no(page_align(rec)));
3758
3893
rec_print(rec);
3760
3895
#endif /* UNIV_SEARCH_DEBUG */
3785
3920
offsets = rec_get_offsets(rec, index, offsets,
3786
3921
ULINT_UNDEFINED, &heap);
3787
err = sel_set_rec_lock(rec, index, offsets,
3922
err = sel_set_rec_lock(btr_pcur_get_block(pcur),
3923
rec, index, offsets,
3788
3924
prebuilt->select_lock_type,
3789
3925
LOCK_ORDINARY, thr);
3823
3959
if (srv_force_recovery == 0 || moves_up == FALSE) {
3824
3960
ut_print_timestamp(stderr);
3825
buf_page_print(buf_frame_align(rec));
3961
buf_page_print(page_align(rec), 0);
3826
3962
fprintf(stderr,
3827
"\nInnoDB: rec address %p, first"
3828
" buffer frame %p\n"
3829
"InnoDB: buffer pool high end %p,"
3963
"\nInnoDB: rec address %p,"
3830
3964
" buf block fix count %lu\n",
3831
(void*) rec, (void*) buf_pool->frame_zero,
3832
(void*) buf_pool->high_end,
3833
(ulong)buf_block_align(rec)->buf_fix_count);
3965
(void*) rec, (ulong)
3966
btr_cur_get_block(btr_pcur_get_btr_cur(pcur))
3967
->page.buf_fix_count);
3834
3968
fprintf(stderr,
3835
3969
"InnoDB: Index corruption: rec offs %lu"
3836
3970
" next offs %lu, page no %lu,\n"
3838
3972
(ulong) page_offset(rec),
3839
3973
(ulong) next_offs,
3840
(ulong) buf_frame_get_page_no(rec));
3974
(ulong) page_get_page_no(page_align(rec)));
3841
3975
dict_index_name_print(stderr, trx, index);
3842
3976
fputs(". Run CHECK TABLE. You may need to\n"
3843
3977
"InnoDB: restore from a backup, or"
3858
3992
(ulong) page_offset(rec),
3859
3993
(ulong) next_offs,
3860
(ulong) buf_frame_get_page_no(rec));
3994
(ulong) page_get_page_no(page_align(rec)));
3861
3995
dict_index_name_print(stderr, trx, index);
3862
3996
fputs(". We try to skip the rest of the page.\n",
3883
4017
(ulong) page_offset(rec),
3884
4018
(ulong) next_offs,
3885
(ulong) buf_frame_get_page_no(rec));
4019
(ulong) page_get_page_no(page_align(rec)));
3886
4020
dict_index_name_print(stderr, trx, index);
3887
4021
fputs(". We try to skip the record.\n",
4019
4155
lock_type = LOCK_REC_NOT_GAP;
4022
err = sel_set_rec_lock(rec, index, offsets,
4158
err = sel_set_rec_lock(btr_pcur_get_block(pcur),
4159
rec, index, offsets,
4023
4160
prebuilt->select_lock_type,
4024
4161
lock_type, thr);
4164
const rec_t* old_vers;
4028
4165
case DB_SUCCESS:
4030
4167
case DB_LOCK_WAIT:
4128
4265
rec = old_vers;
4130
} else if (!lock_sec_rec_cons_read_sees(rec, index,
4267
} else if (!lock_sec_rec_cons_read_sees(rec, trx->read_view)) {
4132
4268
/* We are looking into a non-clustered index,
4133
4269
and to get the right version of the record we
4134
4270
have to look also into the clustered index: this
4203
4338
/* Get the clustered index record if needed, if we did not do the
4204
4339
search using the clustered index. */
4205
4341
if (get_clust_rec || (index != clust_index &&
4206
prebuilt->need_to_access_clustered)) {
4342
prebuilt->need_to_access_clustered)) {
4208
4344
/* We use a 'goto' to the preceding label if a consistent
4209
4345
read of a secondary index record requires us to look up old
4210
4346
versions of the associated clustered index record. */
4212
4348
ut_ad(rec_offs_validate(rec, index, offsets));
4214
4350
/* It was a non-clustered index and we must fetch also the
4215
4351
clustered index record */
4277
4413
result_rec != rec ? clust_index : index,
4416
/* At this point, the clustered index record is protected
4417
by a page latch that was acquired when pcur was positioned.
4418
The latch will not be released until mtr_commit(&mtr). */
4280
4420
if ((match_mode == ROW_SEL_EXACT
4281
|| prebuilt->n_rows_fetched >= DRIZZLE_FETCH_CACHE_THRESHOLD)
4421
|| prebuilt->n_rows_fetched >= MYSQL_FETCH_CACHE_THRESHOLD)
4282
4422
&& prebuilt->select_lock_type == LOCK_NONE
4283
4423
&& !prebuilt->templ_contains_blob
4284
4424
&& !prebuilt->clust_index_was_generated
4285
4425
&& !prebuilt->used_in_HANDLER
4286
4426
&& prebuilt->template_type
4287
!= ROW_DRIZZLE_DUMMY_TEMPLATE) {
4427
!= ROW_MYSQL_DUMMY_TEMPLATE) {
4289
4429
/* Inside an update, for example, we do not cache rows,
4290
4430
since we may use the cursor position to do the actual
4294
4434
are BLOBs in the fields to be fetched. In HANDLER we do
4295
4435
not cache rows because there the cursor is a scrollable
4297
some_fields_in_buffer= (index != clust_index &&
4437
some_fields_in_buffer= (index != clust_index &&
4298
4438
prebuilt->idx_cond_func);
4300
4440
row_sel_push_cache_row_for_mysql(prebuilt, result_rec,
4302
some_fields_in_buffer?
4303
prebuilt->n_index_fields: 0,
4305
if (prebuilt->n_fetch_cached == DRIZZLE_FETCH_CACHE_SIZE) {
4442
some_fields_in_buffer?
4443
prebuilt->n_index_fields: 0,
4445
if (prebuilt->n_fetch_cached == MYSQL_FETCH_CACHE_SIZE) {
4312
if (prebuilt->template_type == ROW_DRIZZLE_DUMMY_TEMPLATE) {
4452
if (prebuilt->template_type == ROW_MYSQL_DUMMY_TEMPLATE) {
4313
4453
memcpy(buf + 4, result_rec
4314
4454
- rec_offs_extra_size(offsets),
4315
4455
rec_offs_size(offsets));
4360
4498
btr_pcur_store_position(pcur, &mtr);
4363
4503
goto normal_return;
4366
4506
/* Reset the old and new "did semi-consistent read" flags. */
4367
get_clust_rec= FALSE;
4368
4507
if (UNIV_UNLIKELY(prebuilt->row_read_type
4369
4508
== ROW_READ_DID_SEMI_CONSISTENT)) {
4370
4509
prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
4545
4684
/***********************************************************************
4546
4685
Checks if MySQL at the moment is allowed for this table to retrieve a
4547
4686
consistent read result, or store it to the query cache. */
4550
4689
row_search_check_if_query_cache_permitted(
4551
4690
/*======================================*/
4603
4742
Read the AUTOINC column from the current row. If the value is less than
4604
4743
0 and the type is not unsigned then we reset the value to 0. */
4607
4746
row_search_autoinc_read_column(
4608
4747
/*===========================*/
4609
4748
/* out: value read from the column */
4610
4749
dict_index_t* index, /* in: index to read from */
4611
rec_t* rec, /* in: current rec */
4750
const rec_t* rec, /* in: current rec */
4612
4751
ulint col_no, /* in: column number */
4613
4752
ibool unsigned_type) /* in: signed or unsigned flag */
4616
4755
const byte* data;
4618
4757
mem_heap_t* heap = NULL;
4619
/* Our requirement is that dest should be word aligned. */
4620
byte dest[sizeof(value)];
4621
4758
ulint offsets_[REC_OFFS_NORMAL_SIZE];
4622
4759
ulint* offsets = offsets_;
4624
*offsets_ = sizeof offsets_ / sizeof *offsets_;
4761
rec_offs_init(offsets_);
4626
4763
offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
4630
4767
ut_a(len != UNIV_SQL_NULL);
4631
4768
ut_a(len <= sizeof value);
4633
mach_read_int_type(dest, data, len, unsigned_type);
4635
/* The assumption here is that the AUTOINC value can't be negative
4636
and that dest is word aligned. */
4639
value = *(ib_longlong*) dest;
4643
value = *(ib_uint32_t*) dest;
4647
value = *(ib_uint32_t*) dest;
4652
value = *(uint16_t *) dest;
4770
/* we assume AUTOINC value cannot be negative */
4771
value = mach_read_int_type(data, len, unsigned_type);
4663
4773
if (UNIV_LIKELY_NULL(heap)) {
4664
4774
mem_heap_free(heap);
4667
if (!unsigned_type && value < 0) {
4777
if (!unsigned_type && (ib_int64_t) value < 0) {
4703
4813
column name can't be found in index */
4704
4814
dict_index_t* index, /* in: index to search */
4705
4815
const char* col_name, /* in: name of autoinc column */
4706
ib_longlong* value) /* out: AUTOINC value read */
4816
ib_uint64_t* value) /* out: AUTOINC value read */
4736
4846
FALSE, index, BTR_SEARCH_LEAF, &pcur, TRUE, &mtr);
4738
4848
if (page_get_n_recs(btr_pcur_get_page(&pcur)) > 0) {
4741
4851
rec = row_search_autoinc_get_rec(&pcur, &mtr);