~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

Tags: innodb-plugin-1.0.1
Imported 1.0.1 with clean - with no changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*******************************************************
 
2
Select
 
3
 
 
4
(c) 1997 Innobase Oy
 
5
 
 
6
Created 12/19/1997 Heikki Tuuri
 
7
*******************************************************/
 
8
 
 
9
#include "row0sel.h"
 
10
 
 
11
#ifdef UNIV_NONINL
 
12
#include "row0sel.ic"
 
13
#endif
 
14
 
 
15
#include "dict0dict.h"
 
16
#include "dict0boot.h"
 
17
#include "trx0undo.h"
 
18
#include "trx0trx.h"
 
19
#include "btr0btr.h"
 
20
#include "btr0cur.h"
 
21
#include "btr0sea.h"
 
22
#include "mach0data.h"
 
23
#include "que0que.h"
 
24
#include "row0upd.h"
 
25
#include "row0row.h"
 
26
#include "row0vers.h"
 
27
#include "rem0cmp.h"
 
28
#include "lock0lock.h"
 
29
#include "eval0eval.h"
 
30
#include "pars0sym.h"
 
31
#include "pars0pars.h"
 
32
#include "row0mysql.h"
 
33
#include "read0read.h"
 
34
#include "buf0lru.h"
 
35
 
 
36
/* Maximum number of rows to prefetch; MySQL interface has another parameter */
 
37
#define SEL_MAX_N_PREFETCH      16
 
38
 
 
39
/* Number of rows fetched, after which to start prefetching; MySQL interface
 
40
has another parameter */
 
41
#define SEL_PREFETCH_LIMIT      1
 
42
 
 
43
/* When a select has accessed about this many pages, it returns control back
 
44
to que_run_threads: this is to allow canceling runaway queries */
 
45
 
 
46
#define SEL_COST_LIMIT  100
 
47
 
 
48
/* Flags for search shortcut */
 
49
#define SEL_FOUND       0
 
50
#define SEL_EXHAUSTED   1
 
51
#define SEL_RETRY       2
 
52
 
 
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
 
56
index record.
 
57
NOTE: the comparison is NOT done as a binary comparison, but character
 
58
fields are compared with collation! */
 
59
static
 
60
ibool
 
61
row_sel_sec_rec_is_for_blob(
 
62
/*========================*/
 
63
                                        /* out: TRUE if the columns
 
64
                                        are equal */
 
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 */
 
81
{
 
82
        ulint   len;
 
83
        byte    buf[DICT_MAX_INDEX_COL_LEN];
 
84
 
 
85
        len = btr_copy_externally_stored_field_prefix(buf, sizeof buf,
 
86
                                                      zip_size,
 
87
                                                      clust_field, clust_len);
 
88
        len = dtype_get_at_most_n_mbchars(prtype, mbminlen, mbmaxlen,
 
89
                                          sec_len, len, (const char*) buf);
 
90
 
 
91
        return(!cmp_data_data(mtype, prtype, buf, len, sec_field, sec_len));
 
92
}
 
93
 
 
94
/************************************************************************
 
95
Returns TRUE if the user-defined column values in a secondary index record
 
96
are alphabetically the same as the corresponding columns in the clustered
 
97
index record.
 
98
NOTE: the comparison is NOT done as a binary comparison, but character
 
99
fields are compared with collation! */
 
100
static
 
101
ibool
 
102
row_sel_sec_rec_is_for_clust_rec(
 
103
/*=============================*/
 
104
                                        /* out: TRUE if the secondary
 
105
                                        record is equal to the corresponding
 
106
                                        fields in the clustered record,
 
107
                                        when compared with collation */
 
108
        const rec_t*    sec_rec,        /* in: secondary index record */
 
109
        dict_index_t*   sec_index,      /* in: secondary index */
 
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 */
 
114
        dict_index_t*   clust_index)    /* in: clustered index */
 
115
{
 
116
        const byte*     sec_field;
 
117
        ulint           sec_len;
 
118
        const byte*     clust_field;
 
119
        ulint           n;
 
120
        ulint           i;
 
121
        mem_heap_t*     heap            = NULL;
 
122
        ulint           clust_offsets_[REC_OFFS_NORMAL_SIZE];
 
123
        ulint           sec_offsets_[REC_OFFS_SMALL_SIZE];
 
124
        ulint*          clust_offs      = clust_offsets_;
 
125
        ulint*          sec_offs        = sec_offsets_;
 
126
        ibool           is_equal        = TRUE;
 
127
 
 
128
        rec_offs_init(clust_offsets_);
 
129
        rec_offs_init(sec_offsets_);
 
130
 
 
131
        if (rec_get_deleted_flag(clust_rec,
 
132
                                 dict_table_is_comp(clust_index->table))) {
 
133
 
 
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. */
 
138
                return(FALSE);
 
139
        }
 
140
 
 
141
        clust_offs = rec_get_offsets(clust_rec, clust_index, clust_offs,
 
142
                                     ULINT_UNDEFINED, &heap);
 
143
        sec_offs = rec_get_offsets(sec_rec, sec_index, sec_offs,
 
144
                                   ULINT_UNDEFINED, &heap);
 
145
 
 
146
        n = dict_index_get_n_ordering_defined_by_user(sec_index);
 
147
 
 
148
        for (i = 0; i < n; i++) {
 
149
                const dict_field_t*     ifield;
 
150
                const dict_col_t*       col;
 
151
                ulint                   clust_pos;
 
152
                ulint                   clust_len;
 
153
                ulint                   len;
 
154
 
 
155
                ifield = dict_index_get_nth_field(sec_index, i);
 
156
                col = dict_field_get_col(ifield);
 
157
                clust_pos = dict_col_get_clust_pos(col, clust_index);
 
158
 
 
159
                clust_field = rec_get_nth_field(
 
160
                        clust_rec, clust_offs, clust_pos, &clust_len);
 
161
                sec_field = rec_get_nth_field(sec_rec, sec_offs, i, &sec_len);
 
162
 
 
163
                len = clust_len;
 
164
 
 
165
                if (ifield->prefix_len > 0 && len != UNIV_SQL_NULL) {
 
166
 
 
167
                        if (rec_offs_nth_extern(clust_offs, clust_pos)) {
 
168
                                len -= BTR_EXTERN_FIELD_REF_SIZE;
 
169
                        }
 
170
 
 
171
                        len = dtype_get_at_most_n_mbchars(
 
172
                                col->prtype, col->mbminlen, col->mbmaxlen,
 
173
                                ifield->prefix_len, len, (char*) clust_field);
 
174
 
 
175
                        if (rec_offs_nth_extern(clust_offs, clust_pos)
 
176
                            && len < sec_len) {
 
177
                                if (!row_sel_sec_rec_is_for_blob(
 
178
                                            col->mtype, col->prtype,
 
179
                                            col->mbminlen, col->mbmaxlen,
 
180
                                            clust_field, clust_len,
 
181
                                            sec_field, sec_len,
 
182
                                            dict_table_zip_size(
 
183
                                                    clust_index->table))) {
 
184
                                        goto inequal;
 
185
                                }
 
186
 
 
187
                                continue;
 
188
                        }
 
189
                }
 
190
 
 
191
                if (0 != cmp_data_data(col->mtype, col->prtype,
 
192
                                       clust_field, len,
 
193
                                       sec_field, sec_len)) {
 
194
inequal:
 
195
                        is_equal = FALSE;
 
196
                        goto func_exit;
 
197
                }
 
198
        }
 
199
 
 
200
func_exit:
 
201
        if (UNIV_LIKELY_NULL(heap)) {
 
202
                mem_heap_free(heap);
 
203
        }
 
204
        return(is_equal);
 
205
}
 
206
 
 
207
/*************************************************************************
 
208
Creates a select node struct. */
 
209
UNIV_INTERN
 
210
sel_node_t*
 
211
sel_node_create(
 
212
/*============*/
 
213
                                /* out, own: select node struct */
 
214
        mem_heap_t*     heap)   /* in: memory heap where created */
 
215
{
 
216
        sel_node_t*     node;
 
217
 
 
218
        node = mem_heap_alloc(heap, sizeof(sel_node_t));
 
219
        node->common.type = QUE_NODE_SELECT;
 
220
        node->state = SEL_NODE_OPEN;
 
221
 
 
222
        node->select_will_do_update = FALSE;
 
223
        node->latch_mode = BTR_SEARCH_LEAF;
 
224
 
 
225
        node->plans = NULL;
 
226
 
 
227
        return(node);
 
228
}
 
229
 
 
230
/*************************************************************************
 
231
Frees the memory private to a select node when a query graph is freed,
 
232
does not free the heap where the node was originally created. */
 
233
UNIV_INTERN
 
234
void
 
235
sel_node_free_private(
 
236
/*==================*/
 
237
        sel_node_t*     node)   /* in: select node struct */
 
238
{
 
239
        ulint   i;
 
240
        plan_t* plan;
 
241
 
 
242
        if (node->plans != NULL) {
 
243
                for (i = 0; i < node->n_tables; i++) {
 
244
                        plan = sel_node_get_nth_plan(node, i);
 
245
 
 
246
                        btr_pcur_close(&(plan->pcur));
 
247
                        btr_pcur_close(&(plan->clust_pcur));
 
248
 
 
249
                        if (plan->old_vers_heap) {
 
250
                                mem_heap_free(plan->old_vers_heap);
 
251
                        }
 
252
                }
 
253
        }
 
254
}
 
255
 
 
256
/*************************************************************************
 
257
Evaluates the values in a select list. If there are aggregate functions,
 
258
their argument value is added to the aggregate total. */
 
259
UNIV_INLINE
 
260
void
 
261
sel_eval_select_list(
 
262
/*=================*/
 
263
        sel_node_t*     node)   /* in: select node */
 
264
{
 
265
        que_node_t*     exp;
 
266
 
 
267
        exp = node->select_list;
 
268
 
 
269
        while (exp) {
 
270
                eval_exp(exp);
 
271
 
 
272
                exp = que_node_get_next(exp);
 
273
        }
 
274
}
 
275
 
 
276
/*************************************************************************
 
277
Assigns the values in the select list to the possible into-variables in
 
278
SELECT ... INTO ... */
 
279
UNIV_INLINE
 
280
void
 
281
sel_assign_into_var_values(
 
282
/*=======================*/
 
283
        sym_node_t*     var,    /* in: first variable in a list of variables */
 
284
        sel_node_t*     node)   /* in: select node */
 
285
{
 
286
        que_node_t*     exp;
 
287
 
 
288
        if (var == NULL) {
 
289
 
 
290
                return;
 
291
        }
 
292
 
 
293
        exp = node->select_list;
 
294
 
 
295
        while (var) {
 
296
                ut_ad(exp);
 
297
 
 
298
                eval_node_copy_val(var->alias, exp);
 
299
 
 
300
                exp = que_node_get_next(exp);
 
301
                var = que_node_get_next(var);
 
302
        }
 
303
}
 
304
 
 
305
/*************************************************************************
 
306
Resets the aggregate value totals in the select list of an aggregate type
 
307
query. */
 
308
UNIV_INLINE
 
309
void
 
310
sel_reset_aggregate_vals(
 
311
/*=====================*/
 
312
        sel_node_t*     node)   /* in: select node */
 
313
{
 
314
        func_node_t*    func_node;
 
315
 
 
316
        ut_ad(node->is_aggregate);
 
317
 
 
318
        func_node = node->select_list;
 
319
 
 
320
        while (func_node) {
 
321
                eval_node_set_int_val(func_node, 0);
 
322
 
 
323
                func_node = que_node_get_next(func_node);
 
324
        }
 
325
 
 
326
        node->aggregate_already_fetched = FALSE;
 
327
}
 
328
 
 
329
/*************************************************************************
 
330
Copies the input variable values when an explicit cursor is opened. */
 
331
UNIV_INLINE
 
332
void
 
333
row_sel_copy_input_variable_vals(
 
334
/*=============================*/
 
335
        sel_node_t*     node)   /* in: select node */
 
336
{
 
337
        sym_node_t*     var;
 
338
 
 
339
        var = UT_LIST_GET_FIRST(node->copy_variables);
 
340
 
 
341
        while (var) {
 
342
                eval_node_copy_val(var, var->alias);
 
343
 
 
344
                var->indirection = NULL;
 
345
 
 
346
                var = UT_LIST_GET_NEXT(col_var_list, var);
 
347
        }
 
348
}
 
349
 
 
350
/*************************************************************************
 
351
Fetches the column values from a record. */
 
352
static
 
353
void
 
354
row_sel_fetch_columns(
 
355
/*==================*/
 
356
        dict_index_t*   index,  /* in: record index */
 
357
        const rec_t*    rec,    /* in: record in a clustered or non-clustered
 
358
                                index; must be protected by a page latch */
 
359
        const ulint*    offsets,/* in: rec_get_offsets(rec, index) */
 
360
        sym_node_t*     column) /* in: first column in a column list, or
 
361
                                NULL */
 
362
{
 
363
        dfield_t*       val;
 
364
        ulint           index_type;
 
365
        ulint           field_no;
 
366
        const byte*     data;
 
367
        ulint           len;
 
368
 
 
369
        ut_ad(rec_offs_validate(rec, index, offsets));
 
370
 
 
371
        if (dict_index_is_clust(index)) {
 
372
                index_type = SYM_CLUST_FIELD_NO;
 
373
        } else {
 
374
                index_type = SYM_SEC_FIELD_NO;
 
375
        }
 
376
 
 
377
        while (column) {
 
378
                mem_heap_t*     heap = NULL;
 
379
                ibool           needs_copy;
 
380
 
 
381
                field_no = column->field_nos[index_type];
 
382
 
 
383
                if (field_no != ULINT_UNDEFINED) {
 
384
 
 
385
                        if (UNIV_UNLIKELY(rec_offs_nth_extern(offsets,
 
386
                                                              field_no))) {
 
387
 
 
388
                                /* Copy an externally stored field to the
 
389
                                temporary heap */
 
390
 
 
391
                                heap = mem_heap_create(1);
 
392
 
 
393
                                data = btr_rec_copy_externally_stored_field(
 
394
                                        rec, offsets,
 
395
                                        dict_table_zip_size(index->table),
 
396
                                        field_no, &len, heap);
 
397
 
 
398
                                ut_a(len != UNIV_SQL_NULL);
 
399
 
 
400
                                needs_copy = TRUE;
 
401
                        } else {
 
402
                                data = rec_get_nth_field(rec, offsets,
 
403
                                                         field_no, &len);
 
404
 
 
405
                                if (len == UNIV_SQL_NULL) {
 
406
                                        len = UNIV_SQL_NULL;
 
407
                                }
 
408
 
 
409
                                needs_copy = column->copy_val;
 
410
                        }
 
411
 
 
412
                        if (needs_copy) {
 
413
                                eval_node_copy_and_alloc_val(column, data,
 
414
                                                             len);
 
415
                        } else {
 
416
                                val = que_node_get_val(column);
 
417
                                dfield_set_data(val, data, len);
 
418
                        }
 
419
 
 
420
                        if (UNIV_LIKELY_NULL(heap)) {
 
421
                                mem_heap_free(heap);
 
422
                        }
 
423
                }
 
424
 
 
425
                column = UT_LIST_GET_NEXT(col_var_list, column);
 
426
        }
 
427
}
 
428
 
 
429
/*************************************************************************
 
430
Allocates a prefetch buffer for a column when prefetch is first time done. */
 
431
static
 
432
void
 
433
sel_col_prefetch_buf_alloc(
 
434
/*=======================*/
 
435
        sym_node_t*     column) /* in: symbol table node for a column */
 
436
{
 
437
        sel_buf_t*      sel_buf;
 
438
        ulint           i;
 
439
 
 
440
        ut_ad(que_node_get_type(column) == QUE_NODE_SYMBOL);
 
441
 
 
442
        column->prefetch_buf = mem_alloc(SEL_MAX_N_PREFETCH
 
443
                                         * sizeof(sel_buf_t));
 
444
        for (i = 0; i < SEL_MAX_N_PREFETCH; i++) {
 
445
                sel_buf = column->prefetch_buf + i;
 
446
 
 
447
                sel_buf->data = NULL;
 
448
 
 
449
                sel_buf->val_buf_size = 0;
 
450
        }
 
451
}
 
452
 
 
453
/*************************************************************************
 
454
Frees a prefetch buffer for a column, including the dynamically allocated
 
455
memory for data stored there. */
 
456
UNIV_INTERN
 
457
void
 
458
sel_col_prefetch_buf_free(
 
459
/*======================*/
 
460
        sel_buf_t*      prefetch_buf)   /* in, own: prefetch buffer */
 
461
{
 
462
        sel_buf_t*      sel_buf;
 
463
        ulint           i;
 
464
 
 
465
        for (i = 0; i < SEL_MAX_N_PREFETCH; i++) {
 
466
                sel_buf = prefetch_buf + i;
 
467
 
 
468
                if (sel_buf->val_buf_size > 0) {
 
469
 
 
470
                        mem_free(sel_buf->data);
 
471
                }
 
472
        }
 
473
}
 
474
 
 
475
/*************************************************************************
 
476
Pops the column values for a prefetched, cached row from the column prefetch
 
477
buffers and places them to the val fields in the column nodes. */
 
478
static
 
479
void
 
480
sel_pop_prefetched_row(
 
481
/*===================*/
 
482
        plan_t* plan)   /* in: plan node for a table */
 
483
{
 
484
        sym_node_t*     column;
 
485
        sel_buf_t*      sel_buf;
 
486
        dfield_t*       val;
 
487
        byte*           data;
 
488
        ulint           len;
 
489
        ulint           val_buf_size;
 
490
 
 
491
        ut_ad(plan->n_rows_prefetched > 0);
 
492
 
 
493
        column = UT_LIST_GET_FIRST(plan->columns);
 
494
 
 
495
        while (column) {
 
496
                val = que_node_get_val(column);
 
497
 
 
498
                if (!column->copy_val) {
 
499
                        /* We did not really push any value for the
 
500
                        column */
 
501
 
 
502
                        ut_ad(!column->prefetch_buf);
 
503
                        ut_ad(que_node_get_val_buf_size(column) == 0);
 
504
                        ut_d(dfield_set_null(val));
 
505
 
 
506
                        goto next_col;
 
507
                }
 
508
 
 
509
                ut_ad(column->prefetch_buf);
 
510
                ut_ad(!dfield_is_ext(val));
 
511
 
 
512
                sel_buf = column->prefetch_buf + plan->first_prefetched;
 
513
 
 
514
                data = sel_buf->data;
 
515
                len = sel_buf->len;
 
516
                val_buf_size = sel_buf->val_buf_size;
 
517
 
 
518
                /* We must keep track of the allocated memory for
 
519
                column values to be able to free it later: therefore
 
520
                we swap the values for sel_buf and val */
 
521
 
 
522
                sel_buf->data = dfield_get_data(val);
 
523
                sel_buf->len = dfield_get_len(val);
 
524
                sel_buf->val_buf_size = que_node_get_val_buf_size(column);
 
525
 
 
526
                dfield_set_data(val, data, len);
 
527
                que_node_set_val_buf_size(column, val_buf_size);
 
528
next_col:
 
529
                column = UT_LIST_GET_NEXT(col_var_list, column);
 
530
        }
 
531
 
 
532
        plan->n_rows_prefetched--;
 
533
 
 
534
        plan->first_prefetched++;
 
535
}
 
536
 
 
537
/*************************************************************************
 
538
Pushes the column values for a prefetched, cached row to the column prefetch
 
539
buffers from the val fields in the column nodes. */
 
540
UNIV_INLINE
 
541
void
 
542
sel_push_prefetched_row(
 
543
/*====================*/
 
544
        plan_t* plan)   /* in: plan node for a table */
 
545
{
 
546
        sym_node_t*     column;
 
547
        sel_buf_t*      sel_buf;
 
548
        dfield_t*       val;
 
549
        byte*           data;
 
550
        ulint           len;
 
551
        ulint           pos;
 
552
        ulint           val_buf_size;
 
553
 
 
554
        if (plan->n_rows_prefetched == 0) {
 
555
                pos = 0;
 
556
                plan->first_prefetched = 0;
 
557
        } else {
 
558
                pos = plan->n_rows_prefetched;
 
559
 
 
560
                /* We have the convention that pushing new rows starts only
 
561
                after the prefetch stack has been emptied: */
 
562
 
 
563
                ut_ad(plan->first_prefetched == 0);
 
564
        }
 
565
 
 
566
        plan->n_rows_prefetched++;
 
567
 
 
568
        ut_ad(pos < SEL_MAX_N_PREFETCH);
 
569
 
 
570
        column = UT_LIST_GET_FIRST(plan->columns);
 
571
 
 
572
        while (column) {
 
573
                if (!column->copy_val) {
 
574
                        /* There is no sense to push pointers to database
 
575
                        page fields when we do not keep latch on the page! */
 
576
 
 
577
                        goto next_col;
 
578
                }
 
579
 
 
580
                if (!column->prefetch_buf) {
 
581
                        /* Allocate a new prefetch buffer */
 
582
 
 
583
                        sel_col_prefetch_buf_alloc(column);
 
584
                }
 
585
 
 
586
                sel_buf = column->prefetch_buf + pos;
 
587
 
 
588
                val = que_node_get_val(column);
 
589
 
 
590
                data = dfield_get_data(val);
 
591
                len = dfield_get_len(val);
 
592
                val_buf_size = que_node_get_val_buf_size(column);
 
593
 
 
594
                /* We must keep track of the allocated memory for
 
595
                column values to be able to free it later: therefore
 
596
                we swap the values for sel_buf and val */
 
597
 
 
598
                dfield_set_data(val, sel_buf->data, sel_buf->len);
 
599
                que_node_set_val_buf_size(column, sel_buf->val_buf_size);
 
600
 
 
601
                sel_buf->data = data;
 
602
                sel_buf->len = len;
 
603
                sel_buf->val_buf_size = val_buf_size;
 
604
next_col:
 
605
                column = UT_LIST_GET_NEXT(col_var_list, column);
 
606
        }
 
607
}
 
608
 
 
609
/*************************************************************************
 
610
Builds a previous version of a clustered index record for a consistent read */
 
611
static
 
612
ulint
 
613
row_sel_build_prev_vers(
 
614
/*====================*/
 
615
                                        /* out: DB_SUCCESS or error code */
 
616
        read_view_t*    read_view,      /* in: read view */
 
617
        dict_index_t*   index,          /* in: plan node for table */
 
618
        rec_t*          rec,            /* in: record in a clustered index */
 
619
        ulint**         offsets,        /* in/out: offsets returned by
 
620
                                        rec_get_offsets(rec, plan->index) */
 
621
        mem_heap_t**    offset_heap,    /* in/out: memory heap from which
 
622
                                        the offsets are allocated */
 
623
        mem_heap_t**    old_vers_heap,  /* out: old version heap to use */
 
624
        rec_t**         old_vers,       /* out: old version, or NULL if the
 
625
                                        record does not exist in the view:
 
626
                                        i.e., it was freshly inserted
 
627
                                        afterwards */
 
628
        mtr_t*          mtr)            /* in: mtr */
 
629
{
 
630
        ulint   err;
 
631
 
 
632
        if (*old_vers_heap) {
 
633
                mem_heap_empty(*old_vers_heap);
 
634
        } else {
 
635
                *old_vers_heap = mem_heap_create(512);
 
636
        }
 
637
 
 
638
        err = row_vers_build_for_consistent_read(
 
639
                rec, mtr, index, offsets, read_view, offset_heap,
 
640
                *old_vers_heap, old_vers);
 
641
        return(err);
 
642
}
 
643
 
 
644
/*************************************************************************
 
645
Builds the last committed version of a clustered index record for a
 
646
semi-consistent read. */
 
647
static
 
648
ulint
 
649
row_sel_build_committed_vers_for_mysql(
 
650
/*===================================*/
 
651
                                        /* out: DB_SUCCESS or error code */
 
652
        dict_index_t*   clust_index,    /* in: clustered index */
 
653
        row_prebuilt_t* prebuilt,       /* in: prebuilt struct */
 
654
        const rec_t*    rec,            /* in: record in a clustered index */
 
655
        ulint**         offsets,        /* in/out: offsets returned by
 
656
                                        rec_get_offsets(rec, clust_index) */
 
657
        mem_heap_t**    offset_heap,    /* in/out: memory heap from which
 
658
                                        the offsets are allocated */
 
659
        const rec_t**   old_vers,       /* out: old version, or NULL if the
 
660
                                        record does not exist in the view:
 
661
                                        i.e., it was freshly inserted
 
662
                                        afterwards */
 
663
        mtr_t*          mtr)            /* in: mtr */
 
664
{
 
665
        ulint   err;
 
666
 
 
667
        if (prebuilt->old_vers_heap) {
 
668
                mem_heap_empty(prebuilt->old_vers_heap);
 
669
        } else {
 
670
                prebuilt->old_vers_heap = mem_heap_create(200);
 
671
        }
 
672
 
 
673
        err = row_vers_build_for_semi_consistent_read(
 
674
                rec, mtr, clust_index, offsets, offset_heap,
 
675
                prebuilt->old_vers_heap, old_vers);
 
676
        return(err);
 
677
}
 
678
 
 
679
/*************************************************************************
 
680
Tests the conditions which determine when the index segment we are searching
 
681
through has been exhausted. */
 
682
UNIV_INLINE
 
683
ibool
 
684
row_sel_test_end_conds(
 
685
/*===================*/
 
686
                        /* out: TRUE if row passed the tests */
 
687
        plan_t* plan)   /* in: plan for the table; the column values must
 
688
                        already have been retrieved and the right sides of
 
689
                        comparisons evaluated */
 
690
{
 
691
        func_node_t*    cond;
 
692
 
 
693
        /* All conditions in end_conds are comparisons of a column to an
 
694
        expression */
 
695
 
 
696
        cond = UT_LIST_GET_FIRST(plan->end_conds);
 
697
 
 
698
        while (cond) {
 
699
                /* Evaluate the left side of the comparison, i.e., get the
 
700
                column value if there is an indirection */
 
701
 
 
702
                eval_sym(cond->args);
 
703
 
 
704
                /* Do the comparison */
 
705
 
 
706
                if (!eval_cmp(cond)) {
 
707
 
 
708
                        return(FALSE);
 
709
                }
 
710
 
 
711
                cond = UT_LIST_GET_NEXT(cond_list, cond);
 
712
        }
 
713
 
 
714
        return(TRUE);
 
715
}
 
716
 
 
717
/*************************************************************************
 
718
Tests the other conditions. */
 
719
UNIV_INLINE
 
720
ibool
 
721
row_sel_test_other_conds(
 
722
/*=====================*/
 
723
                        /* out: TRUE if row passed the tests */
 
724
        plan_t* plan)   /* in: plan for the table; the column values must
 
725
                        already have been retrieved */
 
726
{
 
727
        func_node_t*    cond;
 
728
 
 
729
        cond = UT_LIST_GET_FIRST(plan->other_conds);
 
730
 
 
731
        while (cond) {
 
732
                eval_exp(cond);
 
733
 
 
734
                if (!eval_node_get_ibool_val(cond)) {
 
735
 
 
736
                        return(FALSE);
 
737
                }
 
738
 
 
739
                cond = UT_LIST_GET_NEXT(cond_list, cond);
 
740
        }
 
741
 
 
742
        return(TRUE);
 
743
}
 
744
 
 
745
/*************************************************************************
 
746
Retrieves the clustered index record corresponding to a record in a
 
747
non-clustered index. Does the necessary locking. */
 
748
static
 
749
ulint
 
750
row_sel_get_clust_rec(
 
751
/*==================*/
 
752
                                /* out: DB_SUCCESS or error code */
 
753
        sel_node_t*     node,   /* in: select_node */
 
754
        plan_t*         plan,   /* in: plan node for table */
 
755
        rec_t*          rec,    /* in: record in a non-clustered index */
 
756
        que_thr_t*      thr,    /* in: query thread */
 
757
        rec_t**         out_rec,/* out: clustered record or an old version of
 
758
                                it, NULL if the old version did not exist
 
759
                                in the read view, i.e., it was a fresh
 
760
                                inserted version */
 
761
        mtr_t*          mtr)    /* in: mtr used to get access to the
 
762
                                non-clustered record; the same mtr is used to
 
763
                                access the clustered index */
 
764
{
 
765
        dict_index_t*   index;
 
766
        rec_t*          clust_rec;
 
767
        rec_t*          old_vers;
 
768
        ulint           err;
 
769
        mem_heap_t*     heap            = NULL;
 
770
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
 
771
        ulint*          offsets         = offsets_;
 
772
        rec_offs_init(offsets_);
 
773
 
 
774
        *out_rec = NULL;
 
775
 
 
776
        offsets = rec_get_offsets(rec,
 
777
                                  btr_pcur_get_btr_cur(&plan->pcur)->index,
 
778
                                  offsets, ULINT_UNDEFINED, &heap);
 
779
 
 
780
        row_build_row_ref_fast(plan->clust_ref, plan->clust_map, rec, offsets);
 
781
 
 
782
        index = dict_table_get_first_index(plan->table);
 
783
 
 
784
        btr_pcur_open_with_no_init(index, plan->clust_ref, PAGE_CUR_LE,
 
785
                                   node->latch_mode, &(plan->clust_pcur),
 
786
                                   0, mtr);
 
787
 
 
788
        clust_rec = btr_pcur_get_rec(&(plan->clust_pcur));
 
789
 
 
790
        /* Note: only if the search ends up on a non-infimum record is the
 
791
        low_match value the real match to the search tuple */
 
792
 
 
793
        if (!page_rec_is_user_rec(clust_rec)
 
794
            || btr_pcur_get_low_match(&(plan->clust_pcur))
 
795
            < dict_index_get_n_unique(index)) {
 
796
 
 
797
                ut_a(rec_get_deleted_flag(rec,
 
798
                                          dict_table_is_comp(plan->table)));
 
799
                ut_a(node->read_view);
 
800
 
 
801
                /* In a rare case it is possible that no clust rec is found
 
802
                for a delete-marked secondary index record: if in row0umod.c
 
803
                in row_undo_mod_remove_clust_low() we have already removed
 
804
                the clust rec, while purge is still cleaning and removing
 
805
                secondary index records associated with earlier versions of
 
806
                the clustered index record. In that case we know that the
 
807
                clustered index record did not exist in the read view of
 
808
                trx. */
 
809
 
 
810
                goto func_exit;
 
811
        }
 
812
 
 
813
        offsets = rec_get_offsets(clust_rec, index, offsets,
 
814
                                  ULINT_UNDEFINED, &heap);
 
815
 
 
816
        if (!node->read_view) {
 
817
                /* Try to place a lock on the index record */
 
818
 
 
819
                /* If innodb_locks_unsafe_for_binlog option is used
 
820
                or this session is using READ COMMITTED isolation level
 
821
                we lock only the record, i.e., next-key locking is
 
822
                not used. */
 
823
                ulint   lock_type;
 
824
                trx_t*  trx;
 
825
 
 
826
                trx = thr_get_trx(thr);
 
827
 
 
828
                if (srv_locks_unsafe_for_binlog
 
829
                    || trx->isolation_level == TRX_ISO_READ_COMMITTED) {
 
830
                        lock_type = LOCK_REC_NOT_GAP;
 
831
                } else {
 
832
                        lock_type = LOCK_ORDINARY;
 
833
                }
 
834
 
 
835
                err = lock_clust_rec_read_check_and_lock(
 
836
                        0, btr_pcur_get_block(&plan->clust_pcur),
 
837
                        clust_rec, index, offsets,
 
838
                        node->row_lock_mode, lock_type, thr);
 
839
 
 
840
                if (err != DB_SUCCESS) {
 
841
 
 
842
                        goto err_exit;
 
843
                }
 
844
        } else {
 
845
                /* This is a non-locking consistent read: if necessary, fetch
 
846
                a previous version of the record */
 
847
 
 
848
                old_vers = NULL;
 
849
 
 
850
                if (!lock_clust_rec_cons_read_sees(clust_rec, index, offsets,
 
851
                                                   node->read_view)) {
 
852
 
 
853
                        err = row_sel_build_prev_vers(
 
854
                                node->read_view, index, clust_rec,
 
855
                                &offsets, &heap, &plan->old_vers_heap,
 
856
                                &old_vers, mtr);
 
857
 
 
858
                        if (err != DB_SUCCESS) {
 
859
 
 
860
                                goto err_exit;
 
861
                        }
 
862
 
 
863
                        clust_rec = old_vers;
 
864
 
 
865
                        if (clust_rec == NULL) {
 
866
                                goto func_exit;
 
867
                        }
 
868
                }
 
869
 
 
870
                /* If we had to go to an earlier version of row or the
 
871
                secondary index record is delete marked, then it may be that
 
872
                the secondary index record corresponding to clust_rec
 
873
                (or old_vers) is not rec; in that case we must ignore
 
874
                such row because in our snapshot rec would not have existed.
 
875
                Remember that from rec we cannot see directly which transaction
 
876
                id corresponds to it: we have to go to the clustered index
 
877
                record. A query where we want to fetch all rows where
 
878
                the secondary index value is in some interval would return
 
879
                a wrong result if we would not drop rows which we come to
 
880
                visit through secondary index records that would not really
 
881
                exist in our snapshot. */
 
882
 
 
883
                if ((old_vers
 
884
                     || rec_get_deleted_flag(rec, dict_table_is_comp(
 
885
                                                     plan->table)))
 
886
                    && !row_sel_sec_rec_is_for_clust_rec(rec, plan->index,
 
887
                                                         clust_rec, index)) {
 
888
                        goto func_exit;
 
889
                }
 
890
        }
 
891
 
 
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). */
 
896
 
 
897
        row_sel_fetch_columns(index, clust_rec, offsets,
 
898
                              UT_LIST_GET_FIRST(plan->columns));
 
899
        *out_rec = clust_rec;
 
900
func_exit:
 
901
        err = DB_SUCCESS;
 
902
err_exit:
 
903
        if (UNIV_LIKELY_NULL(heap)) {
 
904
                mem_heap_free(heap);
 
905
        }
 
906
        return(err);
 
907
}
 
908
 
 
909
/*************************************************************************
 
910
Sets a lock on a record. */
 
911
UNIV_INLINE
 
912
ulint
 
913
sel_set_rec_lock(
 
914
/*=============*/
 
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
 
922
                                        LOC_REC_NOT_GAP */
 
923
        que_thr_t*              thr)    /* in: query thread */
 
924
{
 
925
        trx_t*  trx;
 
926
        ulint   err;
 
927
 
 
928
        trx = thr_get_trx(thr);
 
929
 
 
930
        if (UT_LIST_GET_LEN(trx->trx_locks) > 10000) {
 
931
                if (buf_LRU_buf_pool_running_out()) {
 
932
 
 
933
                        return(DB_LOCK_TABLE_FULL);
 
934
                }
 
935
        }
 
936
 
 
937
        if (dict_index_is_clust(index)) {
 
938
                err = lock_clust_rec_read_check_and_lock(
 
939
                        0, block, rec, index, offsets, mode, type, thr);
 
940
        } else {
 
941
                err = lock_sec_rec_read_check_and_lock(
 
942
                        0, block, rec, index, offsets, mode, type, thr);
 
943
        }
 
944
 
 
945
        return(err);
 
946
}
 
947
 
 
948
/*************************************************************************
 
949
Opens a pcur to a table index. */
 
950
static
 
951
void
 
952
row_sel_open_pcur(
 
953
/*==============*/
 
954
        sel_node_t*     node,           /* in: select node */
 
955
        plan_t*         plan,           /* in: table plan */
 
956
        ibool           search_latch_locked,
 
957
                                        /* in: TRUE if the thread currently
 
958
                                        has the search latch locked in
 
959
                                        s-mode */
 
960
        mtr_t*          mtr)            /* in: mtr */
 
961
{
 
962
        dict_index_t*   index;
 
963
        func_node_t*    cond;
 
964
        que_node_t*     exp;
 
965
        ulint           n_fields;
 
966
        ulint           has_search_latch = 0;   /* RW_S_LATCH or 0 */
 
967
        ulint           i;
 
968
 
 
969
        if (search_latch_locked) {
 
970
                has_search_latch = RW_S_LATCH;
 
971
        }
 
972
 
 
973
        index = plan->index;
 
974
 
 
975
        /* Calculate the value of the search tuple: the exact match columns
 
976
        get their expressions evaluated when we evaluate the right sides of
 
977
        end_conds */
 
978
 
 
979
        cond = UT_LIST_GET_FIRST(plan->end_conds);
 
980
 
 
981
        while (cond) {
 
982
                eval_exp(que_node_get_next(cond->args));
 
983
 
 
984
                cond = UT_LIST_GET_NEXT(cond_list, cond);
 
985
        }
 
986
 
 
987
        if (plan->tuple) {
 
988
                n_fields = dtuple_get_n_fields(plan->tuple);
 
989
 
 
990
                if (plan->n_exact_match < n_fields) {
 
991
                        /* There is a non-exact match field which must be
 
992
                        evaluated separately */
 
993
 
 
994
                        eval_exp(plan->tuple_exps[n_fields - 1]);
 
995
                }
 
996
 
 
997
                for (i = 0; i < n_fields; i++) {
 
998
                        exp = plan->tuple_exps[i];
 
999
 
 
1000
                        dfield_copy_data(dtuple_get_nth_field(plan->tuple, i),
 
1001
                                         que_node_get_val(exp));
 
1002
                }
 
1003
 
 
1004
                /* Open pcur to the index */
 
1005
 
 
1006
                btr_pcur_open_with_no_init(index, plan->tuple, plan->mode,
 
1007
                                           node->latch_mode, &(plan->pcur),
 
1008
                                           has_search_latch, mtr);
 
1009
        } else {
 
1010
                /* Open the cursor to the start or the end of the index
 
1011
                (FALSE: no init) */
 
1012
 
 
1013
                btr_pcur_open_at_index_side(plan->asc, index, node->latch_mode,
 
1014
                                            &(plan->pcur), FALSE, mtr);
 
1015
        }
 
1016
 
 
1017
        ut_ad(plan->n_rows_prefetched == 0);
 
1018
        ut_ad(plan->n_rows_fetched == 0);
 
1019
        ut_ad(plan->cursor_at_end == FALSE);
 
1020
 
 
1021
        plan->pcur_is_open = TRUE;
 
1022
}
 
1023
 
 
1024
/*************************************************************************
 
1025
Restores a stored pcur position to a table index. */
 
1026
static
 
1027
ibool
 
1028
row_sel_restore_pcur_pos(
 
1029
/*=====================*/
 
1030
                                /* out: TRUE if the cursor should be moved to
 
1031
                                the next record after we return from this
 
1032
                                function (moved to the previous, in the case
 
1033
                                of a descending cursor) without processing
 
1034
                                again the current cursor record */
 
1035
        sel_node_t*     node,   /* in: select node */
 
1036
        plan_t*         plan,   /* in: table plan */
 
1037
        mtr_t*          mtr)    /* in: mtr */
 
1038
{
 
1039
        ibool   equal_position;
 
1040
        ulint   relative_position;
 
1041
 
 
1042
        ut_ad(!plan->cursor_at_end);
 
1043
 
 
1044
        relative_position = btr_pcur_get_rel_pos(&(plan->pcur));
 
1045
 
 
1046
        equal_position = btr_pcur_restore_position(node->latch_mode,
 
1047
                                                   &(plan->pcur), mtr);
 
1048
 
 
1049
        /* If the cursor is traveling upwards, and relative_position is
 
1050
 
 
1051
        (1) BTR_PCUR_BEFORE: this is not allowed, as we did not have a lock
 
1052
        yet on the successor of the page infimum;
 
1053
        (2) BTR_PCUR_AFTER: btr_pcur_restore_position placed the cursor on the
 
1054
        first record GREATER than the predecessor of a page supremum; we have
 
1055
        not yet processed the cursor record: no need to move the cursor to the
 
1056
        next record;
 
1057
        (3) BTR_PCUR_ON: btr_pcur_restore_position placed the cursor on the
 
1058
        last record LESS or EQUAL to the old stored user record; (a) if
 
1059
        equal_position is FALSE, this means that the cursor is now on a record
 
1060
        less than the old user record, and we must move to the next record;
 
1061
        (b) if equal_position is TRUE, then if
 
1062
        plan->stored_cursor_rec_processed is TRUE, we must move to the next
 
1063
        record, else there is no need to move the cursor. */
 
1064
 
 
1065
        if (plan->asc) {
 
1066
                if (relative_position == BTR_PCUR_ON) {
 
1067
 
 
1068
                        if (equal_position) {
 
1069
 
 
1070
                                return(plan->stored_cursor_rec_processed);
 
1071
                        }
 
1072
 
 
1073
                        return(TRUE);
 
1074
                }
 
1075
 
 
1076
                ut_ad(relative_position == BTR_PCUR_AFTER
 
1077
                      || relative_position == BTR_PCUR_AFTER_LAST_IN_TREE);
 
1078
 
 
1079
                return(FALSE);
 
1080
        }
 
1081
 
 
1082
        /* If the cursor is traveling downwards, and relative_position is
 
1083
 
 
1084
        (1) BTR_PCUR_BEFORE: btr_pcur_restore_position placed the cursor on
 
1085
        the last record LESS than the successor of a page infimum; we have not
 
1086
        processed the cursor record: no need to move the cursor;
 
1087
        (2) BTR_PCUR_AFTER: btr_pcur_restore_position placed the cursor on the
 
1088
        first record GREATER than the predecessor of a page supremum; we have
 
1089
        processed the cursor record: we should move the cursor to the previous
 
1090
        record;
 
1091
        (3) BTR_PCUR_ON: btr_pcur_restore_position placed the cursor on the
 
1092
        last record LESS or EQUAL to the old stored user record; (a) if
 
1093
        equal_position is FALSE, this means that the cursor is now on a record
 
1094
        less than the old user record, and we need not move to the previous
 
1095
        record; (b) if equal_position is TRUE, then if
 
1096
        plan->stored_cursor_rec_processed is TRUE, we must move to the previous
 
1097
        record, else there is no need to move the cursor. */
 
1098
 
 
1099
        if (relative_position == BTR_PCUR_BEFORE
 
1100
            || relative_position == BTR_PCUR_BEFORE_FIRST_IN_TREE) {
 
1101
 
 
1102
                return(FALSE);
 
1103
        }
 
1104
 
 
1105
        if (relative_position == BTR_PCUR_ON) {
 
1106
 
 
1107
                if (equal_position) {
 
1108
 
 
1109
                        return(plan->stored_cursor_rec_processed);
 
1110
                }
 
1111
 
 
1112
                return(FALSE);
 
1113
        }
 
1114
 
 
1115
        ut_ad(relative_position == BTR_PCUR_AFTER
 
1116
              || relative_position == BTR_PCUR_AFTER_LAST_IN_TREE);
 
1117
 
 
1118
        return(TRUE);
 
1119
}
 
1120
 
 
1121
/*************************************************************************
 
1122
Resets a plan cursor to a closed state. */
 
1123
UNIV_INLINE
 
1124
void
 
1125
plan_reset_cursor(
 
1126
/*==============*/
 
1127
        plan_t* plan)   /* in: plan */
 
1128
{
 
1129
        plan->pcur_is_open = FALSE;
 
1130
        plan->cursor_at_end = FALSE;
 
1131
        plan->n_rows_fetched = 0;
 
1132
        plan->n_rows_prefetched = 0;
 
1133
}
 
1134
 
 
1135
/*************************************************************************
 
1136
Tries to do a shortcut to fetch a clustered index record with a unique key,
 
1137
using the hash index if possible (not always). */
 
1138
static
 
1139
ulint
 
1140
row_sel_try_search_shortcut(
 
1141
/*========================*/
 
1142
                                /* out: SEL_FOUND, SEL_EXHAUSTED, SEL_RETRY */
 
1143
        sel_node_t*     node,   /* in: select node for a consistent read */
 
1144
        plan_t*         plan,   /* in: plan for a unique search in clustered
 
1145
                                index */
 
1146
        mtr_t*          mtr)    /* in: mtr */
 
1147
{
 
1148
        dict_index_t*   index;
 
1149
        rec_t*          rec;
 
1150
        mem_heap_t*     heap            = NULL;
 
1151
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
 
1152
        ulint*          offsets         = offsets_;
 
1153
        ulint           ret;
 
1154
        rec_offs_init(offsets_);
 
1155
 
 
1156
        index = plan->index;
 
1157
 
 
1158
        ut_ad(node->read_view);
 
1159
        ut_ad(plan->unique_search);
 
1160
        ut_ad(!plan->must_get_clust);
 
1161
#ifdef UNIV_SYNC_DEBUG
 
1162
        ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_SHARED));
 
1163
#endif /* UNIV_SYNC_DEBUG */
 
1164
 
 
1165
        row_sel_open_pcur(node, plan, TRUE, mtr);
 
1166
 
 
1167
        rec = btr_pcur_get_rec(&(plan->pcur));
 
1168
 
 
1169
        if (!page_rec_is_user_rec(rec)) {
 
1170
 
 
1171
                return(SEL_RETRY);
 
1172
        }
 
1173
 
 
1174
        ut_ad(plan->mode == PAGE_CUR_GE);
 
1175
 
 
1176
        /* As the cursor is now placed on a user record after a search with
 
1177
        the mode PAGE_CUR_GE, the up_match field in the cursor tells how many
 
1178
        fields in the user record matched to the search tuple */
 
1179
 
 
1180
        if (btr_pcur_get_up_match(&(plan->pcur)) < plan->n_exact_match) {
 
1181
 
 
1182
                return(SEL_EXHAUSTED);
 
1183
        }
 
1184
 
 
1185
        /* This is a non-locking consistent read: if necessary, fetch
 
1186
        a previous version of the record */
 
1187
 
 
1188
        offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
 
1189
 
 
1190
        if (dict_index_is_clust(index)) {
 
1191
                if (!lock_clust_rec_cons_read_sees(rec, index, offsets,
 
1192
                                                   node->read_view)) {
 
1193
                        ret = SEL_RETRY;
 
1194
                        goto func_exit;
 
1195
                }
 
1196
        } else if (!lock_sec_rec_cons_read_sees(rec, node->read_view)) {
 
1197
 
 
1198
                ret = SEL_RETRY;
 
1199
                goto func_exit;
 
1200
        }
 
1201
 
 
1202
        /* Test the deleted flag. */
 
1203
 
 
1204
        if (rec_get_deleted_flag(rec, dict_table_is_comp(plan->table))) {
 
1205
 
 
1206
                ret = SEL_EXHAUSTED;
 
1207
                goto func_exit;
 
1208
        }
 
1209
 
 
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). */
 
1214
 
 
1215
        row_sel_fetch_columns(index, rec, offsets,
 
1216
                              UT_LIST_GET_FIRST(plan->columns));
 
1217
 
 
1218
        /* Test the rest of search conditions */
 
1219
 
 
1220
        if (!row_sel_test_other_conds(plan)) {
 
1221
 
 
1222
                ret = SEL_EXHAUSTED;
 
1223
                goto func_exit;
 
1224
        }
 
1225
 
 
1226
        ut_ad(plan->pcur.latch_mode == node->latch_mode);
 
1227
 
 
1228
        plan->n_rows_fetched++;
 
1229
        ret = SEL_FOUND;
 
1230
func_exit:
 
1231
        if (UNIV_LIKELY_NULL(heap)) {
 
1232
                mem_heap_free(heap);
 
1233
        }
 
1234
        return(ret);
 
1235
}
 
1236
 
 
1237
/*************************************************************************
 
1238
Performs a select step. */
 
1239
static
 
1240
ulint
 
1241
row_sel(
 
1242
/*====*/
 
1243
                                /* out: DB_SUCCESS or error code */
 
1244
        sel_node_t*     node,   /* in: select node */
 
1245
        que_thr_t*      thr)    /* in: query thread */
 
1246
{
 
1247
        dict_index_t*   index;
 
1248
        plan_t*         plan;
 
1249
        mtr_t           mtr;
 
1250
        ibool           moved;
 
1251
        rec_t*          rec;
 
1252
        rec_t*          old_vers;
 
1253
        rec_t*          clust_rec;
 
1254
        ibool           search_latch_locked;
 
1255
        ibool           consistent_read;
 
1256
 
 
1257
        /* The following flag becomes TRUE when we are doing a
 
1258
        consistent read from a non-clustered index and we must look
 
1259
        at the clustered index to find out the previous delete mark
 
1260
        state of the non-clustered record: */
 
1261
 
 
1262
        ibool           cons_read_requires_clust_rec    = FALSE;
 
1263
        ulint           cost_counter                    = 0;
 
1264
        ibool           cursor_just_opened;
 
1265
        ibool           must_go_to_next;
 
1266
        ibool           leaf_contains_updates           = FALSE;
 
1267
        /* TRUE if select_will_do_update is
 
1268
        TRUE and the current clustered index
 
1269
        leaf page has been updated during
 
1270
        the current mtr: mtr must be committed
 
1271
        at the same time as the leaf x-latch
 
1272
        is released */
 
1273
        ibool           mtr_has_extra_clust_latch       = FALSE;
 
1274
        /* TRUE if the search was made using
 
1275
        a non-clustered index, and we had to
 
1276
        access the clustered record: now &mtr
 
1277
        contains a clustered index latch, and
 
1278
        &mtr must be committed before we move
 
1279
        to the next non-clustered record */
 
1280
        ulint           found_flag;
 
1281
        ulint           err;
 
1282
        mem_heap_t*     heap                            = NULL;
 
1283
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
 
1284
        ulint*          offsets                         = offsets_;
 
1285
        rec_offs_init(offsets_);
 
1286
 
 
1287
        ut_ad(thr->run_node == node);
 
1288
 
 
1289
        search_latch_locked = FALSE;
 
1290
 
 
1291
        if (node->read_view) {
 
1292
                /* In consistent reads, we try to do with the hash index and
 
1293
                not to use the buffer page get. This is to reduce memory bus
 
1294
                load resulting from semaphore operations. The search latch
 
1295
                will be s-locked when we access an index with a unique search
 
1296
                condition, but not locked when we access an index with a
 
1297
                less selective search condition. */
 
1298
 
 
1299
                consistent_read = TRUE;
 
1300
        } else {
 
1301
                consistent_read = FALSE;
 
1302
        }
 
1303
 
 
1304
table_loop:
 
1305
        /* TABLE LOOP
 
1306
        ----------
 
1307
        This is the outer major loop in calculating a join. We come here when
 
1308
        node->fetch_table changes, and after adding a row to aggregate totals
 
1309
        and, of course, when this function is called. */
 
1310
 
 
1311
        ut_ad(leaf_contains_updates == FALSE);
 
1312
        ut_ad(mtr_has_extra_clust_latch == FALSE);
 
1313
 
 
1314
        plan = sel_node_get_nth_plan(node, node->fetch_table);
 
1315
        index = plan->index;
 
1316
 
 
1317
        if (plan->n_rows_prefetched > 0) {
 
1318
                sel_pop_prefetched_row(plan);
 
1319
 
 
1320
                goto next_table_no_mtr;
 
1321
        }
 
1322
 
 
1323
        if (plan->cursor_at_end) {
 
1324
                /* The cursor has already reached the result set end: no more
 
1325
                rows to process for this table cursor, as also the prefetch
 
1326
                stack was empty */
 
1327
 
 
1328
                ut_ad(plan->pcur_is_open);
 
1329
 
 
1330
                goto table_exhausted_no_mtr;
 
1331
        }
 
1332
 
 
1333
        /* Open a cursor to index, or restore an open cursor position */
 
1334
 
 
1335
        mtr_start(&mtr);
 
1336
 
 
1337
        if (consistent_read && plan->unique_search && !plan->pcur_is_open
 
1338
            && !plan->must_get_clust
 
1339
            && !plan->table->big_rows) {
 
1340
                if (!search_latch_locked) {
 
1341
                        rw_lock_s_lock(&btr_search_latch);
 
1342
 
 
1343
                        search_latch_locked = TRUE;
 
1344
                } else if (btr_search_latch.writer_is_wait_ex) {
 
1345
 
 
1346
                        /* There is an x-latch request waiting: release the
 
1347
                        s-latch for a moment; as an s-latch here is often
 
1348
                        kept for some 10 searches before being released,
 
1349
                        a waiting x-latch request would block other threads
 
1350
                        from acquiring an s-latch for a long time, lowering
 
1351
                        performance significantly in multiprocessors. */
 
1352
 
 
1353
                        rw_lock_s_unlock(&btr_search_latch);
 
1354
                        rw_lock_s_lock(&btr_search_latch);
 
1355
                }
 
1356
 
 
1357
                found_flag = row_sel_try_search_shortcut(node, plan, &mtr);
 
1358
 
 
1359
                if (found_flag == SEL_FOUND) {
 
1360
 
 
1361
                        goto next_table;
 
1362
 
 
1363
                } else if (found_flag == SEL_EXHAUSTED) {
 
1364
 
 
1365
                        goto table_exhausted;
 
1366
                }
 
1367
 
 
1368
                ut_ad(found_flag == SEL_RETRY);
 
1369
 
 
1370
                plan_reset_cursor(plan);
 
1371
 
 
1372
                mtr_commit(&mtr);
 
1373
                mtr_start(&mtr);
 
1374
        }
 
1375
 
 
1376
        if (search_latch_locked) {
 
1377
                rw_lock_s_unlock(&btr_search_latch);
 
1378
 
 
1379
                search_latch_locked = FALSE;
 
1380
        }
 
1381
 
 
1382
        if (!plan->pcur_is_open) {
 
1383
                /* Evaluate the expressions to build the search tuple and
 
1384
                open the cursor */
 
1385
 
 
1386
                row_sel_open_pcur(node, plan, search_latch_locked, &mtr);
 
1387
 
 
1388
                cursor_just_opened = TRUE;
 
1389
 
 
1390
                /* A new search was made: increment the cost counter */
 
1391
                cost_counter++;
 
1392
        } else {
 
1393
                /* Restore pcur position to the index */
 
1394
 
 
1395
                must_go_to_next = row_sel_restore_pcur_pos(node, plan, &mtr);
 
1396
 
 
1397
                cursor_just_opened = FALSE;
 
1398
 
 
1399
                if (must_go_to_next) {
 
1400
                        /* We have already processed the cursor record: move
 
1401
                        to the next */
 
1402
 
 
1403
                        goto next_rec;
 
1404
                }
 
1405
        }
 
1406
 
 
1407
rec_loop:
 
1408
        /* RECORD LOOP
 
1409
        -----------
 
1410
        In this loop we use pcur and try to fetch a qualifying row, and
 
1411
        also fill the prefetch buffer for this table if n_rows_fetched has
 
1412
        exceeded a threshold. While we are inside this loop, the following
 
1413
        holds:
 
1414
        (1) &mtr is started,
 
1415
        (2) pcur is positioned and open.
 
1416
 
 
1417
        NOTE that if cursor_just_opened is TRUE here, it means that we came
 
1418
        to this point right after row_sel_open_pcur. */
 
1419
 
 
1420
        ut_ad(mtr_has_extra_clust_latch == FALSE);
 
1421
 
 
1422
        rec = btr_pcur_get_rec(&(plan->pcur));
 
1423
 
 
1424
        /* PHASE 1: Set a lock if specified */
 
1425
 
 
1426
        if (!node->asc && cursor_just_opened
 
1427
            && !page_rec_is_supremum(rec)) {
 
1428
 
 
1429
                /* When we open a cursor for a descending search, we must set
 
1430
                a next-key lock on the successor record: otherwise it would
 
1431
                be possible to insert new records next to the cursor position,
 
1432
                and it might be that these new records should appear in the
 
1433
                search result set, resulting in the phantom problem. */
 
1434
 
 
1435
                if (!consistent_read) {
 
1436
 
 
1437
                        /* If innodb_locks_unsafe_for_binlog option is used
 
1438
                        or this session is using READ COMMITTED isolation
 
1439
                        level, we lock only the record, i.e., next-key
 
1440
                        locking is not used. */
 
1441
 
 
1442
                        rec_t*  next_rec = page_rec_get_next(rec);
 
1443
                        ulint   lock_type;
 
1444
                        trx_t*  trx;
 
1445
 
 
1446
                        trx = thr_get_trx(thr);
 
1447
 
 
1448
                        offsets = rec_get_offsets(next_rec, index, offsets,
 
1449
                                                  ULINT_UNDEFINED, &heap);
 
1450
 
 
1451
                        if (srv_locks_unsafe_for_binlog
 
1452
                            || trx->isolation_level
 
1453
                            == TRX_ISO_READ_COMMITTED) {
 
1454
 
 
1455
                                if (page_rec_is_supremum(next_rec)) {
 
1456
 
 
1457
                                        goto skip_lock;
 
1458
                                }
 
1459
 
 
1460
                                lock_type = LOCK_REC_NOT_GAP;
 
1461
                        } else {
 
1462
                                lock_type = LOCK_ORDINARY;
 
1463
                        }
 
1464
 
 
1465
                        err = sel_set_rec_lock(btr_pcur_get_block(&plan->pcur),
 
1466
                                               next_rec, index, offsets,
 
1467
                                               node->row_lock_mode,
 
1468
                                               lock_type, thr);
 
1469
 
 
1470
                        if (err != DB_SUCCESS) {
 
1471
                                /* Note that in this case we will store in pcur
 
1472
                                the PREDECESSOR of the record we are waiting
 
1473
                                the lock for */
 
1474
 
 
1475
                                goto lock_wait_or_error;
 
1476
                        }
 
1477
                }
 
1478
        }
 
1479
 
 
1480
skip_lock:
 
1481
        if (page_rec_is_infimum(rec)) {
 
1482
 
 
1483
                /* The infimum record on a page cannot be in the result set,
 
1484
                and neither can a record lock be placed on it: we skip such
 
1485
                a record. We also increment the cost counter as we may have
 
1486
                processed yet another page of index. */
 
1487
 
 
1488
                cost_counter++;
 
1489
 
 
1490
                goto next_rec;
 
1491
        }
 
1492
 
 
1493
        if (!consistent_read) {
 
1494
                /* Try to place a lock on the index record */
 
1495
 
 
1496
                /* If innodb_locks_unsafe_for_binlog option is used
 
1497
                or this session is using READ COMMITTED isolation level,
 
1498
                we lock only the record, i.e., next-key locking is
 
1499
                not used. */
 
1500
 
 
1501
                ulint   lock_type;
 
1502
                trx_t*  trx;
 
1503
 
 
1504
                offsets = rec_get_offsets(rec, index, offsets,
 
1505
                                          ULINT_UNDEFINED, &heap);
 
1506
 
 
1507
                trx = thr_get_trx(thr);
 
1508
 
 
1509
                if (srv_locks_unsafe_for_binlog
 
1510
                    || trx->isolation_level == TRX_ISO_READ_COMMITTED) {
 
1511
 
 
1512
                        if (page_rec_is_supremum(rec)) {
 
1513
 
 
1514
                                goto next_rec;
 
1515
                        }
 
1516
 
 
1517
                        lock_type = LOCK_REC_NOT_GAP;
 
1518
                } else {
 
1519
                        lock_type = LOCK_ORDINARY;
 
1520
                }
 
1521
 
 
1522
                err = sel_set_rec_lock(btr_pcur_get_block(&plan->pcur),
 
1523
                                       rec, index, offsets,
 
1524
                                       node->row_lock_mode, lock_type, thr);
 
1525
 
 
1526
                if (err != DB_SUCCESS) {
 
1527
 
 
1528
                        goto lock_wait_or_error;
 
1529
                }
 
1530
        }
 
1531
 
 
1532
        if (page_rec_is_supremum(rec)) {
 
1533
 
 
1534
                /* A page supremum record cannot be in the result set: skip
 
1535
                it now when we have placed a possible lock on it */
 
1536
 
 
1537
                goto next_rec;
 
1538
        }
 
1539
 
 
1540
        ut_ad(page_rec_is_user_rec(rec));
 
1541
 
 
1542
        if (cost_counter > SEL_COST_LIMIT) {
 
1543
 
 
1544
                /* Now that we have placed the necessary locks, we can stop
 
1545
                for a while and store the cursor position; NOTE that if we
 
1546
                would store the cursor position BEFORE placing a record lock,
 
1547
                it might happen that the cursor would jump over some records
 
1548
                that another transaction could meanwhile insert adjacent to
 
1549
                the cursor: this would result in the phantom problem. */
 
1550
 
 
1551
                goto stop_for_a_while;
 
1552
        }
 
1553
 
 
1554
        /* PHASE 2: Check a mixed index mix id if needed */
 
1555
 
 
1556
        if (plan->unique_search && cursor_just_opened) {
 
1557
 
 
1558
                ut_ad(plan->mode == PAGE_CUR_GE);
 
1559
 
 
1560
                /* As the cursor is now placed on a user record after a search
 
1561
                with the mode PAGE_CUR_GE, the up_match field in the cursor
 
1562
                tells how many fields in the user record matched to the search
 
1563
                tuple */
 
1564
 
 
1565
                if (btr_pcur_get_up_match(&(plan->pcur))
 
1566
                    < plan->n_exact_match) {
 
1567
                        goto table_exhausted;
 
1568
                }
 
1569
 
 
1570
                /* Ok, no need to test end_conds or mix id */
 
1571
 
 
1572
        }
 
1573
 
 
1574
        /* We are ready to look at a possible new index entry in the result
 
1575
        set: the cursor is now placed on a user record */
 
1576
 
 
1577
        /* PHASE 3: Get previous version in a consistent read */
 
1578
 
 
1579
        cons_read_requires_clust_rec = FALSE;
 
1580
        offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
 
1581
 
 
1582
        if (consistent_read) {
 
1583
                /* This is a non-locking consistent read: if necessary, fetch
 
1584
                a previous version of the record */
 
1585
 
 
1586
                if (dict_index_is_clust(index)) {
 
1587
 
 
1588
                        if (!lock_clust_rec_cons_read_sees(rec, index, offsets,
 
1589
                                                           node->read_view)) {
 
1590
 
 
1591
                                err = row_sel_build_prev_vers(
 
1592
                                        node->read_view, index, rec,
 
1593
                                        &offsets, &heap, &plan->old_vers_heap,
 
1594
                                        &old_vers, &mtr);
 
1595
 
 
1596
                                if (err != DB_SUCCESS) {
 
1597
 
 
1598
                                        goto lock_wait_or_error;
 
1599
                                }
 
1600
 
 
1601
                                if (old_vers == NULL) {
 
1602
                                        offsets = rec_get_offsets(
 
1603
                                                rec, index, offsets,
 
1604
                                                ULINT_UNDEFINED, &heap);
 
1605
 
 
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). */
 
1614
 
 
1615
                                        row_sel_fetch_columns(
 
1616
                                                index, rec, offsets,
 
1617
                                                UT_LIST_GET_FIRST(
 
1618
                                                        plan->columns));
 
1619
 
 
1620
                                        if (!row_sel_test_end_conds(plan)) {
 
1621
 
 
1622
                                                goto table_exhausted;
 
1623
                                        }
 
1624
 
 
1625
                                        goto next_rec;
 
1626
                                }
 
1627
 
 
1628
                                rec = old_vers;
 
1629
                        }
 
1630
                } else if (!lock_sec_rec_cons_read_sees(rec,
 
1631
                                                        node->read_view)) {
 
1632
                        cons_read_requires_clust_rec = TRUE;
 
1633
                }
 
1634
        }
 
1635
 
 
1636
        /* PHASE 4: Test search end conditions and deleted flag */
 
1637
 
 
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). */
 
1642
 
 
1643
        row_sel_fetch_columns(index, rec, offsets,
 
1644
                              UT_LIST_GET_FIRST(plan->columns));
 
1645
 
 
1646
        /* Test the selection end conditions: these can only contain columns
 
1647
        which already are found in the index, even though the index might be
 
1648
        non-clustered */
 
1649
 
 
1650
        if (plan->unique_search && cursor_just_opened) {
 
1651
 
 
1652
                /* No test necessary: the test was already made above */
 
1653
 
 
1654
        } else if (!row_sel_test_end_conds(plan)) {
 
1655
 
 
1656
                goto table_exhausted;
 
1657
        }
 
1658
 
 
1659
        if (rec_get_deleted_flag(rec, dict_table_is_comp(plan->table))
 
1660
            && !cons_read_requires_clust_rec) {
 
1661
 
 
1662
                /* The record is delete marked: we can skip it if this is
 
1663
                not a consistent read which might see an earlier version
 
1664
                of a non-clustered index record */
 
1665
 
 
1666
                if (plan->unique_search) {
 
1667
 
 
1668
                        goto table_exhausted;
 
1669
                }
 
1670
 
 
1671
                goto next_rec;
 
1672
        }
 
1673
 
 
1674
        /* PHASE 5: Get the clustered index record, if needed and if we did
 
1675
        not do the search using the clustered index */
 
1676
 
 
1677
        if (plan->must_get_clust || cons_read_requires_clust_rec) {
 
1678
 
 
1679
                /* It was a non-clustered index and we must fetch also the
 
1680
                clustered index record */
 
1681
 
 
1682
                err = row_sel_get_clust_rec(node, plan, rec, thr, &clust_rec,
 
1683
                                            &mtr);
 
1684
                mtr_has_extra_clust_latch = TRUE;
 
1685
 
 
1686
                if (err != DB_SUCCESS) {
 
1687
 
 
1688
                        goto lock_wait_or_error;
 
1689
                }
 
1690
 
 
1691
                /* Retrieving the clustered record required a search:
 
1692
                increment the cost counter */
 
1693
 
 
1694
                cost_counter++;
 
1695
 
 
1696
                if (clust_rec == NULL) {
 
1697
                        /* The record did not exist in the read view */
 
1698
                        ut_ad(consistent_read);
 
1699
 
 
1700
                        goto next_rec;
 
1701
                }
 
1702
 
 
1703
                if (rec_get_deleted_flag(clust_rec,
 
1704
                                         dict_table_is_comp(plan->table))) {
 
1705
 
 
1706
                        /* The record is delete marked: we can skip it */
 
1707
 
 
1708
                        goto next_rec;
 
1709
                }
 
1710
 
 
1711
                if (node->can_get_updated) {
 
1712
 
 
1713
                        btr_pcur_store_position(&(plan->clust_pcur), &mtr);
 
1714
                }
 
1715
        }
 
1716
 
 
1717
        /* PHASE 6: Test the rest of search conditions */
 
1718
 
 
1719
        if (!row_sel_test_other_conds(plan)) {
 
1720
 
 
1721
                if (plan->unique_search) {
 
1722
 
 
1723
                        goto table_exhausted;
 
1724
                }
 
1725
 
 
1726
                goto next_rec;
 
1727
        }
 
1728
 
 
1729
        /* PHASE 7: We found a new qualifying row for the current table; push
 
1730
        the row if prefetch is on, or move to the next table in the join */
 
1731
 
 
1732
        plan->n_rows_fetched++;
 
1733
 
 
1734
        ut_ad(plan->pcur.latch_mode == node->latch_mode);
 
1735
 
 
1736
        if (node->select_will_do_update) {
 
1737
                /* This is a searched update and we can do the update in-place,
 
1738
                saving CPU time */
 
1739
 
 
1740
                row_upd_in_place_in_select(node, thr, &mtr);
 
1741
 
 
1742
                leaf_contains_updates = TRUE;
 
1743
 
 
1744
                /* When the database is in the online backup mode, the number
 
1745
                of log records for a single mtr should be small: increment the
 
1746
                cost counter to ensure it */
 
1747
 
 
1748
                cost_counter += 1 + (SEL_COST_LIMIT / 8);
 
1749
 
 
1750
                if (plan->unique_search) {
 
1751
 
 
1752
                        goto table_exhausted;
 
1753
                }
 
1754
 
 
1755
                goto next_rec;
 
1756
        }
 
1757
 
 
1758
        if ((plan->n_rows_fetched <= SEL_PREFETCH_LIMIT)
 
1759
            || plan->unique_search || plan->no_prefetch
 
1760
            || plan->table->big_rows) {
 
1761
 
 
1762
                /* No prefetch in operation: go to the next table */
 
1763
 
 
1764
                goto next_table;
 
1765
        }
 
1766
 
 
1767
        sel_push_prefetched_row(plan);
 
1768
 
 
1769
        if (plan->n_rows_prefetched == SEL_MAX_N_PREFETCH) {
 
1770
 
 
1771
                /* The prefetch buffer is now full */
 
1772
 
 
1773
                sel_pop_prefetched_row(plan);
 
1774
 
 
1775
                goto next_table;
 
1776
        }
 
1777
 
 
1778
next_rec:
 
1779
        ut_ad(!search_latch_locked);
 
1780
 
 
1781
        if (mtr_has_extra_clust_latch) {
 
1782
 
 
1783
                /* We must commit &mtr if we are moving to the next
 
1784
                non-clustered index record, because we could break the
 
1785
                latching order if we would access a different clustered
 
1786
                index page right away without releasing the previous. */
 
1787
 
 
1788
                goto commit_mtr_for_a_while;
 
1789
        }
 
1790
 
 
1791
        if (leaf_contains_updates
 
1792
            && btr_pcur_is_after_last_on_page(&plan->pcur)) {
 
1793
 
 
1794
                /* We must commit &mtr if we are moving to a different page,
 
1795
                because we have done updates to the x-latched leaf page, and
 
1796
                the latch would be released in btr_pcur_move_to_next, without
 
1797
                &mtr getting committed there */
 
1798
 
 
1799
                ut_ad(node->asc);
 
1800
 
 
1801
                goto commit_mtr_for_a_while;
 
1802
        }
 
1803
 
 
1804
        if (node->asc) {
 
1805
                moved = btr_pcur_move_to_next(&(plan->pcur), &mtr);
 
1806
        } else {
 
1807
                moved = btr_pcur_move_to_prev(&(plan->pcur), &mtr);
 
1808
        }
 
1809
 
 
1810
        if (!moved) {
 
1811
 
 
1812
                goto table_exhausted;
 
1813
        }
 
1814
 
 
1815
        cursor_just_opened = FALSE;
 
1816
 
 
1817
        /* END OF RECORD LOOP
 
1818
        ------------------ */
 
1819
        goto rec_loop;
 
1820
 
 
1821
next_table:
 
1822
        /* We found a record which satisfies the conditions: we can move to
 
1823
        the next table or return a row in the result set */
 
1824
 
 
1825
        ut_ad(btr_pcur_is_on_user_rec(&plan->pcur));
 
1826
 
 
1827
        if (plan->unique_search && !node->can_get_updated) {
 
1828
 
 
1829
                plan->cursor_at_end = TRUE;
 
1830
        } else {
 
1831
                ut_ad(!search_latch_locked);
 
1832
 
 
1833
                plan->stored_cursor_rec_processed = TRUE;
 
1834
 
 
1835
                btr_pcur_store_position(&(plan->pcur), &mtr);
 
1836
        }
 
1837
 
 
1838
        mtr_commit(&mtr);
 
1839
 
 
1840
        leaf_contains_updates = FALSE;
 
1841
        mtr_has_extra_clust_latch = FALSE;
 
1842
 
 
1843
next_table_no_mtr:
 
1844
        /* If we use 'goto' to this label, it means that the row was popped
 
1845
        from the prefetched rows stack, and &mtr is already committed */
 
1846
 
 
1847
        if (node->fetch_table + 1 == node->n_tables) {
 
1848
 
 
1849
                sel_eval_select_list(node);
 
1850
 
 
1851
                if (node->is_aggregate) {
 
1852
 
 
1853
                        goto table_loop;
 
1854
                }
 
1855
 
 
1856
                sel_assign_into_var_values(node->into_list, node);
 
1857
 
 
1858
                thr->run_node = que_node_get_parent(node);
 
1859
 
 
1860
                err = DB_SUCCESS;
 
1861
                goto func_exit;
 
1862
        }
 
1863
 
 
1864
        node->fetch_table++;
 
1865
 
 
1866
        /* When we move to the next table, we first reset the plan cursor:
 
1867
        we do not care about resetting it when we backtrack from a table */
 
1868
 
 
1869
        plan_reset_cursor(sel_node_get_nth_plan(node, node->fetch_table));
 
1870
 
 
1871
        goto table_loop;
 
1872
 
 
1873
table_exhausted:
 
1874
        /* The table cursor pcur reached the result set end: backtrack to the
 
1875
        previous table in the join if we do not have cached prefetched rows */
 
1876
 
 
1877
        plan->cursor_at_end = TRUE;
 
1878
 
 
1879
        mtr_commit(&mtr);
 
1880
 
 
1881
        leaf_contains_updates = FALSE;
 
1882
        mtr_has_extra_clust_latch = FALSE;
 
1883
 
 
1884
        if (plan->n_rows_prefetched > 0) {
 
1885
                /* The table became exhausted during a prefetch */
 
1886
 
 
1887
                sel_pop_prefetched_row(plan);
 
1888
 
 
1889
                goto next_table_no_mtr;
 
1890
        }
 
1891
 
 
1892
table_exhausted_no_mtr:
 
1893
        if (node->fetch_table == 0) {
 
1894
                err = DB_SUCCESS;
 
1895
 
 
1896
                if (node->is_aggregate && !node->aggregate_already_fetched) {
 
1897
 
 
1898
                        node->aggregate_already_fetched = TRUE;
 
1899
 
 
1900
                        sel_assign_into_var_values(node->into_list, node);
 
1901
 
 
1902
                        thr->run_node = que_node_get_parent(node);
 
1903
                } else {
 
1904
                        node->state = SEL_NODE_NO_MORE_ROWS;
 
1905
 
 
1906
                        thr->run_node = que_node_get_parent(node);
 
1907
                }
 
1908
 
 
1909
                goto func_exit;
 
1910
        }
 
1911
 
 
1912
        node->fetch_table--;
 
1913
 
 
1914
        goto table_loop;
 
1915
 
 
1916
stop_for_a_while:
 
1917
        /* Return control for a while to que_run_threads, so that runaway
 
1918
        queries can be canceled. NOTE that when we come here, we must, in a
 
1919
        locking read, have placed the necessary (possibly waiting request)
 
1920
        record lock on the cursor record or its successor: when we reposition
 
1921
        the cursor, this record lock guarantees that nobody can meanwhile have
 
1922
        inserted new records which should have appeared in the result set,
 
1923
        which would result in the phantom problem. */
 
1924
 
 
1925
        ut_ad(!search_latch_locked);
 
1926
 
 
1927
        plan->stored_cursor_rec_processed = FALSE;
 
1928
        btr_pcur_store_position(&(plan->pcur), &mtr);
 
1929
 
 
1930
        mtr_commit(&mtr);
 
1931
 
 
1932
#ifdef UNIV_SYNC_DEBUG
 
1933
        ut_ad(sync_thread_levels_empty_gen(TRUE));
 
1934
#endif /* UNIV_SYNC_DEBUG */
 
1935
        err = DB_SUCCESS;
 
1936
        goto func_exit;
 
1937
 
 
1938
commit_mtr_for_a_while:
 
1939
        /* Stores the cursor position and commits &mtr; this is used if
 
1940
        &mtr may contain latches which would break the latching order if
 
1941
        &mtr would not be committed and the latches released. */
 
1942
 
 
1943
        plan->stored_cursor_rec_processed = TRUE;
 
1944
 
 
1945
        ut_ad(!search_latch_locked);
 
1946
        btr_pcur_store_position(&(plan->pcur), &mtr);
 
1947
 
 
1948
        mtr_commit(&mtr);
 
1949
 
 
1950
        leaf_contains_updates = FALSE;
 
1951
        mtr_has_extra_clust_latch = FALSE;
 
1952
 
 
1953
#ifdef UNIV_SYNC_DEBUG
 
1954
        ut_ad(sync_thread_levels_empty_gen(TRUE));
 
1955
#endif /* UNIV_SYNC_DEBUG */
 
1956
 
 
1957
        goto table_loop;
 
1958
 
 
1959
lock_wait_or_error:
 
1960
        /* See the note at stop_for_a_while: the same holds for this case */
 
1961
 
 
1962
        ut_ad(!btr_pcur_is_before_first_on_page(&plan->pcur) || !node->asc);
 
1963
        ut_ad(!search_latch_locked);
 
1964
 
 
1965
        plan->stored_cursor_rec_processed = FALSE;
 
1966
        btr_pcur_store_position(&(plan->pcur), &mtr);
 
1967
 
 
1968
        mtr_commit(&mtr);
 
1969
 
 
1970
#ifdef UNIV_SYNC_DEBUG
 
1971
        ut_ad(sync_thread_levels_empty_gen(TRUE));
 
1972
#endif /* UNIV_SYNC_DEBUG */
 
1973
 
 
1974
func_exit:
 
1975
        if (search_latch_locked) {
 
1976
                rw_lock_s_unlock(&btr_search_latch);
 
1977
        }
 
1978
        if (UNIV_LIKELY_NULL(heap)) {
 
1979
                mem_heap_free(heap);
 
1980
        }
 
1981
        return(err);
 
1982
}
 
1983
 
 
1984
/**************************************************************************
 
1985
Performs a select step. This is a high-level function used in SQL execution
 
1986
graphs. */
 
1987
UNIV_INTERN
 
1988
que_thr_t*
 
1989
row_sel_step(
 
1990
/*=========*/
 
1991
                                /* out: query thread to run next or NULL */
 
1992
        que_thr_t*      thr)    /* in: query thread */
 
1993
{
 
1994
        ulint           i_lock_mode;
 
1995
        sym_node_t*     table_node;
 
1996
        sel_node_t*     node;
 
1997
        ulint           err;
 
1998
 
 
1999
        ut_ad(thr);
 
2000
 
 
2001
        node = thr->run_node;
 
2002
 
 
2003
        ut_ad(que_node_get_type(node) == QUE_NODE_SELECT);
 
2004
 
 
2005
        /* If this is a new time this node is executed (or when execution
 
2006
        resumes after wait for a table intention lock), set intention locks
 
2007
        on the tables, or assign a read view */
 
2008
 
 
2009
        if (node->into_list && (thr->prev_node == que_node_get_parent(node))) {
 
2010
 
 
2011
                node->state = SEL_NODE_OPEN;
 
2012
        }
 
2013
 
 
2014
        if (node->state == SEL_NODE_OPEN) {
 
2015
 
 
2016
                /* It may be that the current session has not yet started
 
2017
                its transaction, or it has been committed: */
 
2018
 
 
2019
                trx_start_if_not_started(thr_get_trx(thr));
 
2020
 
 
2021
                plan_reset_cursor(sel_node_get_nth_plan(node, 0));
 
2022
 
 
2023
                if (node->consistent_read) {
 
2024
                        /* Assign a read view for the query */
 
2025
                        node->read_view = trx_assign_read_view(
 
2026
                                thr_get_trx(thr));
 
2027
                } else {
 
2028
                        if (node->set_x_locks) {
 
2029
                                i_lock_mode = LOCK_IX;
 
2030
                        } else {
 
2031
                                i_lock_mode = LOCK_IS;
 
2032
                        }
 
2033
 
 
2034
                        table_node = node->table_list;
 
2035
 
 
2036
                        while (table_node) {
 
2037
                                err = lock_table(0, table_node->table,
 
2038
                                                 i_lock_mode, thr);
 
2039
                                if (err != DB_SUCCESS) {
 
2040
                                        thr_get_trx(thr)->error_state = err;
 
2041
 
 
2042
                                        return(NULL);
 
2043
                                }
 
2044
 
 
2045
                                table_node = que_node_get_next(table_node);
 
2046
                        }
 
2047
                }
 
2048
 
 
2049
                /* If this is an explicit cursor, copy stored procedure
 
2050
                variable values, so that the values cannot change between
 
2051
                fetches (currently, we copy them also for non-explicit
 
2052
                cursors) */
 
2053
 
 
2054
                if (node->explicit_cursor
 
2055
                    && UT_LIST_GET_FIRST(node->copy_variables)) {
 
2056
 
 
2057
                        row_sel_copy_input_variable_vals(node);
 
2058
                }
 
2059
 
 
2060
                node->state = SEL_NODE_FETCH;
 
2061
                node->fetch_table = 0;
 
2062
 
 
2063
                if (node->is_aggregate) {
 
2064
                        /* Reset the aggregate total values */
 
2065
                        sel_reset_aggregate_vals(node);
 
2066
                }
 
2067
        }
 
2068
 
 
2069
        err = row_sel(node, thr);
 
2070
 
 
2071
        /* NOTE! if queries are parallelized, the following assignment may
 
2072
        have problems; the assignment should be made only if thr is the
 
2073
        only top-level thr in the graph: */
 
2074
 
 
2075
        thr->graph->last_sel_node = node;
 
2076
 
 
2077
        if (err != DB_SUCCESS) {
 
2078
                thr_get_trx(thr)->error_state = err;
 
2079
 
 
2080
                return(NULL);
 
2081
        }
 
2082
 
 
2083
        return(thr);
 
2084
}
 
2085
 
 
2086
/**************************************************************************
 
2087
Performs a fetch for a cursor. */
 
2088
UNIV_INTERN
 
2089
que_thr_t*
 
2090
fetch_step(
 
2091
/*=======*/
 
2092
                                /* out: query thread to run next or NULL */
 
2093
        que_thr_t*      thr)    /* in: query thread */
 
2094
{
 
2095
        sel_node_t*     sel_node;
 
2096
        fetch_node_t*   node;
 
2097
 
 
2098
        ut_ad(thr);
 
2099
 
 
2100
        node = thr->run_node;
 
2101
        sel_node = node->cursor_def;
 
2102
 
 
2103
        ut_ad(que_node_get_type(node) == QUE_NODE_FETCH);
 
2104
 
 
2105
        if (thr->prev_node != que_node_get_parent(node)) {
 
2106
 
 
2107
                if (sel_node->state != SEL_NODE_NO_MORE_ROWS) {
 
2108
 
 
2109
                        if (node->into_list) {
 
2110
                                sel_assign_into_var_values(node->into_list,
 
2111
                                                           sel_node);
 
2112
                        } else {
 
2113
                                void* ret = (*node->func->func)(
 
2114
                                        sel_node, node->func->arg);
 
2115
 
 
2116
                                if (!ret) {
 
2117
                                        sel_node->state
 
2118
                                                = SEL_NODE_NO_MORE_ROWS;
 
2119
                                }
 
2120
                        }
 
2121
                }
 
2122
 
 
2123
                thr->run_node = que_node_get_parent(node);
 
2124
 
 
2125
                return(thr);
 
2126
        }
 
2127
 
 
2128
        /* Make the fetch node the parent of the cursor definition for
 
2129
        the time of the fetch, so that execution knows to return to this
 
2130
        fetch node after a row has been selected or we know that there is
 
2131
        no row left */
 
2132
 
 
2133
        sel_node->common.parent = node;
 
2134
 
 
2135
        if (sel_node->state == SEL_NODE_CLOSED) {
 
2136
                fprintf(stderr,
 
2137
                        "InnoDB: Error: fetch called on a closed cursor\n");
 
2138
 
 
2139
                thr_get_trx(thr)->error_state = DB_ERROR;
 
2140
 
 
2141
                return(NULL);
 
2142
        }
 
2143
 
 
2144
        thr->run_node = sel_node;
 
2145
 
 
2146
        return(thr);
 
2147
}
 
2148
 
 
2149
/********************************************************************
 
2150
Sample callback function for fetch that prints each row.*/
 
2151
UNIV_INTERN
 
2152
void*
 
2153
row_fetch_print(
 
2154
/*============*/
 
2155
                                /* out: always returns non-NULL */
 
2156
        void*   row,            /* in:  sel_node_t* */
 
2157
        void*   user_arg)       /* in:  not used */
 
2158
{
 
2159
        sel_node_t*     node = row;
 
2160
        que_node_t*     exp;
 
2161
        ulint           i = 0;
 
2162
 
 
2163
        UT_NOT_USED(user_arg);
 
2164
 
 
2165
        fprintf(stderr, "row_fetch_print: row %p\n", row);
 
2166
 
 
2167
        exp = node->select_list;
 
2168
 
 
2169
        while (exp) {
 
2170
                dfield_t*       dfield = que_node_get_val(exp);
 
2171
                const dtype_t*  type = dfield_get_type(dfield);
 
2172
 
 
2173
                fprintf(stderr, " column %lu:\n", (ulong)i);
 
2174
 
 
2175
                dtype_print(type);
 
2176
                fprintf(stderr, "\n");
 
2177
 
 
2178
                if (dfield_get_len(dfield) != UNIV_SQL_NULL) {
 
2179
                        ut_print_buf(stderr, dfield_get_data(dfield),
 
2180
                                     dfield_get_len(dfield));
 
2181
                } else {
 
2182
                        fprintf(stderr, " <NULL>;");
 
2183
                }
 
2184
 
 
2185
                fprintf(stderr, "\n");
 
2186
 
 
2187
                exp = que_node_get_next(exp);
 
2188
                i++;
 
2189
        }
 
2190
 
 
2191
        return((void*)42);
 
2192
}
 
2193
 
 
2194
/********************************************************************
 
2195
Callback function for fetch that stores an unsigned 4 byte integer to the
 
2196
location pointed. The column's type must be DATA_INT, DATA_UNSIGNED, length
 
2197
= 4. */
 
2198
UNIV_INTERN
 
2199
void*
 
2200
row_fetch_store_uint4(
 
2201
/*==================*/
 
2202
                                /* out: always returns NULL */
 
2203
        void*   row,            /* in:  sel_node_t* */
 
2204
        void*   user_arg)       /* in:  data pointer */
 
2205
{
 
2206
        sel_node_t*     node = row;
 
2207
        ib_uint32_t*    val = user_arg;
 
2208
        ulint           tmp;
 
2209
 
 
2210
        dfield_t*       dfield = que_node_get_val(node->select_list);
 
2211
        const dtype_t*  type = dfield_get_type(dfield);
 
2212
        ulint           len = dfield_get_len(dfield);
 
2213
 
 
2214
        ut_a(dtype_get_mtype(type) == DATA_INT);
 
2215
        ut_a(dtype_get_prtype(type) & DATA_UNSIGNED);
 
2216
        ut_a(len == 4);
 
2217
 
 
2218
        tmp = mach_read_from_4(dfield_get_data(dfield));
 
2219
        *val = (ib_uint32_t) tmp;
 
2220
 
 
2221
        return(NULL);
 
2222
}
 
2223
 
 
2224
/***************************************************************
 
2225
Prints a row in a select result. */
 
2226
UNIV_INTERN
 
2227
que_thr_t*
 
2228
row_printf_step(
 
2229
/*============*/
 
2230
                                /* out: query thread to run next or NULL */
 
2231
        que_thr_t*      thr)    /* in: query thread */
 
2232
{
 
2233
        row_printf_node_t*      node;
 
2234
        sel_node_t*             sel_node;
 
2235
        que_node_t*             arg;
 
2236
 
 
2237
        ut_ad(thr);
 
2238
 
 
2239
        node = thr->run_node;
 
2240
 
 
2241
        sel_node = node->sel_node;
 
2242
 
 
2243
        ut_ad(que_node_get_type(node) == QUE_NODE_ROW_PRINTF);
 
2244
 
 
2245
        if (thr->prev_node == que_node_get_parent(node)) {
 
2246
 
 
2247
                /* Reset the cursor */
 
2248
                sel_node->state = SEL_NODE_OPEN;
 
2249
 
 
2250
                /* Fetch next row to print */
 
2251
 
 
2252
                thr->run_node = sel_node;
 
2253
 
 
2254
                return(thr);
 
2255
        }
 
2256
 
 
2257
        if (sel_node->state != SEL_NODE_FETCH) {
 
2258
 
 
2259
                ut_ad(sel_node->state == SEL_NODE_NO_MORE_ROWS);
 
2260
 
 
2261
                /* No more rows to print */
 
2262
 
 
2263
                thr->run_node = que_node_get_parent(node);
 
2264
 
 
2265
                return(thr);
 
2266
        }
 
2267
 
 
2268
        arg = sel_node->select_list;
 
2269
 
 
2270
        while (arg) {
 
2271
                dfield_print_also_hex(que_node_get_val(arg));
 
2272
 
 
2273
                fputs(" ::: ", stderr);
 
2274
 
 
2275
                arg = que_node_get_next(arg);
 
2276
        }
 
2277
 
 
2278
        putc('\n', stderr);
 
2279
 
 
2280
        /* Fetch next row to print */
 
2281
 
 
2282
        thr->run_node = sel_node;
 
2283
 
 
2284
        return(thr);
 
2285
}
 
2286
 
 
2287
/********************************************************************
 
2288
Converts a key value stored in MySQL format to an Innobase dtuple. The last
 
2289
field of the key value may be just a prefix of a fixed length field: hence
 
2290
the parameter key_len. But currently we do not allow search keys where the
 
2291
last field is only a prefix of the full key field len and print a warning if
 
2292
such appears. A counterpart of this function is
 
2293
ha_innobase::store_key_val_for_row() in ha_innodb.cc. */
 
2294
UNIV_INTERN
 
2295
void
 
2296
row_sel_convert_mysql_key_to_innobase(
 
2297
/*==================================*/
 
2298
        dtuple_t*       tuple,          /* in/out: tuple where to build;
 
2299
                                        NOTE: we assume that the type info
 
2300
                                        in the tuple is already according
 
2301
                                        to index! */
 
2302
        byte*           buf,            /* in: buffer to use in field
 
2303
                                        conversions */
 
2304
        ulint           buf_len,        /* in: buffer length */
 
2305
        dict_index_t*   index,          /* in: index of the key value */
 
2306
        const byte*     key_ptr,        /* in: MySQL key value */
 
2307
        ulint           key_len,        /* in: MySQL key value length */
 
2308
        trx_t*          trx)            /* in: transaction */
 
2309
{
 
2310
        byte*           original_buf    = buf;
 
2311
        const byte*     original_key_ptr = key_ptr;
 
2312
        dict_field_t*   field;
 
2313
        dfield_t*       dfield;
 
2314
        ulint           data_offset;
 
2315
        ulint           data_len;
 
2316
        ulint           data_field_len;
 
2317
        ibool           is_null;
 
2318
        const byte*     key_end;
 
2319
        ulint           n_fields = 0;
 
2320
 
 
2321
        /* For documentation of the key value storage format in MySQL, see
 
2322
        ha_innobase::store_key_val_for_row() in ha_innodb.cc. */
 
2323
 
 
2324
        key_end = key_ptr + key_len;
 
2325
 
 
2326
        /* Permit us to access any field in the tuple (ULINT_MAX): */
 
2327
 
 
2328
        dtuple_set_n_fields(tuple, ULINT_MAX);
 
2329
 
 
2330
        dfield = dtuple_get_nth_field(tuple, 0);
 
2331
        field = dict_index_get_nth_field(index, 0);
 
2332
 
 
2333
        if (UNIV_UNLIKELY(dfield_get_type(dfield)->mtype == DATA_SYS)) {
 
2334
                /* A special case: we are looking for a position in the
 
2335
                generated clustered index which InnoDB automatically added
 
2336
                to a table with no primary key: the first and the only
 
2337
                ordering column is ROW_ID which InnoDB stored to the key_ptr
 
2338
                buffer. */
 
2339
 
 
2340
                ut_a(key_len == DATA_ROW_ID_LEN);
 
2341
 
 
2342
                dfield_set_data(dfield, key_ptr, DATA_ROW_ID_LEN);
 
2343
 
 
2344
                dtuple_set_n_fields(tuple, 1);
 
2345
 
 
2346
                return;
 
2347
        }
 
2348
 
 
2349
        while (key_ptr < key_end) {
 
2350
 
 
2351
                ulint   type = dfield_get_type(dfield)->mtype;
 
2352
                ut_a(field->col->mtype == type);
 
2353
 
 
2354
                data_offset = 0;
 
2355
                is_null = FALSE;
 
2356
 
 
2357
                if (!(dfield_get_type(dfield)->prtype & DATA_NOT_NULL)) {
 
2358
                        /* The first byte in the field tells if this is
 
2359
                        an SQL NULL value */
 
2360
 
 
2361
                        data_offset = 1;
 
2362
 
 
2363
                        if (*key_ptr != 0) {
 
2364
                                dfield_set_null(dfield);
 
2365
 
 
2366
                                is_null = TRUE;
 
2367
                        }
 
2368
                }
 
2369
 
 
2370
                /* Calculate data length and data field total length */
 
2371
 
 
2372
                if (type == DATA_BLOB) {
 
2373
                        /* The key field is a column prefix of a BLOB or
 
2374
                        TEXT */
 
2375
 
 
2376
                        ut_a(field->prefix_len > 0);
 
2377
 
 
2378
                        /* MySQL stores the actual data length to the first 2
 
2379
                        bytes after the optional SQL NULL marker byte. The
 
2380
                        storage format is little-endian, that is, the most
 
2381
                        significant byte at a higher address. In UTF-8, MySQL
 
2382
                        seems to reserve field->prefix_len bytes for
 
2383
                        storing this field in the key value buffer, even
 
2384
                        though the actual value only takes data_len bytes
 
2385
                        from the start. */
 
2386
 
 
2387
                        data_len = key_ptr[data_offset]
 
2388
                                + 256 * key_ptr[data_offset + 1];
 
2389
                        data_field_len = data_offset + 2 + field->prefix_len;
 
2390
 
 
2391
                        data_offset += 2;
 
2392
 
 
2393
                        /* Now that we know the length, we store the column
 
2394
                        value like it would be a fixed char field */
 
2395
 
 
2396
                } else if (field->prefix_len > 0) {
 
2397
                        /* Looks like MySQL pads unused end bytes in the
 
2398
                        prefix with space. Therefore, also in UTF-8, it is ok
 
2399
                        to compare with a prefix containing full prefix_len
 
2400
                        bytes, and no need to take at most prefix_len / 3
 
2401
                        UTF-8 characters from the start.
 
2402
                        If the prefix is used as the upper end of a LIKE
 
2403
                        'abc%' query, then MySQL pads the end with chars
 
2404
                        0xff. TODO: in that case does it any harm to compare
 
2405
                        with the full prefix_len bytes. How do characters
 
2406
                        0xff in UTF-8 behave? */
 
2407
 
 
2408
                        data_len = field->prefix_len;
 
2409
                        data_field_len = data_offset + data_len;
 
2410
                } else {
 
2411
                        data_len = dfield_get_type(dfield)->len;
 
2412
                        data_field_len = data_offset + data_len;
 
2413
                }
 
2414
 
 
2415
                if (UNIV_UNLIKELY
 
2416
                    (dtype_get_mysql_type(dfield_get_type(dfield))
 
2417
                     == DATA_MYSQL_TRUE_VARCHAR)
 
2418
                    && UNIV_LIKELY(type != DATA_INT)) {
 
2419
                        /* In a MySQL key value format, a true VARCHAR is
 
2420
                        always preceded by 2 bytes of a length field.
 
2421
                        dfield_get_type(dfield)->len returns the maximum
 
2422
                        'payload' len in bytes. That does not include the
 
2423
                        2 bytes that tell the actual data length.
 
2424
 
 
2425
                        We added the check != DATA_INT to make sure we do
 
2426
                        not treat MySQL ENUM or SET as a true VARCHAR! */
 
2427
 
 
2428
                        data_len += 2;
 
2429
                        data_field_len += 2;
 
2430
                }
 
2431
 
 
2432
                /* Storing may use at most data_len bytes of buf */
 
2433
 
 
2434
                if (UNIV_LIKELY(!is_null)) {
 
2435
                        row_mysql_store_col_in_innobase_format(
 
2436
                                dfield, buf,
 
2437
                                FALSE, /* MySQL key value format col */
 
2438
                                key_ptr + data_offset, data_len,
 
2439
                                dict_table_is_comp(index->table));
 
2440
                        buf += data_len;
 
2441
                }
 
2442
 
 
2443
                key_ptr += data_field_len;
 
2444
 
 
2445
                if (UNIV_UNLIKELY(key_ptr > key_end)) {
 
2446
                        /* The last field in key was not a complete key field
 
2447
                        but a prefix of it.
 
2448
 
 
2449
                        Print a warning about this! HA_READ_PREFIX_LAST does
 
2450
                        not currently work in InnoDB with partial-field key
 
2451
                        value prefixes. Since MySQL currently uses a padding
 
2452
                        trick to calculate LIKE 'abc%' type queries there
 
2453
                        should never be partial-field prefixes in searches. */
 
2454
 
 
2455
                        ut_print_timestamp(stderr);
 
2456
 
 
2457
                        fputs("  InnoDB: Warning: using a partial-field"
 
2458
                              " key prefix in search.\n"
 
2459
                              "InnoDB: ", stderr);
 
2460
                        dict_index_name_print(stderr, trx, index);
 
2461
                        fprintf(stderr, ". Last data field length %lu bytes,\n"
 
2462
                                "InnoDB: key ptr now exceeds"
 
2463
                                " key end by %lu bytes.\n"
 
2464
                                "InnoDB: Key value in the MySQL format:\n",
 
2465
                                (ulong) data_field_len,
 
2466
                                (ulong) (key_ptr - key_end));
 
2467
                        fflush(stderr);
 
2468
                        ut_print_buf(stderr, original_key_ptr, key_len);
 
2469
                        fprintf(stderr, "\n");
 
2470
 
 
2471
                        if (!is_null) {
 
2472
                                ulint   len = dfield_get_len(dfield);
 
2473
                                dfield_set_len(dfield, len
 
2474
                                               - (ulint) (key_ptr - key_end));
 
2475
                        }
 
2476
                }
 
2477
 
 
2478
                n_fields++;
 
2479
                field++;
 
2480
                dfield++;
 
2481
        }
 
2482
 
 
2483
        ut_a(buf <= original_buf + buf_len);
 
2484
 
 
2485
        /* We set the length of tuple to n_fields: we assume that the memory
 
2486
        area allocated for it is big enough (usually bigger than n_fields). */
 
2487
 
 
2488
        dtuple_set_n_fields(tuple, n_fields);
 
2489
}
 
2490
 
 
2491
/******************************************************************
 
2492
Stores the row id to the prebuilt struct. */
 
2493
static
 
2494
void
 
2495
row_sel_store_row_id_to_prebuilt(
 
2496
/*=============================*/
 
2497
        row_prebuilt_t*         prebuilt,       /* in/out: prebuilt */
 
2498
        const rec_t*            index_rec,      /* in: record */
 
2499
        const dict_index_t*     index,          /* in: index of the record */
 
2500
        const ulint*            offsets)        /* in: rec_get_offsets
 
2501
                                                (index_rec, index) */
 
2502
{
 
2503
        const byte*     data;
 
2504
        ulint           len;
 
2505
 
 
2506
        ut_ad(rec_offs_validate(index_rec, index, offsets));
 
2507
 
 
2508
        data = rec_get_nth_field(
 
2509
                index_rec, offsets,
 
2510
                dict_index_get_sys_col_pos(index, DATA_ROW_ID), &len);
 
2511
 
 
2512
        if (UNIV_UNLIKELY(len != DATA_ROW_ID_LEN)) {
 
2513
                fprintf(stderr,
 
2514
                        "InnoDB: Error: Row id field is"
 
2515
                        " wrong length %lu in ", (ulong) len);
 
2516
                dict_index_name_print(stderr, prebuilt->trx, index);
 
2517
                fprintf(stderr, "\n"
 
2518
                        "InnoDB: Field number %lu, record:\n",
 
2519
                        (ulong) dict_index_get_sys_col_pos(index,
 
2520
                                                           DATA_ROW_ID));
 
2521
                rec_print_new(stderr, index_rec, offsets);
 
2522
                putc('\n', stderr);
 
2523
                ut_error;
 
2524
        }
 
2525
 
 
2526
        ut_memcpy(prebuilt->row_id, data, len);
 
2527
}
 
2528
 
 
2529
/******************************************************************
 
2530
Stores a non-SQL-NULL field in the MySQL format. The counterpart of this
 
2531
function is row_mysql_store_col_in_innobase_format() in row0mysql.c. */
 
2532
static
 
2533
void
 
2534
row_sel_field_store_in_mysql_format(
 
2535
/*================================*/
 
2536
        byte*           dest,   /* in/out: buffer where to store; NOTE
 
2537
                                that BLOBs are not in themselves
 
2538
                                stored here: the caller must allocate
 
2539
                                and copy the BLOB into buffer before,
 
2540
                                and pass the pointer to the BLOB in
 
2541
                                'data' */
 
2542
        const mysql_row_templ_t* templ,
 
2543
                                /* in: MySQL column template.
 
2544
                                Its following fields are referenced:
 
2545
                                type, is_unsigned, mysql_col_len,
 
2546
                                mbminlen, mbmaxlen */
 
2547
        const byte*     data,   /* in: data to store */
 
2548
        ulint           len)    /* in: length of the data */
 
2549
{
 
2550
        byte*   ptr;
 
2551
        byte*   field_end;
 
2552
        byte*   pad_ptr;
 
2553
 
 
2554
        ut_ad(len != UNIV_SQL_NULL);
 
2555
 
 
2556
        switch (templ->type) {
 
2557
        case DATA_INT:
 
2558
                /* Convert integer data from Innobase to a little-endian
 
2559
                format, sign bit restored to normal */
 
2560
 
 
2561
                ptr = dest + len;
 
2562
 
 
2563
                for (;;) {
 
2564
                        ptr--;
 
2565
                        *ptr = *data;
 
2566
                        if (ptr == dest) {
 
2567
                                break;
 
2568
                        }
 
2569
                        data++;
 
2570
                }
 
2571
 
 
2572
                if (!templ->is_unsigned) {
 
2573
                        dest[len - 1] = (byte) (dest[len - 1] ^ 128);
 
2574
                }
 
2575
 
 
2576
                ut_ad(templ->mysql_col_len == len);
 
2577
                break;
 
2578
 
 
2579
        case DATA_VARCHAR:
 
2580
        case DATA_VARMYSQL:
 
2581
        case DATA_BINARY:
 
2582
                field_end = dest + templ->mysql_col_len;
 
2583
 
 
2584
                if (templ->mysql_type == DATA_MYSQL_TRUE_VARCHAR) {
 
2585
                        /* This is a >= 5.0.3 type true VARCHAR. Store the
 
2586
                        length of the data to the first byte or the first
 
2587
                        two bytes of dest. */
 
2588
 
 
2589
                        dest = row_mysql_store_true_var_len(
 
2590
                                dest, len, templ->mysql_length_bytes);
 
2591
                }
 
2592
 
 
2593
                /* Copy the actual data */
 
2594
                ut_memcpy(dest, data, len);
 
2595
 
 
2596
                /* Pad with trailing spaces. We pad with spaces also the
 
2597
                unused end of a >= 5.0.3 true VARCHAR column, just in case
 
2598
                MySQL expects its contents to be deterministic. */
 
2599
 
 
2600
                pad_ptr = dest + len;
 
2601
 
 
2602
                ut_ad(templ->mbminlen <= templ->mbmaxlen);
 
2603
 
 
2604
                /* We handle UCS2 charset strings differently. */
 
2605
                if (templ->mbminlen == 2) {
 
2606
                        /* A space char is two bytes, 0x0020 in UCS2 */
 
2607
 
 
2608
                        if (len & 1) {
 
2609
                                /* A 0x20 has been stripped from the column.
 
2610
                                Pad it back. */
 
2611
 
 
2612
                                if (pad_ptr < field_end) {
 
2613
                                        *pad_ptr = 0x20;
 
2614
                                        pad_ptr++;
 
2615
                                }
 
2616
                        }
 
2617
 
 
2618
                        /* Pad the rest of the string with 0x0020 */
 
2619
 
 
2620
                        while (pad_ptr < field_end) {
 
2621
                                *pad_ptr = 0x00;
 
2622
                                pad_ptr++;
 
2623
                                *pad_ptr = 0x20;
 
2624
                                pad_ptr++;
 
2625
                        }
 
2626
                } else {
 
2627
                        ut_ad(templ->mbminlen == 1);
 
2628
                        /* space=0x20 */
 
2629
 
 
2630
                        memset(pad_ptr, 0x20, field_end - pad_ptr);
 
2631
                }
 
2632
                break;
 
2633
 
 
2634
        case DATA_BLOB:
 
2635
                /* Store a pointer to the BLOB buffer to dest: the BLOB was
 
2636
                already copied to the buffer in row_sel_store_mysql_rec */
 
2637
 
 
2638
                row_mysql_store_blob_ref(dest, templ->mysql_col_len, data,
 
2639
                                         len);
 
2640
                break;
 
2641
 
 
2642
        case DATA_MYSQL:
 
2643
                memcpy(dest, data, len);
 
2644
 
 
2645
                ut_ad(templ->mysql_col_len >= len);
 
2646
                ut_ad(templ->mbmaxlen >= templ->mbminlen);
 
2647
 
 
2648
                ut_ad(templ->mbmaxlen > templ->mbminlen
 
2649
                      || templ->mysql_col_len == len);
 
2650
                /* The following assertion would fail for old tables
 
2651
                containing UTF-8 ENUM columns due to Bug #9526. */
 
2652
                ut_ad(!templ->mbmaxlen
 
2653
                      || !(templ->mysql_col_len % templ->mbmaxlen));
 
2654
                ut_ad(len * templ->mbmaxlen >= templ->mysql_col_len);
 
2655
 
 
2656
                if (templ->mbminlen != templ->mbmaxlen) {
 
2657
                        /* Pad with spaces. This undoes the stripping
 
2658
                        done in row0mysql.ic, function
 
2659
                        row_mysql_store_col_in_innobase_format(). */
 
2660
 
 
2661
                        memset(dest + len, 0x20, templ->mysql_col_len - len);
 
2662
                }
 
2663
                break;
 
2664
 
 
2665
        default:
 
2666
#ifdef UNIV_DEBUG
 
2667
        case DATA_SYS_CHILD:
 
2668
        case DATA_SYS:
 
2669
                /* These column types should never be shipped to MySQL. */
 
2670
                ut_ad(0);
 
2671
 
 
2672
        case DATA_CHAR:
 
2673
        case DATA_FIXBINARY:
 
2674
        case DATA_FLOAT:
 
2675
        case DATA_DOUBLE:
 
2676
        case DATA_DECIMAL:
 
2677
                /* Above are the valid column types for MySQL data. */
 
2678
#endif /* UNIV_DEBUG */
 
2679
                ut_ad(templ->mysql_col_len == len);
 
2680
                memcpy(dest, data, len);
 
2681
        }
 
2682
}
 
2683
 
 
2684
/******************************************************************
 
2685
Convert a row in the Innobase format to a row in the MySQL format.
 
2686
Note that the template in prebuilt may advise us to copy only a few
 
2687
columns to mysql_rec, other columns are left blank. All columns may not
 
2688
be needed in the query. */
 
2689
static
 
2690
ibool
 
2691
row_sel_store_mysql_rec(
 
2692
/*====================*/
 
2693
                                        /* out: TRUE if success, FALSE if
 
2694
                                        could not allocate memory for a BLOB
 
2695
                                        (though we may also assert in that
 
2696
                                        case) */
 
2697
        byte*           mysql_rec,      /* out: row in the MySQL format */
 
2698
        row_prebuilt_t* prebuilt,       /* in: prebuilt struct */
 
2699
        const rec_t*    rec,            /* in: Innobase record in the index
 
2700
                                        which was described in prebuilt's
 
2701
                                        template; must be protected by
 
2702
                                        a page latch */
 
2703
        const ulint*    offsets)        /* in: array returned by
 
2704
                                        rec_get_offsets() */
 
2705
{
 
2706
        mysql_row_templ_t*      templ;
 
2707
        mem_heap_t*             extern_field_heap       = NULL;
 
2708
        mem_heap_t*             heap;
 
2709
        const byte*             data;
 
2710
        ulint                   len;
 
2711
        ulint                   i;
 
2712
 
 
2713
        ut_ad(prebuilt->mysql_template);
 
2714
        ut_ad(rec_offs_validate(rec, NULL, offsets));
 
2715
 
 
2716
        if (UNIV_LIKELY_NULL(prebuilt->blob_heap)) {
 
2717
                mem_heap_free(prebuilt->blob_heap);
 
2718
                prebuilt->blob_heap = NULL;
 
2719
        }
 
2720
 
 
2721
        for (i = 0; i < prebuilt->n_template; i++) {
 
2722
 
 
2723
                templ = prebuilt->mysql_template + i;
 
2724
 
 
2725
                if (UNIV_UNLIKELY(rec_offs_nth_extern(offsets,
 
2726
                                                      templ->rec_field_no))) {
 
2727
 
 
2728
                        /* Copy an externally stored field to the temporary
 
2729
                        heap */
 
2730
 
 
2731
                        ut_a(!prebuilt->trx->has_search_latch);
 
2732
 
 
2733
                        if (UNIV_UNLIKELY(templ->type == DATA_BLOB)) {
 
2734
                                if (prebuilt->blob_heap == NULL) {
 
2735
                                        prebuilt->blob_heap = mem_heap_create(
 
2736
                                                UNIV_PAGE_SIZE);
 
2737
                                }
 
2738
 
 
2739
                                heap = prebuilt->blob_heap;
 
2740
                        } else {
 
2741
                                extern_field_heap
 
2742
                                        = mem_heap_create(UNIV_PAGE_SIZE);
 
2743
 
 
2744
                                heap = extern_field_heap;
 
2745
                        }
 
2746
 
 
2747
                        /* NOTE: if we are retrieving a big BLOB, we may
 
2748
                        already run out of memory in the next call, which
 
2749
                        causes an assert */
 
2750
 
 
2751
                        data = btr_rec_copy_externally_stored_field(
 
2752
                                rec, offsets,
 
2753
                                dict_table_zip_size(prebuilt->table),
 
2754
                                templ->rec_field_no, &len, heap);
 
2755
 
 
2756
                        ut_a(len != UNIV_SQL_NULL);
 
2757
                } else {
 
2758
                        /* Field is stored in the row. */
 
2759
 
 
2760
                        data = rec_get_nth_field(rec, offsets,
 
2761
                                                 templ->rec_field_no, &len);
 
2762
 
 
2763
                        if (UNIV_UNLIKELY(templ->type == DATA_BLOB)
 
2764
                            && len != UNIV_SQL_NULL) {
 
2765
 
 
2766
                                /* It is a BLOB field locally stored in the
 
2767
                                InnoDB record: we MUST copy its contents to
 
2768
                                prebuilt->blob_heap here because later code
 
2769
                                assumes all BLOB values have been copied to a
 
2770
                                safe place. */
 
2771
 
 
2772
                                if (prebuilt->blob_heap == NULL) {
 
2773
                                        prebuilt->blob_heap = mem_heap_create(
 
2774
                                                UNIV_PAGE_SIZE);
 
2775
                                }
 
2776
 
 
2777
                                data = memcpy(mem_heap_alloc(
 
2778
                                                prebuilt->blob_heap, len),
 
2779
                                                data, len);
 
2780
                        }
 
2781
                }
 
2782
 
 
2783
                if (len != UNIV_SQL_NULL) {
 
2784
                        row_sel_field_store_in_mysql_format(
 
2785
                                mysql_rec + templ->mysql_col_offset,
 
2786
                                templ, data, len);
 
2787
 
 
2788
                        /* Cleanup */
 
2789
                        if (extern_field_heap) {
 
2790
                                mem_heap_free(extern_field_heap);
 
2791
                                extern_field_heap = NULL;
 
2792
                        }
 
2793
 
 
2794
                        if (templ->mysql_null_bit_mask) {
 
2795
                                /* It is a nullable column with a non-NULL
 
2796
                                value */
 
2797
                                mysql_rec[templ->mysql_null_byte_offset]
 
2798
                                        &= ~(byte) templ->mysql_null_bit_mask;
 
2799
                        }
 
2800
                } else {
 
2801
                        /* MySQL seems to assume the field for an SQL NULL
 
2802
                        value is set to zero or space. Not taking this into
 
2803
                        account caused seg faults with NULL BLOB fields, and
 
2804
                        bug number 154 in the MySQL bug database: GROUP BY
 
2805
                        and DISTINCT could treat NULL values inequal. */
 
2806
                        int     pad_char;
 
2807
 
 
2808
                        mysql_rec[templ->mysql_null_byte_offset]
 
2809
                                |= (byte) templ->mysql_null_bit_mask;
 
2810
                        switch (templ->type) {
 
2811
                        case DATA_VARCHAR:
 
2812
                        case DATA_BINARY:
 
2813
                        case DATA_VARMYSQL:
 
2814
                                if (templ->mysql_type
 
2815
                                    == DATA_MYSQL_TRUE_VARCHAR) {
 
2816
                                        /* This is a >= 5.0.3 type
 
2817
                                        true VARCHAR.  Zero the field. */
 
2818
                                        pad_char = 0x00;
 
2819
                                        break;
 
2820
                                }
 
2821
                                /* Fall through */
 
2822
                        case DATA_CHAR:
 
2823
                        case DATA_FIXBINARY:
 
2824
                        case DATA_MYSQL:
 
2825
                                /* MySQL pads all string types (except
 
2826
                                BLOB, TEXT and true VARCHAR) with space. */
 
2827
                                if (UNIV_UNLIKELY(templ->mbminlen == 2)) {
 
2828
                                        /* Treat UCS2 as a special case. */
 
2829
                                        byte* d = mysql_rec
 
2830
                                                + templ->mysql_col_offset;
 
2831
                                        len = templ->mysql_col_len;
 
2832
                                        /* There are two UCS2 bytes per char,
 
2833
                                        so the length has to be even. */
 
2834
                                        ut_a(!(len & 1));
 
2835
                                        /* Pad with 0x0020. */
 
2836
                                        while (len) {
 
2837
                                                *d++ = 0x00;
 
2838
                                                *d++ = 0x20;
 
2839
                                                len -= 2;
 
2840
                                        }
 
2841
                                        continue;
 
2842
                                }
 
2843
                                pad_char = 0x20;
 
2844
                                break;
 
2845
                        default:
 
2846
                                pad_char = 0x00;
 
2847
                                break;
 
2848
                        }
 
2849
 
 
2850
                        ut_ad(!pad_char || templ->mbminlen == 1);
 
2851
                        memset(mysql_rec + templ->mysql_col_offset,
 
2852
                               pad_char, templ->mysql_col_len);
 
2853
                }
 
2854
        }
 
2855
 
 
2856
        return(TRUE);
 
2857
}
 
2858
 
 
2859
/*************************************************************************
 
2860
Builds a previous version of a clustered index record for a consistent read */
 
2861
static
 
2862
ulint
 
2863
row_sel_build_prev_vers_for_mysql(
 
2864
/*==============================*/
 
2865
                                        /* out: DB_SUCCESS or error code */
 
2866
        read_view_t*    read_view,      /* in: read view */
 
2867
        dict_index_t*   clust_index,    /* in: clustered index */
 
2868
        row_prebuilt_t* prebuilt,       /* in: prebuilt struct */
 
2869
        const rec_t*    rec,            /* in: record in a clustered index */
 
2870
        ulint**         offsets,        /* in/out: offsets returned by
 
2871
                                        rec_get_offsets(rec, clust_index) */
 
2872
        mem_heap_t**    offset_heap,    /* in/out: memory heap from which
 
2873
                                        the offsets are allocated */
 
2874
        rec_t**         old_vers,       /* out: old version, or NULL if the
 
2875
                                        record does not exist in the view:
 
2876
                                        i.e., it was freshly inserted
 
2877
                                        afterwards */
 
2878
        mtr_t*          mtr)            /* in: mtr */
 
2879
{
 
2880
        ulint   err;
 
2881
 
 
2882
        if (prebuilt->old_vers_heap) {
 
2883
                mem_heap_empty(prebuilt->old_vers_heap);
 
2884
        } else {
 
2885
                prebuilt->old_vers_heap = mem_heap_create(200);
 
2886
        }
 
2887
 
 
2888
        err = row_vers_build_for_consistent_read(
 
2889
                rec, mtr, clust_index, offsets, read_view, offset_heap,
 
2890
                prebuilt->old_vers_heap, old_vers);
 
2891
        return(err);
 
2892
}
 
2893
 
 
2894
/*************************************************************************
 
2895
Retrieves the clustered index record corresponding to a record in a
 
2896
non-clustered index. Does the necessary locking. Used in the MySQL
 
2897
interface. */
 
2898
static
 
2899
ulint
 
2900
row_sel_get_clust_rec_for_mysql(
 
2901
/*============================*/
 
2902
                                /* out: DB_SUCCESS or error code */
 
2903
        row_prebuilt_t* prebuilt,/* in: prebuilt struct in the handle */
 
2904
        dict_index_t*   sec_index,/* in: secondary index where rec resides */
 
2905
        const rec_t*    rec,    /* in: record in a non-clustered index; if
 
2906
                                this is a locking read, then rec is not
 
2907
                                allowed to be delete-marked, and that would
 
2908
                                not make sense either */
 
2909
        que_thr_t*      thr,    /* in: query thread */
 
2910
        const rec_t**   out_rec,/* out: clustered record or an old version of
 
2911
                                it, NULL if the old version did not exist
 
2912
                                in the read view, i.e., it was a fresh
 
2913
                                inserted version */
 
2914
        ulint**         offsets,/* in: offsets returned by
 
2915
                                rec_get_offsets(rec, sec_index);
 
2916
                                out: offsets returned by
 
2917
                                rec_get_offsets(out_rec, clust_index) */
 
2918
        mem_heap_t**    offset_heap,/* in/out: memory heap from which
 
2919
                                the offsets are allocated */
 
2920
        mtr_t*          mtr)    /* in: mtr used to get access to the
 
2921
                                non-clustered record; the same mtr is used to
 
2922
                                access the clustered index */
 
2923
{
 
2924
        dict_index_t*   clust_index;
 
2925
        const rec_t*    clust_rec;
 
2926
        rec_t*          old_vers;
 
2927
        ulint           err;
 
2928
        trx_t*          trx;
 
2929
 
 
2930
        *out_rec = NULL;
 
2931
        trx = thr_get_trx(thr);
 
2932
 
 
2933
        row_build_row_ref_in_tuple(prebuilt->clust_ref, rec,
 
2934
                                   sec_index, *offsets, trx);
 
2935
 
 
2936
        clust_index = dict_table_get_first_index(sec_index->table);
 
2937
 
 
2938
        btr_pcur_open_with_no_init(clust_index, prebuilt->clust_ref,
 
2939
                                   PAGE_CUR_LE, BTR_SEARCH_LEAF,
 
2940
                                   prebuilt->clust_pcur, 0, mtr);
 
2941
 
 
2942
        clust_rec = btr_pcur_get_rec(prebuilt->clust_pcur);
 
2943
 
 
2944
        prebuilt->clust_pcur->trx_if_known = trx;
 
2945
 
 
2946
        /* Note: only if the search ends up on a non-infimum record is the
 
2947
        low_match value the real match to the search tuple */
 
2948
 
 
2949
        if (!page_rec_is_user_rec(clust_rec)
 
2950
            || btr_pcur_get_low_match(prebuilt->clust_pcur)
 
2951
            < dict_index_get_n_unique(clust_index)) {
 
2952
 
 
2953
                /* In a rare case it is possible that no clust rec is found
 
2954
                for a delete-marked secondary index record: if in row0umod.c
 
2955
                in row_undo_mod_remove_clust_low() we have already removed
 
2956
                the clust rec, while purge is still cleaning and removing
 
2957
                secondary index records associated with earlier versions of
 
2958
                the clustered index record. In that case we know that the
 
2959
                clustered index record did not exist in the read view of
 
2960
                trx. */
 
2961
 
 
2962
                if (!rec_get_deleted_flag(rec,
 
2963
                                          dict_table_is_comp(sec_index->table))
 
2964
                    || prebuilt->select_lock_type != LOCK_NONE) {
 
2965
                        ut_print_timestamp(stderr);
 
2966
                        fputs("  InnoDB: error clustered record"
 
2967
                              " for sec rec not found\n"
 
2968
                              "InnoDB: ", stderr);
 
2969
                        dict_index_name_print(stderr, trx, sec_index);
 
2970
                        fputs("\n"
 
2971
                              "InnoDB: sec index record ", stderr);
 
2972
                        rec_print(stderr, rec, sec_index);
 
2973
                        fputs("\n"
 
2974
                              "InnoDB: clust index record ", stderr);
 
2975
                        rec_print(stderr, clust_rec, clust_index);
 
2976
                        putc('\n', stderr);
 
2977
                        trx_print(stderr, trx, 600);
 
2978
 
 
2979
                        fputs("\n"
 
2980
                              "InnoDB: Submit a detailed bug report"
 
2981
                              " to http://bugs.mysql.com\n", stderr);
 
2982
                }
 
2983
 
 
2984
                clust_rec = NULL;
 
2985
 
 
2986
                goto func_exit;
 
2987
        }
 
2988
 
 
2989
        *offsets = rec_get_offsets(clust_rec, clust_index, *offsets,
 
2990
                                   ULINT_UNDEFINED, offset_heap);
 
2991
 
 
2992
        if (prebuilt->select_lock_type != LOCK_NONE) {
 
2993
                /* Try to place a lock on the index record; we are searching
 
2994
                the clust rec with a unique condition, hence
 
2995
                we set a LOCK_REC_NOT_GAP type lock */
 
2996
 
 
2997
                err = lock_clust_rec_read_check_and_lock(
 
2998
                        0, btr_pcur_get_block(prebuilt->clust_pcur),
 
2999
                        clust_rec, clust_index, *offsets,
 
3000
                        prebuilt->select_lock_type, LOCK_REC_NOT_GAP, thr);
 
3001
                if (err != DB_SUCCESS) {
 
3002
 
 
3003
                        goto err_exit;
 
3004
                }
 
3005
        } else {
 
3006
                /* This is a non-locking consistent read: if necessary, fetch
 
3007
                a previous version of the record */
 
3008
 
 
3009
                old_vers = NULL;
 
3010
 
 
3011
                /* If the isolation level allows reading of uncommitted data,
 
3012
                then we never look for an earlier version */
 
3013
 
 
3014
                if (trx->isolation_level > TRX_ISO_READ_UNCOMMITTED
 
3015
                    && !lock_clust_rec_cons_read_sees(
 
3016
                            clust_rec, clust_index, *offsets,
 
3017
                            trx->read_view)) {
 
3018
 
 
3019
                        /* The following call returns 'offsets' associated with
 
3020
                        'old_vers' */
 
3021
                        err = row_sel_build_prev_vers_for_mysql(
 
3022
                                trx->read_view, clust_index, prebuilt,
 
3023
                                clust_rec, offsets, offset_heap, &old_vers,
 
3024
                                mtr);
 
3025
 
 
3026
                        if (err != DB_SUCCESS || old_vers == NULL) {
 
3027
 
 
3028
                                goto err_exit;
 
3029
                        }
 
3030
 
 
3031
                        clust_rec = old_vers;
 
3032
                }
 
3033
 
 
3034
                /* If we had to go to an earlier version of row or the
 
3035
                secondary index record is delete marked, then it may be that
 
3036
                the secondary index record corresponding to clust_rec
 
3037
                (or old_vers) is not rec; in that case we must ignore
 
3038
                such row because in our snapshot rec would not have existed.
 
3039
                Remember that from rec we cannot see directly which transaction
 
3040
                id corresponds to it: we have to go to the clustered index
 
3041
                record. A query where we want to fetch all rows where
 
3042
                the secondary index value is in some interval would return
 
3043
                a wrong result if we would not drop rows which we come to
 
3044
                visit through secondary index records that would not really
 
3045
                exist in our snapshot. */
 
3046
 
 
3047
                if (clust_rec
 
3048
                    && (old_vers
 
3049
                        || rec_get_deleted_flag(rec, dict_table_is_comp(
 
3050
                                                        sec_index->table)))
 
3051
                    && !row_sel_sec_rec_is_for_clust_rec(
 
3052
                            rec, sec_index, clust_rec, clust_index)) {
 
3053
                        clust_rec = NULL;
 
3054
#ifdef UNIV_SEARCH_DEBUG
 
3055
                } else {
 
3056
                        ut_a(clust_rec == NULL
 
3057
                             || row_sel_sec_rec_is_for_clust_rec(
 
3058
                                     rec, sec_index, clust_rec, clust_index));
 
3059
#endif
 
3060
                }
 
3061
        }
 
3062
 
 
3063
func_exit:
 
3064
        *out_rec = clust_rec;
 
3065
 
 
3066
        if (prebuilt->select_lock_type == LOCK_X) {
 
3067
                /* We may use the cursor in update: store its position */
 
3068
 
 
3069
                btr_pcur_store_position(prebuilt->clust_pcur, mtr);
 
3070
        }
 
3071
 
 
3072
        err = DB_SUCCESS;
 
3073
err_exit:
 
3074
        return(err);
 
3075
}
 
3076
 
 
3077
/************************************************************************
 
3078
Restores cursor position after it has been stored. We have to take into
 
3079
account that the record cursor was positioned on may have been deleted.
 
3080
Then we may have to move the cursor one step up or down. */
 
3081
static
 
3082
ibool
 
3083
sel_restore_position_for_mysql(
 
3084
/*===========================*/
 
3085
                                        /* out: TRUE if we may need to
 
3086
                                        process the record the cursor is
 
3087
                                        now positioned on (i.e. we should
 
3088
                                        not go to the next record yet) */
 
3089
        ibool*          same_user_rec,  /* out: TRUE if we were able to restore
 
3090
                                        the cursor on a user record with the
 
3091
                                        same ordering prefix in in the
 
3092
                                        B-tree index */
 
3093
        ulint           latch_mode,     /* in: latch mode wished in
 
3094
                                        restoration */
 
3095
        btr_pcur_t*     pcur,           /* in: cursor whose position
 
3096
                                        has been stored */
 
3097
        ibool           moves_up,       /* in: TRUE if the cursor moves up
 
3098
                                        in the index */
 
3099
        mtr_t*          mtr)            /* in: mtr; CAUTION: may commit
 
3100
                                        mtr temporarily! */
 
3101
{
 
3102
        ibool   success;
 
3103
        ulint   relative_position;
 
3104
 
 
3105
        relative_position = pcur->rel_pos;
 
3106
 
 
3107
        success = btr_pcur_restore_position(latch_mode, pcur, mtr);
 
3108
 
 
3109
        *same_user_rec = success;
 
3110
 
 
3111
        if (relative_position == BTR_PCUR_ON) {
 
3112
                if (success) {
 
3113
                        return(FALSE);
 
3114
                }
 
3115
 
 
3116
                if (moves_up) {
 
3117
                        btr_pcur_move_to_next(pcur, mtr);
 
3118
                }
 
3119
 
 
3120
                return(TRUE);
 
3121
        }
 
3122
 
 
3123
        if (relative_position == BTR_PCUR_AFTER
 
3124
            || relative_position == BTR_PCUR_AFTER_LAST_IN_TREE) {
 
3125
 
 
3126
                if (moves_up) {
 
3127
                        return(TRUE);
 
3128
                }
 
3129
 
 
3130
                if (btr_pcur_is_on_user_rec(pcur)) {
 
3131
                        btr_pcur_move_to_prev(pcur, mtr);
 
3132
                }
 
3133
 
 
3134
                return(TRUE);
 
3135
        }
 
3136
 
 
3137
        ut_ad(relative_position == BTR_PCUR_BEFORE
 
3138
              || relative_position == BTR_PCUR_BEFORE_FIRST_IN_TREE);
 
3139
 
 
3140
        if (moves_up && btr_pcur_is_on_user_rec(pcur)) {
 
3141
                btr_pcur_move_to_next(pcur, mtr);
 
3142
        }
 
3143
 
 
3144
        return(TRUE);
 
3145
}
 
3146
 
 
3147
/************************************************************************
 
3148
Pops a cached row for MySQL from the fetch cache. */
 
3149
UNIV_INLINE
 
3150
void
 
3151
row_sel_pop_cached_row_for_mysql(
 
3152
/*=============================*/
 
3153
        byte*           buf,            /* in/out: buffer where to copy the
 
3154
                                        row */
 
3155
        row_prebuilt_t* prebuilt)       /* in: prebuilt struct */
 
3156
{
 
3157
        ulint                   i;
 
3158
        mysql_row_templ_t*      templ;
 
3159
        byte*                   cached_rec;
 
3160
        ut_ad(prebuilt->n_fetch_cached > 0);
 
3161
        ut_ad(prebuilt->mysql_prefix_len <= prebuilt->mysql_row_len);
 
3162
 
 
3163
        if (UNIV_UNLIKELY(prebuilt->keep_other_fields_on_keyread)) {
 
3164
                /* Copy cache record field by field, don't touch fields that
 
3165
                are not covered by current key */
 
3166
                cached_rec = prebuilt->fetch_cache[
 
3167
                        prebuilt->fetch_cache_first];
 
3168
 
 
3169
                for (i = 0; i < prebuilt->n_template; i++) {
 
3170
                        templ = prebuilt->mysql_template + i;
 
3171
                        ut_memcpy(buf + templ->mysql_col_offset,
 
3172
                                  cached_rec + templ->mysql_col_offset,
 
3173
                                  templ->mysql_col_len);
 
3174
                        /* Copy NULL bit of the current field from cached_rec
 
3175
                        to buf */
 
3176
                        if (templ->mysql_null_bit_mask) {
 
3177
                                buf[templ->mysql_null_byte_offset]
 
3178
                                        ^= (buf[templ->mysql_null_byte_offset]
 
3179
                                            ^ cached_rec[templ->mysql_null_byte_offset])
 
3180
                                        & (byte)templ->mysql_null_bit_mask;
 
3181
                        }
 
3182
                }
 
3183
        }
 
3184
        else {
 
3185
                ut_memcpy(buf,
 
3186
                          prebuilt->fetch_cache[prebuilt->fetch_cache_first],
 
3187
                          prebuilt->mysql_prefix_len);
 
3188
        }
 
3189
        prebuilt->n_fetch_cached--;
 
3190
        prebuilt->fetch_cache_first++;
 
3191
 
 
3192
        if (prebuilt->n_fetch_cached == 0) {
 
3193
                prebuilt->fetch_cache_first = 0;
 
3194
        }
 
3195
}
 
3196
 
 
3197
/************************************************************************
 
3198
Pushes a row for MySQL to the fetch cache. */
 
3199
UNIV_INLINE
 
3200
void
 
3201
row_sel_push_cache_row_for_mysql(
 
3202
/*=============================*/
 
3203
        row_prebuilt_t* prebuilt,       /* in: prebuilt struct */
 
3204
        const rec_t*    rec,            /* in: record to push; must
 
3205
                                        be protected by a page latch */
 
3206
        const ulint*    offsets)        /* in: rec_get_offsets() */
 
3207
{
 
3208
        byte*   buf;
 
3209
        ulint   i;
 
3210
 
 
3211
        ut_ad(prebuilt->n_fetch_cached < MYSQL_FETCH_CACHE_SIZE);
 
3212
        ut_ad(rec_offs_validate(rec, NULL, offsets));
 
3213
        ut_a(!prebuilt->templ_contains_blob);
 
3214
 
 
3215
        if (prebuilt->fetch_cache[0] == NULL) {
 
3216
                /* Allocate memory for the fetch cache */
 
3217
 
 
3218
                for (i = 0; i < MYSQL_FETCH_CACHE_SIZE; i++) {
 
3219
 
 
3220
                        /* A user has reported memory corruption in these
 
3221
                        buffers in Linux. Put magic numbers there to help
 
3222
                        to track a possible bug. */
 
3223
 
 
3224
                        buf = mem_alloc(prebuilt->mysql_row_len + 8);
 
3225
 
 
3226
                        prebuilt->fetch_cache[i] = buf + 4;
 
3227
 
 
3228
                        mach_write_to_4(buf, ROW_PREBUILT_FETCH_MAGIC_N);
 
3229
                        mach_write_to_4(buf + 4 + prebuilt->mysql_row_len,
 
3230
                                        ROW_PREBUILT_FETCH_MAGIC_N);
 
3231
                }
 
3232
        }
 
3233
 
 
3234
        ut_ad(prebuilt->fetch_cache_first == 0);
 
3235
 
 
3236
        if (UNIV_UNLIKELY(!row_sel_store_mysql_rec(
 
3237
                                  prebuilt->fetch_cache[
 
3238
                                          prebuilt->n_fetch_cached],
 
3239
                                  prebuilt, rec, offsets))) {
 
3240
                ut_error;
 
3241
        }
 
3242
 
 
3243
        prebuilt->n_fetch_cached++;
 
3244
}
 
3245
 
 
3246
/*************************************************************************
 
3247
Tries to do a shortcut to fetch a clustered index record with a unique key,
 
3248
using the hash index if possible (not always). We assume that the search
 
3249
mode is PAGE_CUR_GE, it is a consistent read, there is a read view in trx,
 
3250
btr search latch has been locked in S-mode. */
 
3251
static
 
3252
ulint
 
3253
row_sel_try_search_shortcut_for_mysql(
 
3254
/*==================================*/
 
3255
                                /* out: SEL_FOUND, SEL_EXHAUSTED, SEL_RETRY */
 
3256
        const rec_t**   out_rec,/* out: record if found */
 
3257
        row_prebuilt_t* prebuilt,/* in: prebuilt struct */
 
3258
        ulint**         offsets,/* in/out: for rec_get_offsets(*out_rec) */
 
3259
        mem_heap_t**    heap,   /* in/out: heap for rec_get_offsets() */
 
3260
        mtr_t*          mtr)    /* in: started mtr */
 
3261
{
 
3262
        dict_index_t*   index           = prebuilt->index;
 
3263
        const dtuple_t* search_tuple    = prebuilt->search_tuple;
 
3264
        btr_pcur_t*     pcur            = prebuilt->pcur;
 
3265
        trx_t*          trx             = prebuilt->trx;
 
3266
        const rec_t*    rec;
 
3267
 
 
3268
        ut_ad(dict_index_is_clust(index));
 
3269
        ut_ad(!prebuilt->templ_contains_blob);
 
3270
 
 
3271
        btr_pcur_open_with_no_init(index, search_tuple, PAGE_CUR_GE,
 
3272
                                   BTR_SEARCH_LEAF, pcur,
 
3273
#ifndef UNIV_SEARCH_DEBUG
 
3274
                                   RW_S_LATCH,
 
3275
#else
 
3276
                                   0,
 
3277
#endif
 
3278
                                   mtr);
 
3279
        rec = btr_pcur_get_rec(pcur);
 
3280
 
 
3281
        if (!page_rec_is_user_rec(rec)) {
 
3282
 
 
3283
                return(SEL_RETRY);
 
3284
        }
 
3285
 
 
3286
        /* As the cursor is now placed on a user record after a search with
 
3287
        the mode PAGE_CUR_GE, the up_match field in the cursor tells how many
 
3288
        fields in the user record matched to the search tuple */
 
3289
 
 
3290
        if (btr_pcur_get_up_match(pcur) < dtuple_get_n_fields(search_tuple)) {
 
3291
 
 
3292
                return(SEL_EXHAUSTED);
 
3293
        }
 
3294
 
 
3295
        /* This is a non-locking consistent read: if necessary, fetch
 
3296
        a previous version of the record */
 
3297
 
 
3298
        *offsets = rec_get_offsets(rec, index, *offsets,
 
3299
                                   ULINT_UNDEFINED, heap);
 
3300
 
 
3301
        if (!lock_clust_rec_cons_read_sees(rec, index,
 
3302
                                           *offsets, trx->read_view)) {
 
3303
 
 
3304
                return(SEL_RETRY);
 
3305
        }
 
3306
 
 
3307
        if (rec_get_deleted_flag(rec, dict_table_is_comp(index->table))) {
 
3308
 
 
3309
                return(SEL_EXHAUSTED);
 
3310
        }
 
3311
 
 
3312
        *out_rec = rec;
 
3313
 
 
3314
        return(SEL_FOUND);
 
3315
}
 
3316
 
 
3317
/************************************************************************
 
3318
Searches for rows in the database. This is used in the interface to
 
3319
MySQL. This function opens a cursor, and also implements fetch next
 
3320
and fetch prev. NOTE that if we do a search with a full key value
 
3321
from a unique index (ROW_SEL_EXACT), then we will not store the cursor
 
3322
position and fetch next or fetch prev must not be tried to the cursor! */
 
3323
UNIV_INTERN
 
3324
ulint
 
3325
row_search_for_mysql(
 
3326
/*=================*/
 
3327
                                        /* out: DB_SUCCESS,
 
3328
                                        DB_RECORD_NOT_FOUND,
 
3329
                                        DB_END_OF_INDEX, DB_DEADLOCK,
 
3330
                                        DB_LOCK_TABLE_FULL, DB_CORRUPTION,
 
3331
                                        or DB_TOO_BIG_RECORD */
 
3332
        byte*           buf,            /* in/out: buffer for the fetched
 
3333
                                        row in the MySQL format */
 
3334
        ulint           mode,           /* in: search mode PAGE_CUR_L, ... */
 
3335
        row_prebuilt_t* prebuilt,       /* in: prebuilt struct for the
 
3336
                                        table handle; this contains the info
 
3337
                                        of search_tuple, index; if search
 
3338
                                        tuple contains 0 fields then we
 
3339
                                        position the cursor at the start or
 
3340
                                        the end of the index, depending on
 
3341
                                        'mode' */
 
3342
        ulint           match_mode,     /* in: 0 or ROW_SEL_EXACT or
 
3343
                                        ROW_SEL_EXACT_PREFIX */
 
3344
        ulint           direction)      /* in: 0 or ROW_SEL_NEXT or
 
3345
                                        ROW_SEL_PREV; NOTE: if this is != 0,
 
3346
                                        then prebuilt must have a pcur
 
3347
                                        with stored position! In opening of a
 
3348
                                        cursor 'direction' should be 0. */
 
3349
{
 
3350
        dict_index_t*   index           = prebuilt->index;
 
3351
        ibool           comp            = dict_table_is_comp(index->table);
 
3352
        const dtuple_t* search_tuple    = prebuilt->search_tuple;
 
3353
        btr_pcur_t*     pcur            = prebuilt->pcur;
 
3354
        trx_t*          trx             = prebuilt->trx;
 
3355
        dict_index_t*   clust_index;
 
3356
        que_thr_t*      thr;
 
3357
        const rec_t*    rec;
 
3358
        const rec_t*    result_rec;
 
3359
        const rec_t*    clust_rec;
 
3360
        ulint           err                             = DB_SUCCESS;
 
3361
        ibool           unique_search                   = FALSE;
 
3362
        ibool           unique_search_from_clust_index  = FALSE;
 
3363
        ibool           mtr_has_extra_clust_latch       = FALSE;
 
3364
        ibool           moves_up                        = FALSE;
 
3365
        ibool           set_also_gap_locks              = TRUE;
 
3366
        /* if the query is a plain locking SELECT, and the isolation level
 
3367
        is <= TRX_ISO_READ_COMMITTED, then this is set to FALSE */
 
3368
        ibool           did_semi_consistent_read        = FALSE;
 
3369
        /* if the returned record was locked and we did a semi-consistent
 
3370
        read (fetch the newest committed version), then this is set to
 
3371
        TRUE */
 
3372
#ifdef UNIV_SEARCH_DEBUG
 
3373
        ulint           cnt                             = 0;
 
3374
#endif /* UNIV_SEARCH_DEBUG */
 
3375
        ulint           next_offs;
 
3376
        ibool           same_user_rec;
 
3377
        mtr_t           mtr;
 
3378
        mem_heap_t*     heap                            = NULL;
 
3379
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
 
3380
        ulint*          offsets                         = offsets_;
 
3381
 
 
3382
        rec_offs_init(offsets_);
 
3383
 
 
3384
        ut_ad(index && pcur && search_tuple);
 
3385
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
 
3386
 
 
3387
        if (UNIV_UNLIKELY(prebuilt->table->ibd_file_missing)) {
 
3388
                ut_print_timestamp(stderr);
 
3389
                fprintf(stderr, "  InnoDB: Error:\n"
 
3390
                        "InnoDB: MySQL is trying to use a table handle"
 
3391
                        " but the .ibd file for\n"
 
3392
                        "InnoDB: table %s does not exist.\n"
 
3393
                        "InnoDB: Have you deleted the .ibd file"
 
3394
                        " from the database directory under\n"
 
3395
                        "InnoDB: the MySQL datadir, or have you used"
 
3396
                        " DISCARD TABLESPACE?\n"
 
3397
                        "InnoDB: Look from\n"
 
3398
                        "InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
 
3399
                        "innodb-troubleshooting.html\n"
 
3400
                        "InnoDB: how you can resolve the problem.\n",
 
3401
                        prebuilt->table->name);
 
3402
 
 
3403
                return(DB_ERROR);
 
3404
        }
 
3405
 
 
3406
        if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) {
 
3407
                fprintf(stderr,
 
3408
                        "InnoDB: Error: trying to free a corrupt\n"
 
3409
                        "InnoDB: table handle. Magic n %lu, table name ",
 
3410
                        (ulong) prebuilt->magic_n);
 
3411
                ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
 
3412
                putc('\n', stderr);
 
3413
 
 
3414
                mem_analyze_corruption(prebuilt);
 
3415
 
 
3416
                ut_error;
 
3417
        }
 
3418
 
 
3419
#if 0
 
3420
        /* August 19, 2005 by Heikki: temporarily disable this error
 
3421
        print until the cursor lock count is done correctly.
 
3422
        See bugs #12263 and #12456!*/
 
3423
 
 
3424
        if (trx->n_mysql_tables_in_use == 0
 
3425
            && UNIV_UNLIKELY(prebuilt->select_lock_type == LOCK_NONE)) {
 
3426
                /* Note that if MySQL uses an InnoDB temp table that it
 
3427
                created inside LOCK TABLES, then n_mysql_tables_in_use can
 
3428
                be zero; in that case select_lock_type is set to LOCK_X in
 
3429
                ::start_stmt. */
 
3430
 
 
3431
                fputs("InnoDB: Error: MySQL is trying to perform a SELECT\n"
 
3432
                      "InnoDB: but it has not locked"
 
3433
                      " any tables in ::external_lock()!\n",
 
3434
                      stderr);
 
3435
                trx_print(stderr, trx, 600);
 
3436
                fputc('\n', stderr);
 
3437
        }
 
3438
#endif
 
3439
 
 
3440
#if 0
 
3441
        fprintf(stderr, "Match mode %lu\n search tuple ",
 
3442
                (ulong) match_mode);
 
3443
        dtuple_print(search_tuple);
 
3444
        fprintf(stderr, "N tables locked %lu\n",
 
3445
                (ulong) trx->mysql_n_tables_locked);
 
3446
#endif
 
3447
        /*-------------------------------------------------------------*/
 
3448
        /* PHASE 0: Release a possible s-latch we are holding on the
 
3449
        adaptive hash index latch if there is someone waiting behind */
 
3450
 
 
3451
        if (UNIV_UNLIKELY(btr_search_latch.writer != RW_LOCK_NOT_LOCKED)
 
3452
            && trx->has_search_latch) {
 
3453
 
 
3454
                /* There is an x-latch request on the adaptive hash index:
 
3455
                release the s-latch to reduce starvation and wait for
 
3456
                BTR_SEA_TIMEOUT rounds before trying to keep it again over
 
3457
                calls from MySQL */
 
3458
 
 
3459
                rw_lock_s_unlock(&btr_search_latch);
 
3460
                trx->has_search_latch = FALSE;
 
3461
 
 
3462
                trx->search_latch_timeout = BTR_SEA_TIMEOUT;
 
3463
        }
 
3464
 
 
3465
        /* Reset the new record lock info if srv_locks_unsafe_for_binlog
 
3466
        is set or session is using a READ COMMITED isolation level. Then
 
3467
        we are able to remove the record locks set here on an individual
 
3468
        row. */
 
3469
 
 
3470
        if ((srv_locks_unsafe_for_binlog
 
3471
             || trx->isolation_level == TRX_ISO_READ_COMMITTED)
 
3472
            && prebuilt->select_lock_type != LOCK_NONE) {
 
3473
 
 
3474
                trx_reset_new_rec_lock_info(trx);
 
3475
        }
 
3476
 
 
3477
        /*-------------------------------------------------------------*/
 
3478
        /* PHASE 1: Try to pop the row from the prefetch cache */
 
3479
 
 
3480
        if (UNIV_UNLIKELY(direction == 0)) {
 
3481
                trx->op_info = "starting index read";
 
3482
 
 
3483
                prebuilt->n_rows_fetched = 0;
 
3484
                prebuilt->n_fetch_cached = 0;
 
3485
                prebuilt->fetch_cache_first = 0;
 
3486
 
 
3487
                if (prebuilt->sel_graph == NULL) {
 
3488
                        /* Build a dummy select query graph */
 
3489
                        row_prebuild_sel_graph(prebuilt);
 
3490
                }
 
3491
        } else {
 
3492
                trx->op_info = "fetching rows";
 
3493
 
 
3494
                if (prebuilt->n_rows_fetched == 0) {
 
3495
                        prebuilt->fetch_direction = direction;
 
3496
                }
 
3497
 
 
3498
                if (UNIV_UNLIKELY(direction != prebuilt->fetch_direction)) {
 
3499
                        if (UNIV_UNLIKELY(prebuilt->n_fetch_cached > 0)) {
 
3500
                                ut_error;
 
3501
                                /* TODO: scrollable cursor: restore cursor to
 
3502
                                the place of the latest returned row,
 
3503
                                or better: prevent caching for a scroll
 
3504
                                cursor! */
 
3505
                        }
 
3506
 
 
3507
                        prebuilt->n_rows_fetched = 0;
 
3508
                        prebuilt->n_fetch_cached = 0;
 
3509
                        prebuilt->fetch_cache_first = 0;
 
3510
 
 
3511
                } else if (UNIV_LIKELY(prebuilt->n_fetch_cached > 0)) {
 
3512
                        row_sel_pop_cached_row_for_mysql(buf, prebuilt);
 
3513
 
 
3514
                        prebuilt->n_rows_fetched++;
 
3515
 
 
3516
                        srv_n_rows_read++;
 
3517
                        err = DB_SUCCESS;
 
3518
                        goto func_exit;
 
3519
                }
 
3520
 
 
3521
                if (prebuilt->fetch_cache_first > 0
 
3522
                    && prebuilt->fetch_cache_first < MYSQL_FETCH_CACHE_SIZE) {
 
3523
 
 
3524
                        /* The previous returned row was popped from the fetch
 
3525
                        cache, but the cache was not full at the time of the
 
3526
                        popping: no more rows can exist in the result set */
 
3527
 
 
3528
                        err = DB_RECORD_NOT_FOUND;
 
3529
                        goto func_exit;
 
3530
                }
 
3531
 
 
3532
                prebuilt->n_rows_fetched++;
 
3533
 
 
3534
                if (prebuilt->n_rows_fetched > 1000000000) {
 
3535
                        /* Prevent wrap-over */
 
3536
                        prebuilt->n_rows_fetched = 500000000;
 
3537
                }
 
3538
 
 
3539
                mode = pcur->search_mode;
 
3540
        }
 
3541
 
 
3542
        /* In a search where at most one record in the index may match, we
 
3543
        can use a LOCK_REC_NOT_GAP type record lock when locking a
 
3544
        non-delete-marked matching record.
 
3545
 
 
3546
        Note that in a unique secondary index there may be different
 
3547
        delete-marked versions of a record where only the primary key
 
3548
        values differ: thus in a secondary index we must use next-key
 
3549
        locks when locking delete-marked records. */
 
3550
 
 
3551
        if (match_mode == ROW_SEL_EXACT
 
3552
            && dict_index_is_unique(index)
 
3553
            && dtuple_get_n_fields(search_tuple)
 
3554
            == dict_index_get_n_unique(index)
 
3555
            && (dict_index_is_clust(index)
 
3556
                || !dtuple_contains_null(search_tuple))) {
 
3557
 
 
3558
                /* Note above that a UNIQUE secondary index can contain many
 
3559
                rows with the same key value if one of the columns is the SQL
 
3560
                null. A clustered index under MySQL can never contain null
 
3561
                columns because we demand that all the columns in primary key
 
3562
                are non-null. */
 
3563
 
 
3564
                unique_search = TRUE;
 
3565
 
 
3566
                /* Even if the condition is unique, MySQL seems to try to
 
3567
                retrieve also a second row if a primary key contains more than
 
3568
                1 column. Return immediately if this is not a HANDLER
 
3569
                command. */
 
3570
 
 
3571
                if (UNIV_UNLIKELY(direction != 0
 
3572
                                  && !prebuilt->used_in_HANDLER)) {
 
3573
 
 
3574
                        err = DB_RECORD_NOT_FOUND;
 
3575
                        goto func_exit;
 
3576
                }
 
3577
        }
 
3578
 
 
3579
        mtr_start(&mtr);
 
3580
 
 
3581
        /*-------------------------------------------------------------*/
 
3582
        /* PHASE 2: Try fast adaptive hash index search if possible */
 
3583
 
 
3584
        /* Next test if this is the special case where we can use the fast
 
3585
        adaptive hash index to try the search. Since we must release the
 
3586
        search system latch when we retrieve an externally stored field, we
 
3587
        cannot use the adaptive hash index in a search in the case the row
 
3588
        may be long and there may be externally stored fields */
 
3589
 
 
3590
        if (UNIV_UNLIKELY(direction == 0)
 
3591
            && unique_search
 
3592
            && dict_index_is_clust(index)
 
3593
            && !prebuilt->templ_contains_blob
 
3594
            && !prebuilt->used_in_HANDLER
 
3595
            && (prebuilt->mysql_row_len < UNIV_PAGE_SIZE / 8)) {
 
3596
 
 
3597
                mode = PAGE_CUR_GE;
 
3598
 
 
3599
                unique_search_from_clust_index = TRUE;
 
3600
 
 
3601
                if (trx->mysql_n_tables_locked == 0
 
3602
                    && prebuilt->select_lock_type == LOCK_NONE
 
3603
                    && trx->isolation_level > TRX_ISO_READ_UNCOMMITTED
 
3604
                    && trx->read_view) {
 
3605
 
 
3606
                        /* This is a SELECT query done as a consistent read,
 
3607
                        and the read view has already been allocated:
 
3608
                        let us try a search shortcut through the hash
 
3609
                        index.
 
3610
                        NOTE that we must also test that
 
3611
                        mysql_n_tables_locked == 0, because this might
 
3612
                        also be INSERT INTO ... SELECT ... or
 
3613
                        CREATE TABLE ... SELECT ... . Our algorithm is
 
3614
                        NOT prepared to inserts interleaved with the SELECT,
 
3615
                        and if we try that, we can deadlock on the adaptive
 
3616
                        hash index semaphore! */
 
3617
 
 
3618
#ifndef UNIV_SEARCH_DEBUG
 
3619
                        if (!trx->has_search_latch) {
 
3620
                                rw_lock_s_lock(&btr_search_latch);
 
3621
                                trx->has_search_latch = TRUE;
 
3622
                        }
 
3623
#endif
 
3624
                        switch (row_sel_try_search_shortcut_for_mysql(
 
3625
                                        &rec, prebuilt, &offsets, &heap,
 
3626
                                        &mtr)) {
 
3627
                        case SEL_FOUND:
 
3628
#ifdef UNIV_SEARCH_DEBUG
 
3629
                                ut_a(0 == cmp_dtuple_rec(search_tuple,
 
3630
                                                         rec, offsets));
 
3631
#endif
 
3632
                                /* At this point, rec is protected by
 
3633
                                a page latch that was acquired by
 
3634
                                row_sel_try_search_shortcut_for_mysql().
 
3635
                                The latch will not be released until
 
3636
                                mtr_commit(&mtr). */
 
3637
 
 
3638
                                if (!row_sel_store_mysql_rec(buf, prebuilt,
 
3639
                                                             rec, offsets)) {
 
3640
                                        err = DB_TOO_BIG_RECORD;
 
3641
 
 
3642
                                        /* We let the main loop to do the
 
3643
                                        error handling */
 
3644
                                        goto shortcut_fails_too_big_rec;
 
3645
                                }
 
3646
 
 
3647
                                mtr_commit(&mtr);
 
3648
 
 
3649
                                /* ut_print_name(stderr, index->name);
 
3650
                                fputs(" shortcut\n", stderr); */
 
3651
 
 
3652
                                srv_n_rows_read++;
 
3653
 
 
3654
                                err = DB_SUCCESS;
 
3655
                                goto release_search_latch_if_needed;
 
3656
 
 
3657
                        case SEL_EXHAUSTED:
 
3658
                                mtr_commit(&mtr);
 
3659
 
 
3660
                                /* ut_print_name(stderr, index->name);
 
3661
                                fputs(" record not found 2\n", stderr); */
 
3662
 
 
3663
                                err = DB_RECORD_NOT_FOUND;
 
3664
release_search_latch_if_needed:
 
3665
                                if (trx->search_latch_timeout > 0
 
3666
                                    && trx->has_search_latch) {
 
3667
 
 
3668
                                        trx->search_latch_timeout--;
 
3669
 
 
3670
                                        rw_lock_s_unlock(&btr_search_latch);
 
3671
                                        trx->has_search_latch = FALSE;
 
3672
                                }
 
3673
 
 
3674
                                /* NOTE that we do NOT store the cursor
 
3675
                                position */
 
3676
                                goto func_exit;
 
3677
 
 
3678
                        case SEL_RETRY:
 
3679
                                break;
 
3680
 
 
3681
                        default:
 
3682
                                ut_ad(0);
 
3683
                        }
 
3684
shortcut_fails_too_big_rec:
 
3685
                        mtr_commit(&mtr);
 
3686
                        mtr_start(&mtr);
 
3687
                }
 
3688
        }
 
3689
 
 
3690
        /*-------------------------------------------------------------*/
 
3691
        /* PHASE 3: Open or restore index cursor position */
 
3692
 
 
3693
        if (trx->has_search_latch) {
 
3694
                rw_lock_s_unlock(&btr_search_latch);
 
3695
                trx->has_search_latch = FALSE;
 
3696
        }
 
3697
 
 
3698
        trx_start_if_not_started(trx);
 
3699
 
 
3700
        if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
 
3701
            && prebuilt->select_lock_type != LOCK_NONE
 
3702
            && trx->mysql_thd != NULL
 
3703
            && trx->mysql_query_str != NULL
 
3704
            && *trx->mysql_query_str != NULL) {
 
3705
 
 
3706
                /* Scan the MySQL query string; check if SELECT is the first
 
3707
                word there */
 
3708
 
 
3709
                if (dict_str_starts_with_keyword(
 
3710
                            trx->mysql_thd, *trx->mysql_query_str, "SELECT")) {
 
3711
                        /* It is a plain locking SELECT and the isolation
 
3712
                        level is low: do not lock gaps */
 
3713
 
 
3714
                        set_also_gap_locks = FALSE;
 
3715
                }
 
3716
        }
 
3717
 
 
3718
        /* Note that if the search mode was GE or G, then the cursor
 
3719
        naturally moves upward (in fetch next) in alphabetical order,
 
3720
        otherwise downward */
 
3721
 
 
3722
        if (UNIV_UNLIKELY(direction == 0)) {
 
3723
                if (mode == PAGE_CUR_GE || mode == PAGE_CUR_G) {
 
3724
                        moves_up = TRUE;
 
3725
                }
 
3726
        } else if (direction == ROW_SEL_NEXT) {
 
3727
                moves_up = TRUE;
 
3728
        }
 
3729
 
 
3730
        thr = que_fork_get_first_thr(prebuilt->sel_graph);
 
3731
 
 
3732
        que_thr_move_to_run_state_for_mysql(thr, trx);
 
3733
 
 
3734
        clust_index = dict_table_get_first_index(index->table);
 
3735
 
 
3736
        if (UNIV_LIKELY(direction != 0)) {
 
3737
                ibool   need_to_process = sel_restore_position_for_mysql(
 
3738
                        &same_user_rec, BTR_SEARCH_LEAF,
 
3739
                        pcur, moves_up, &mtr);
 
3740
 
 
3741
                if (UNIV_UNLIKELY(need_to_process)) {
 
3742
                        if (UNIV_UNLIKELY(prebuilt->row_read_type
 
3743
                                          == ROW_READ_DID_SEMI_CONSISTENT)) {
 
3744
                                /* We did a semi-consistent read,
 
3745
                                but the record was removed in
 
3746
                                the meantime. */
 
3747
                                prebuilt->row_read_type
 
3748
                                        = ROW_READ_TRY_SEMI_CONSISTENT;
 
3749
                        }
 
3750
                } else if (UNIV_LIKELY(prebuilt->row_read_type
 
3751
                                       != ROW_READ_DID_SEMI_CONSISTENT)) {
 
3752
 
 
3753
                        /* The cursor was positioned on the record
 
3754
                        that we returned previously.  If we need
 
3755
                        to repeat a semi-consistent read as a
 
3756
                        pessimistic locking read, the record
 
3757
                        cannot be skipped. */
 
3758
 
 
3759
                        goto next_rec;
 
3760
                }
 
3761
 
 
3762
        } else if (dtuple_get_n_fields(search_tuple) > 0) {
 
3763
 
 
3764
                btr_pcur_open_with_no_init(index, search_tuple, mode,
 
3765
                                           BTR_SEARCH_LEAF,
 
3766
                                           pcur, 0, &mtr);
 
3767
 
 
3768
                pcur->trx_if_known = trx;
 
3769
 
 
3770
                rec = btr_pcur_get_rec(pcur);
 
3771
 
 
3772
                if (!moves_up
 
3773
                    && !page_rec_is_supremum(rec)
 
3774
                    && set_also_gap_locks
 
3775
                    && !(srv_locks_unsafe_for_binlog
 
3776
                         || trx->isolation_level == TRX_ISO_READ_COMMITTED)
 
3777
                    && prebuilt->select_lock_type != LOCK_NONE) {
 
3778
 
 
3779
                        /* Try to place a gap lock on the next index record
 
3780
                        to prevent phantoms in ORDER BY ... DESC queries */
 
3781
                        const rec_t*    next = page_rec_get_next_const(rec);
 
3782
 
 
3783
                        offsets = rec_get_offsets(next, index, offsets,
 
3784
                                                  ULINT_UNDEFINED, &heap);
 
3785
                        err = sel_set_rec_lock(btr_pcur_get_block(pcur),
 
3786
                                               next, index, offsets,
 
3787
                                               prebuilt->select_lock_type,
 
3788
                                               LOCK_GAP, thr);
 
3789
 
 
3790
                        if (err != DB_SUCCESS) {
 
3791
 
 
3792
                                goto lock_wait_or_error;
 
3793
                        }
 
3794
                }
 
3795
        } else {
 
3796
                if (mode == PAGE_CUR_G) {
 
3797
                        btr_pcur_open_at_index_side(
 
3798
                                TRUE, index, BTR_SEARCH_LEAF, pcur, FALSE,
 
3799
                                &mtr);
 
3800
                } else if (mode == PAGE_CUR_L) {
 
3801
                        btr_pcur_open_at_index_side(
 
3802
                                FALSE, index, BTR_SEARCH_LEAF, pcur, FALSE,
 
3803
                                &mtr);
 
3804
                }
 
3805
        }
 
3806
 
 
3807
        if (!prebuilt->sql_stat_start) {
 
3808
                /* No need to set an intention lock or assign a read view */
 
3809
 
 
3810
                if (trx->read_view == NULL
 
3811
                    && prebuilt->select_lock_type == LOCK_NONE) {
 
3812
 
 
3813
                        fputs("InnoDB: Error: MySQL is trying to"
 
3814
                              " perform a consistent read\n"
 
3815
                              "InnoDB: but the read view is not assigned!\n",
 
3816
                              stderr);
 
3817
                        trx_print(stderr, trx, 600);
 
3818
                        fputc('\n', stderr);
 
3819
                        ut_a(0);
 
3820
                }
 
3821
        } else if (prebuilt->select_lock_type == LOCK_NONE) {
 
3822
                /* This is a consistent read */
 
3823
                /* Assign a read view for the query */
 
3824
 
 
3825
                trx_assign_read_view(trx);
 
3826
                prebuilt->sql_stat_start = FALSE;
 
3827
        } else {
 
3828
                ulint   lock_mode;
 
3829
                if (prebuilt->select_lock_type == LOCK_S) {
 
3830
                        lock_mode = LOCK_IS;
 
3831
                } else {
 
3832
                        lock_mode = LOCK_IX;
 
3833
                }
 
3834
                err = lock_table(0, index->table, lock_mode, thr);
 
3835
 
 
3836
                if (err != DB_SUCCESS) {
 
3837
 
 
3838
                        goto lock_wait_or_error;
 
3839
                }
 
3840
                prebuilt->sql_stat_start = FALSE;
 
3841
        }
 
3842
 
 
3843
rec_loop:
 
3844
        /*-------------------------------------------------------------*/
 
3845
        /* PHASE 4: Look for matching records in a loop */
 
3846
 
 
3847
        rec = btr_pcur_get_rec(pcur);
 
3848
        ut_ad(!!page_rec_is_comp(rec) == comp);
 
3849
#ifdef UNIV_SEARCH_DEBUG
 
3850
        /*
 
3851
        fputs("Using ", stderr);
 
3852
        dict_index_name_print(stderr, index);
 
3853
        fprintf(stderr, " cnt %lu ; Page no %lu\n", cnt,
 
3854
        page_get_page_no(page_align(rec)));
 
3855
        rec_print(rec);
 
3856
        */
 
3857
#endif /* UNIV_SEARCH_DEBUG */
 
3858
 
 
3859
        if (page_rec_is_infimum(rec)) {
 
3860
 
 
3861
                /* The infimum record on a page cannot be in the result set,
 
3862
                and neither can a record lock be placed on it: we skip such
 
3863
                a record. */
 
3864
 
 
3865
                goto next_rec;
 
3866
        }
 
3867
 
 
3868
        if (page_rec_is_supremum(rec)) {
 
3869
 
 
3870
                if (set_also_gap_locks
 
3871
                    && !(srv_locks_unsafe_for_binlog
 
3872
                         || trx->isolation_level == TRX_ISO_READ_COMMITTED)
 
3873
                    && prebuilt->select_lock_type != LOCK_NONE) {
 
3874
 
 
3875
                        /* Try to place a lock on the index record */
 
3876
 
 
3877
                        /* If innodb_locks_unsafe_for_binlog option is used
 
3878
                        or this session is using a READ COMMITTED isolation
 
3879
                        level we do not lock gaps. Supremum record is really
 
3880
                        a gap and therefore we do not set locks there. */
 
3881
 
 
3882
                        offsets = rec_get_offsets(rec, index, offsets,
 
3883
                                                  ULINT_UNDEFINED, &heap);
 
3884
                        err = sel_set_rec_lock(btr_pcur_get_block(pcur),
 
3885
                                               rec, index, offsets,
 
3886
                                               prebuilt->select_lock_type,
 
3887
                                               LOCK_ORDINARY, thr);
 
3888
 
 
3889
                        if (err != DB_SUCCESS) {
 
3890
 
 
3891
                                goto lock_wait_or_error;
 
3892
                        }
 
3893
                }
 
3894
                /* A page supremum record cannot be in the result set: skip
 
3895
                it now that we have placed a possible lock on it */
 
3896
 
 
3897
                goto next_rec;
 
3898
        }
 
3899
 
 
3900
        /*-------------------------------------------------------------*/
 
3901
        /* Do sanity checks in case our cursor has bumped into page
 
3902
        corruption */
 
3903
 
 
3904
        if (comp) {
 
3905
                next_offs = rec_get_next_offs(rec, TRUE);
 
3906
                if (UNIV_UNLIKELY(next_offs < PAGE_NEW_SUPREMUM)) {
 
3907
 
 
3908
                        goto wrong_offs;
 
3909
                }
 
3910
        } else {
 
3911
                next_offs = rec_get_next_offs(rec, FALSE);
 
3912
                if (UNIV_UNLIKELY(next_offs < PAGE_OLD_SUPREMUM)) {
 
3913
 
 
3914
                        goto wrong_offs;
 
3915
                }
 
3916
        }
 
3917
 
 
3918
        if (UNIV_UNLIKELY(next_offs >= UNIV_PAGE_SIZE - PAGE_DIR)) {
 
3919
 
 
3920
wrong_offs:
 
3921
                if (srv_force_recovery == 0 || moves_up == FALSE) {
 
3922
                        ut_print_timestamp(stderr);
 
3923
                        buf_page_print(page_align(rec), 0);
 
3924
                        fprintf(stderr,
 
3925
                                "\nInnoDB: rec address %p,"
 
3926
                                " buf block fix count %lu\n",
 
3927
                                (void*) rec, (ulong)
 
3928
                                btr_cur_get_block(btr_pcur_get_btr_cur(pcur))
 
3929
                                ->page.buf_fix_count);
 
3930
                        fprintf(stderr,
 
3931
                                "InnoDB: Index corruption: rec offs %lu"
 
3932
                                " next offs %lu, page no %lu,\n"
 
3933
                                "InnoDB: ",
 
3934
                                (ulong) page_offset(rec),
 
3935
                                (ulong) next_offs,
 
3936
                                (ulong) page_get_page_no(page_align(rec)));
 
3937
                        dict_index_name_print(stderr, trx, index);
 
3938
                        fputs(". Run CHECK TABLE. You may need to\n"
 
3939
                              "InnoDB: restore from a backup, or"
 
3940
                              " dump + drop + reimport the table.\n",
 
3941
                              stderr);
 
3942
 
 
3943
                        err = DB_CORRUPTION;
 
3944
 
 
3945
                        goto lock_wait_or_error;
 
3946
                } else {
 
3947
                        /* The user may be dumping a corrupt table. Jump
 
3948
                        over the corruption to recover as much as possible. */
 
3949
 
 
3950
                        fprintf(stderr,
 
3951
                                "InnoDB: Index corruption: rec offs %lu"
 
3952
                                " next offs %lu, page no %lu,\n"
 
3953
                                "InnoDB: ",
 
3954
                                (ulong) page_offset(rec),
 
3955
                                (ulong) next_offs,
 
3956
                                (ulong) page_get_page_no(page_align(rec)));
 
3957
                        dict_index_name_print(stderr, trx, index);
 
3958
                        fputs(". We try to skip the rest of the page.\n",
 
3959
                              stderr);
 
3960
 
 
3961
                        btr_pcur_move_to_last_on_page(pcur, &mtr);
 
3962
 
 
3963
                        goto next_rec;
 
3964
                }
 
3965
        }
 
3966
        /*-------------------------------------------------------------*/
 
3967
 
 
3968
        /* Calculate the 'offsets' associated with 'rec' */
 
3969
 
 
3970
        offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
 
3971
 
 
3972
        if (UNIV_UNLIKELY(srv_force_recovery > 0)) {
 
3973
                if (!rec_validate(rec, offsets)
 
3974
                    || !btr_index_rec_validate(rec, index, FALSE)) {
 
3975
                        fprintf(stderr,
 
3976
                                "InnoDB: Index corruption: rec offs %lu"
 
3977
                                " next offs %lu, page no %lu,\n"
 
3978
                                "InnoDB: ",
 
3979
                                (ulong) page_offset(rec),
 
3980
                                (ulong) next_offs,
 
3981
                                (ulong) page_get_page_no(page_align(rec)));
 
3982
                        dict_index_name_print(stderr, trx, index);
 
3983
                        fputs(". We try to skip the record.\n",
 
3984
                              stderr);
 
3985
 
 
3986
                        goto next_rec;
 
3987
                }
 
3988
        }
 
3989
 
 
3990
        /* Note that we cannot trust the up_match value in the cursor at this
 
3991
        place because we can arrive here after moving the cursor! Thus
 
3992
        we have to recompare rec and search_tuple to determine if they
 
3993
        match enough. */
 
3994
 
 
3995
        if (match_mode == ROW_SEL_EXACT) {
 
3996
                /* Test if the index record matches completely to search_tuple
 
3997
                in prebuilt: if not, then we return with DB_RECORD_NOT_FOUND */
 
3998
 
 
3999
                /* fputs("Comparing rec and search tuple\n", stderr); */
 
4000
 
 
4001
                if (0 != cmp_dtuple_rec(search_tuple, rec, offsets)) {
 
4002
 
 
4003
                        if (set_also_gap_locks
 
4004
                            && !(srv_locks_unsafe_for_binlog
 
4005
                                 || trx->isolation_level
 
4006
                                 == TRX_ISO_READ_COMMITTED)
 
4007
                            && prebuilt->select_lock_type != LOCK_NONE) {
 
4008
 
 
4009
                                /* Try to place a gap lock on the index
 
4010
                                record only if innodb_locks_unsafe_for_binlog
 
4011
                                option is not set or this session is not
 
4012
                                using a READ COMMITTED isolation level. */
 
4013
 
 
4014
                                err = sel_set_rec_lock(
 
4015
                                        btr_pcur_get_block(pcur),
 
4016
                                        rec, index, offsets,
 
4017
                                        prebuilt->select_lock_type, LOCK_GAP,
 
4018
                                        thr);
 
4019
 
 
4020
                                if (err != DB_SUCCESS) {
 
4021
 
 
4022
                                        goto lock_wait_or_error;
 
4023
                                }
 
4024
                        }
 
4025
 
 
4026
                        btr_pcur_store_position(pcur, &mtr);
 
4027
 
 
4028
                        err = DB_RECORD_NOT_FOUND;
 
4029
                        /* ut_print_name(stderr, index->name);
 
4030
                        fputs(" record not found 3\n", stderr); */
 
4031
 
 
4032
                        goto normal_return;
 
4033
                }
 
4034
 
 
4035
        } else if (match_mode == ROW_SEL_EXACT_PREFIX) {
 
4036
 
 
4037
                if (!cmp_dtuple_is_prefix_of_rec(search_tuple, rec, offsets)) {
 
4038
 
 
4039
                        if (set_also_gap_locks
 
4040
                            && !(srv_locks_unsafe_for_binlog
 
4041
                                 || trx->isolation_level
 
4042
                                 == TRX_ISO_READ_COMMITTED)
 
4043
                            && prebuilt->select_lock_type != LOCK_NONE) {
 
4044
 
 
4045
                                /* Try to place a gap lock on the index
 
4046
                                record only if innodb_locks_unsafe_for_binlog
 
4047
                                option is not set or this session is not
 
4048
                                using a READ COMMITTED isolation level. */
 
4049
 
 
4050
                                err = sel_set_rec_lock(
 
4051
                                        btr_pcur_get_block(pcur),
 
4052
                                        rec, index, offsets,
 
4053
                                        prebuilt->select_lock_type, LOCK_GAP,
 
4054
                                        thr);
 
4055
 
 
4056
                                if (err != DB_SUCCESS) {
 
4057
 
 
4058
                                        goto lock_wait_or_error;
 
4059
                                }
 
4060
                        }
 
4061
 
 
4062
                        btr_pcur_store_position(pcur, &mtr);
 
4063
 
 
4064
                        err = DB_RECORD_NOT_FOUND;
 
4065
                        /* ut_print_name(stderr, index->name);
 
4066
                        fputs(" record not found 4\n", stderr); */
 
4067
 
 
4068
                        goto normal_return;
 
4069
                }
 
4070
        }
 
4071
 
 
4072
        /* We are ready to look at a possible new index entry in the result
 
4073
        set: the cursor is now placed on a user record */
 
4074
 
 
4075
        if (prebuilt->select_lock_type != LOCK_NONE) {
 
4076
                /* Try to place a lock on the index record; note that delete
 
4077
                marked records are a special case in a unique search. If there
 
4078
                is a non-delete marked record, then it is enough to lock its
 
4079
                existence with LOCK_REC_NOT_GAP. */
 
4080
 
 
4081
                /* If innodb_locks_unsafe_for_binlog option is used
 
4082
                or this session is using a READ COMMITED isolation
 
4083
                level we lock only the record, i.e., next-key locking is
 
4084
                not used. */
 
4085
 
 
4086
                ulint   lock_type;
 
4087
 
 
4088
                if (!set_also_gap_locks
 
4089
                    || srv_locks_unsafe_for_binlog
 
4090
                    || trx->isolation_level == TRX_ISO_READ_COMMITTED
 
4091
                    || (unique_search
 
4092
                        && !UNIV_UNLIKELY(rec_get_deleted_flag(rec, comp)))) {
 
4093
 
 
4094
                        goto no_gap_lock;
 
4095
                } else {
 
4096
                        lock_type = LOCK_ORDINARY;
 
4097
                }
 
4098
 
 
4099
                /* If we are doing a 'greater or equal than a primary key
 
4100
                value' search from a clustered index, and we find a record
 
4101
                that has that exact primary key value, then there is no need
 
4102
                to lock the gap before the record, because no insert in the
 
4103
                gap can be in our search range. That is, no phantom row can
 
4104
                appear that way.
 
4105
 
 
4106
                An example: if col1 is the primary key, the search is WHERE
 
4107
                col1 >= 100, and we find a record where col1 = 100, then no
 
4108
                need to lock the gap before that record. */
 
4109
 
 
4110
                if (index == clust_index
 
4111
                    && mode == PAGE_CUR_GE
 
4112
                    && direction == 0
 
4113
                    && dtuple_get_n_fields_cmp(search_tuple)
 
4114
                    == dict_index_get_n_unique(index)
 
4115
                    && 0 == cmp_dtuple_rec(search_tuple, rec, offsets)) {
 
4116
no_gap_lock:
 
4117
                        lock_type = LOCK_REC_NOT_GAP;
 
4118
                }
 
4119
 
 
4120
                err = sel_set_rec_lock(btr_pcur_get_block(pcur),
 
4121
                                       rec, index, offsets,
 
4122
                                       prebuilt->select_lock_type,
 
4123
                                       lock_type, thr);
 
4124
 
 
4125
                switch (err) {
 
4126
                        const rec_t*    old_vers;
 
4127
                case DB_SUCCESS:
 
4128
                        break;
 
4129
                case DB_LOCK_WAIT:
 
4130
                        if (UNIV_LIKELY(prebuilt->row_read_type
 
4131
                                        != ROW_READ_TRY_SEMI_CONSISTENT)
 
4132
                            || index != clust_index) {
 
4133
 
 
4134
                                goto lock_wait_or_error;
 
4135
                        }
 
4136
 
 
4137
                        /* The following call returns 'offsets'
 
4138
                        associated with 'old_vers' */
 
4139
                        err = row_sel_build_committed_vers_for_mysql(
 
4140
                                clust_index, prebuilt, rec,
 
4141
                                &offsets, &heap, &old_vers, &mtr);
 
4142
 
 
4143
                        if (err != DB_SUCCESS) {
 
4144
 
 
4145
                                goto lock_wait_or_error;
 
4146
                        }
 
4147
 
 
4148
                        mutex_enter(&kernel_mutex);
 
4149
                        if (trx->was_chosen_as_deadlock_victim) {
 
4150
                                mutex_exit(&kernel_mutex);
 
4151
                                err = DB_DEADLOCK;
 
4152
 
 
4153
                                goto lock_wait_or_error;
 
4154
                        }
 
4155
                        if (UNIV_LIKELY(trx->wait_lock != NULL)) {
 
4156
                                lock_cancel_waiting_and_release(
 
4157
                                        trx->wait_lock);
 
4158
                                trx_reset_new_rec_lock_info(trx);
 
4159
                        } else {
 
4160
                                mutex_exit(&kernel_mutex);
 
4161
 
 
4162
                                /* The lock was granted while we were
 
4163
                                searching for the last committed version.
 
4164
                                Do a normal locking read. */
 
4165
 
 
4166
                                offsets = rec_get_offsets(rec, index, offsets,
 
4167
                                                          ULINT_UNDEFINED,
 
4168
                                                          &heap);
 
4169
                                err = DB_SUCCESS;
 
4170
                                break;
 
4171
                        }
 
4172
                        mutex_exit(&kernel_mutex);
 
4173
 
 
4174
                        if (old_vers == NULL) {
 
4175
                                /* The row was not yet committed */
 
4176
 
 
4177
                                goto next_rec;
 
4178
                        }
 
4179
 
 
4180
                        did_semi_consistent_read = TRUE;
 
4181
                        rec = old_vers;
 
4182
                        break;
 
4183
                default:
 
4184
 
 
4185
                        goto lock_wait_or_error;
 
4186
                }
 
4187
        } else {
 
4188
                /* This is a non-locking consistent read: if necessary, fetch
 
4189
                a previous version of the record */
 
4190
 
 
4191
                if (trx->isolation_level == TRX_ISO_READ_UNCOMMITTED) {
 
4192
 
 
4193
                        /* Do nothing: we let a non-locking SELECT read the
 
4194
                        latest version of the record */
 
4195
 
 
4196
                } else if (index == clust_index) {
 
4197
 
 
4198
                        /* Fetch a previous version of the row if the current
 
4199
                        one is not visible in the snapshot; if we have a very
 
4200
                        high force recovery level set, we try to avoid crashes
 
4201
                        by skipping this lookup */
 
4202
 
 
4203
                        if (UNIV_LIKELY(srv_force_recovery < 5)
 
4204
                            && !lock_clust_rec_cons_read_sees(
 
4205
                                    rec, index, offsets, trx->read_view)) {
 
4206
 
 
4207
                                rec_t*  old_vers;
 
4208
                                /* The following call returns 'offsets'
 
4209
                                associated with 'old_vers' */
 
4210
                                err = row_sel_build_prev_vers_for_mysql(
 
4211
                                        trx->read_view, clust_index,
 
4212
                                        prebuilt, rec, &offsets, &heap,
 
4213
                                        &old_vers, &mtr);
 
4214
 
 
4215
                                if (err != DB_SUCCESS) {
 
4216
 
 
4217
                                        goto lock_wait_or_error;
 
4218
                                }
 
4219
 
 
4220
                                if (old_vers == NULL) {
 
4221
                                        /* The row did not exist yet in
 
4222
                                        the read view */
 
4223
 
 
4224
                                        goto next_rec;
 
4225
                                }
 
4226
 
 
4227
                                rec = old_vers;
 
4228
                        }
 
4229
                } else if (!lock_sec_rec_cons_read_sees(rec, trx->read_view)) {
 
4230
                        /* We are looking into a non-clustered index,
 
4231
                        and to get the right version of the record we
 
4232
                        have to look also into the clustered index: this
 
4233
                        is necessary, because we can only get the undo
 
4234
                        information via the clustered index record. */
 
4235
 
 
4236
                        ut_ad(index != clust_index);
 
4237
 
 
4238
                        goto requires_clust_rec;
 
4239
                }
 
4240
        }
 
4241
 
 
4242
        /* NOTE that at this point rec can be an old version of a clustered
 
4243
        index record built for a consistent read. We cannot assume after this
 
4244
        point that rec is on a buffer pool page. Functions like
 
4245
        page_rec_is_comp() cannot be used! */
 
4246
 
 
4247
        if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, comp))) {
 
4248
 
 
4249
                /* The record is delete-marked: we can skip it */
 
4250
 
 
4251
                if ((srv_locks_unsafe_for_binlog
 
4252
                     || trx->isolation_level == TRX_ISO_READ_COMMITTED)
 
4253
                    && prebuilt->select_lock_type != LOCK_NONE
 
4254
                    && !did_semi_consistent_read) {
 
4255
 
 
4256
                        /* No need to keep a lock on a delete-marked record
 
4257
                        if we do not want to use next-key locking. */
 
4258
 
 
4259
                        row_unlock_for_mysql(prebuilt, TRUE);
 
4260
                }
 
4261
 
 
4262
                /* This is an optimization to skip setting the next key lock
 
4263
                on the record that follows this delete-marked record. This
 
4264
                optimization works because of the unique search criteria
 
4265
                which precludes the presence of a range lock between this
 
4266
                delete marked record and the record following it.
 
4267
 
 
4268
                For now this is applicable only to clustered indexes while
 
4269
                doing a unique search. There is scope for further optimization
 
4270
                applicable to unique secondary indexes. Current behaviour is
 
4271
                to widen the scope of a lock on an already delete marked record
 
4272
                if the same record is deleted twice by the same transaction */
 
4273
                if (index == clust_index && unique_search) {
 
4274
                        err = DB_RECORD_NOT_FOUND;
 
4275
 
 
4276
                        goto normal_return;
 
4277
                }
 
4278
 
 
4279
                goto next_rec;
 
4280
        }
 
4281
 
 
4282
        /* Get the clustered index record if needed, if we did not do the
 
4283
        search using the clustered index. */
 
4284
 
 
4285
        if (index != clust_index && prebuilt->need_to_access_clustered) {
 
4286
 
 
4287
requires_clust_rec:
 
4288
                /* We use a 'goto' to the preceding label if a consistent
 
4289
                read of a secondary index record requires us to look up old
 
4290
                versions of the associated clustered index record. */
 
4291
 
 
4292
                ut_ad(rec_offs_validate(rec, index, offsets));
 
4293
 
 
4294
                /* It was a non-clustered index and we must fetch also the
 
4295
                clustered index record */
 
4296
 
 
4297
                mtr_has_extra_clust_latch = TRUE;
 
4298
 
 
4299
                /* The following call returns 'offsets' associated with
 
4300
                'clust_rec'. Note that 'clust_rec' can be an old version
 
4301
                built for a consistent read. */
 
4302
 
 
4303
                err = row_sel_get_clust_rec_for_mysql(prebuilt, index, rec,
 
4304
                                                      thr, &clust_rec,
 
4305
                                                      &offsets, &heap, &mtr);
 
4306
                if (err != DB_SUCCESS) {
 
4307
 
 
4308
                        goto lock_wait_or_error;
 
4309
                }
 
4310
 
 
4311
                if (clust_rec == NULL) {
 
4312
                        /* The record did not exist in the read view */
 
4313
                        ut_ad(prebuilt->select_lock_type == LOCK_NONE);
 
4314
 
 
4315
                        goto next_rec;
 
4316
                }
 
4317
 
 
4318
                if (UNIV_UNLIKELY(rec_get_deleted_flag(clust_rec, comp))) {
 
4319
 
 
4320
                        /* The record is delete marked: we can skip it */
 
4321
 
 
4322
                        if ((srv_locks_unsafe_for_binlog
 
4323
                             || trx->isolation_level == TRX_ISO_READ_COMMITTED)
 
4324
                            && prebuilt->select_lock_type != LOCK_NONE) {
 
4325
 
 
4326
                                /* No need to keep a lock on a delete-marked
 
4327
                                record if we do not want to use next-key
 
4328
                                locking. */
 
4329
 
 
4330
                                row_unlock_for_mysql(prebuilt, TRUE);
 
4331
                        }
 
4332
 
 
4333
                        goto next_rec;
 
4334
                }
 
4335
 
 
4336
                if (prebuilt->need_to_access_clustered) {
 
4337
 
 
4338
                        result_rec = clust_rec;
 
4339
 
 
4340
                        ut_ad(rec_offs_validate(result_rec, clust_index,
 
4341
                                                offsets));
 
4342
                } else {
 
4343
                        /* We used 'offsets' for the clust rec, recalculate
 
4344
                        them for 'rec' */
 
4345
                        offsets = rec_get_offsets(rec, index, offsets,
 
4346
                                                  ULINT_UNDEFINED, &heap);
 
4347
                        result_rec = rec;
 
4348
                }
 
4349
        } else {
 
4350
                result_rec = rec;
 
4351
        }
 
4352
 
 
4353
        /* We found a qualifying record 'result_rec'. At this point,
 
4354
        'offsets' are associated with 'result_rec'. */
 
4355
 
 
4356
        ut_ad(rec_offs_validate(result_rec,
 
4357
                                result_rec != rec ? clust_index : index,
 
4358
                                offsets));
 
4359
 
 
4360
        /* At this point, the clustered index record is protected
 
4361
        by a page latch that was acquired when pcur was positioned.
 
4362
        The latch will not be released until mtr_commit(&mtr). */
 
4363
 
 
4364
        if ((match_mode == ROW_SEL_EXACT
 
4365
             || prebuilt->n_rows_fetched >= MYSQL_FETCH_CACHE_THRESHOLD)
 
4366
            && prebuilt->select_lock_type == LOCK_NONE
 
4367
            && !prebuilt->templ_contains_blob
 
4368
            && !prebuilt->clust_index_was_generated
 
4369
            && !prebuilt->used_in_HANDLER
 
4370
            && prebuilt->template_type
 
4371
            != ROW_MYSQL_DUMMY_TEMPLATE) {
 
4372
 
 
4373
                /* Inside an update, for example, we do not cache rows,
 
4374
                since we may use the cursor position to do the actual
 
4375
                update, that is why we require ...lock_type == LOCK_NONE.
 
4376
                Since we keep space in prebuilt only for the BLOBs of
 
4377
                a single row, we cannot cache rows in the case there
 
4378
                are BLOBs in the fields to be fetched. In HANDLER we do
 
4379
                not cache rows because there the cursor is a scrollable
 
4380
                cursor. */
 
4381
 
 
4382
                row_sel_push_cache_row_for_mysql(prebuilt, result_rec,
 
4383
                                                 offsets);
 
4384
                if (prebuilt->n_fetch_cached == MYSQL_FETCH_CACHE_SIZE) {
 
4385
 
 
4386
                        goto got_row;
 
4387
                }
 
4388
 
 
4389
                goto next_rec;
 
4390
        } else {
 
4391
                if (prebuilt->template_type == ROW_MYSQL_DUMMY_TEMPLATE) {
 
4392
                        memcpy(buf + 4, result_rec
 
4393
                               - rec_offs_extra_size(offsets),
 
4394
                               rec_offs_size(offsets));
 
4395
                        mach_write_to_4(buf,
 
4396
                                        rec_offs_extra_size(offsets) + 4);
 
4397
                } else {
 
4398
                        if (!row_sel_store_mysql_rec(buf, prebuilt,
 
4399
                                                     result_rec, offsets)) {
 
4400
                                err = DB_TOO_BIG_RECORD;
 
4401
 
 
4402
                                goto lock_wait_or_error;
 
4403
                        }
 
4404
                }
 
4405
 
 
4406
                if (prebuilt->clust_index_was_generated) {
 
4407
                        if (result_rec != rec) {
 
4408
                                offsets = rec_get_offsets(
 
4409
                                        rec, index, offsets, ULINT_UNDEFINED,
 
4410
                                        &heap);
 
4411
                        }
 
4412
                        row_sel_store_row_id_to_prebuilt(prebuilt, rec,
 
4413
                                                         index, offsets);
 
4414
                }
 
4415
        }
 
4416
 
 
4417
        /* From this point on, 'offsets' are invalid. */
 
4418
 
 
4419
got_row:
 
4420
        /* We have an optimization to save CPU time: if this is a consistent
 
4421
        read on a unique condition on the clustered index, then we do not
 
4422
        store the pcur position, because any fetch next or prev will anyway
 
4423
        return 'end of file'. Exceptions are locking reads and the MySQL
 
4424
        HANDLER command where the user can move the cursor with PREV or NEXT
 
4425
        even after a unique search. */
 
4426
 
 
4427
        if (!unique_search_from_clust_index
 
4428
            || prebuilt->select_lock_type != LOCK_NONE
 
4429
            || prebuilt->used_in_HANDLER) {
 
4430
 
 
4431
                /* Inside an update always store the cursor position */
 
4432
 
 
4433
                btr_pcur_store_position(pcur, &mtr);
 
4434
        }
 
4435
 
 
4436
        err = DB_SUCCESS;
 
4437
 
 
4438
        goto normal_return;
 
4439
 
 
4440
next_rec:
 
4441
        /* Reset the old and new "did semi-consistent read" flags. */
 
4442
        if (UNIV_UNLIKELY(prebuilt->row_read_type
 
4443
                          == ROW_READ_DID_SEMI_CONSISTENT)) {
 
4444
                prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
 
4445
        }
 
4446
        did_semi_consistent_read = FALSE;
 
4447
 
 
4448
        if (UNIV_UNLIKELY(srv_locks_unsafe_for_binlog
 
4449
                          || trx->isolation_level == TRX_ISO_READ_COMMITTED)
 
4450
            && prebuilt->select_lock_type != LOCK_NONE) {
 
4451
 
 
4452
                trx_reset_new_rec_lock_info(trx);
 
4453
        }
 
4454
 
 
4455
        /*-------------------------------------------------------------*/
 
4456
        /* PHASE 5: Move the cursor to the next index record */
 
4457
 
 
4458
        if (UNIV_UNLIKELY(mtr_has_extra_clust_latch)) {
 
4459
                /* We must commit mtr if we are moving to the next
 
4460
                non-clustered index record, because we could break the
 
4461
                latching order if we would access a different clustered
 
4462
                index page right away without releasing the previous. */
 
4463
 
 
4464
                btr_pcur_store_position(pcur, &mtr);
 
4465
 
 
4466
                mtr_commit(&mtr);
 
4467
                mtr_has_extra_clust_latch = FALSE;
 
4468
 
 
4469
                mtr_start(&mtr);
 
4470
                if (sel_restore_position_for_mysql(&same_user_rec,
 
4471
                                                   BTR_SEARCH_LEAF,
 
4472
                                                   pcur, moves_up, &mtr)) {
 
4473
#ifdef UNIV_SEARCH_DEBUG
 
4474
                        cnt++;
 
4475
#endif /* UNIV_SEARCH_DEBUG */
 
4476
 
 
4477
                        goto rec_loop;
 
4478
                }
 
4479
        }
 
4480
 
 
4481
        if (moves_up) {
 
4482
                if (UNIV_UNLIKELY(!btr_pcur_move_to_next(pcur, &mtr))) {
 
4483
not_moved:
 
4484
                        btr_pcur_store_position(pcur, &mtr);
 
4485
 
 
4486
                        if (match_mode != 0) {
 
4487
                                err = DB_RECORD_NOT_FOUND;
 
4488
                        } else {
 
4489
                                err = DB_END_OF_INDEX;
 
4490
                        }
 
4491
 
 
4492
                        goto normal_return;
 
4493
                }
 
4494
        } else {
 
4495
                if (UNIV_UNLIKELY(!btr_pcur_move_to_prev(pcur, &mtr))) {
 
4496
                        goto not_moved;
 
4497
                }
 
4498
        }
 
4499
 
 
4500
#ifdef UNIV_SEARCH_DEBUG
 
4501
        cnt++;
 
4502
#endif /* UNIV_SEARCH_DEBUG */
 
4503
 
 
4504
        goto rec_loop;
 
4505
 
 
4506
lock_wait_or_error:
 
4507
        /* Reset the old and new "did semi-consistent read" flags. */
 
4508
        if (UNIV_UNLIKELY(prebuilt->row_read_type
 
4509
                          == ROW_READ_DID_SEMI_CONSISTENT)) {
 
4510
                prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
 
4511
        }
 
4512
        did_semi_consistent_read = FALSE;
 
4513
 
 
4514
        /*-------------------------------------------------------------*/
 
4515
 
 
4516
        btr_pcur_store_position(pcur, &mtr);
 
4517
 
 
4518
        mtr_commit(&mtr);
 
4519
        mtr_has_extra_clust_latch = FALSE;
 
4520
 
 
4521
        trx->error_state = err;
 
4522
 
 
4523
        /* The following is a patch for MySQL */
 
4524
 
 
4525
        que_thr_stop_for_mysql(thr);
 
4526
 
 
4527
        thr->lock_state = QUE_THR_LOCK_ROW;
 
4528
 
 
4529
        if (row_mysql_handle_errors(&err, trx, thr, NULL)) {
 
4530
                /* It was a lock wait, and it ended */
 
4531
 
 
4532
                thr->lock_state = QUE_THR_LOCK_NOLOCK;
 
4533
                mtr_start(&mtr);
 
4534
 
 
4535
                sel_restore_position_for_mysql(&same_user_rec,
 
4536
                                               BTR_SEARCH_LEAF, pcur,
 
4537
                                               moves_up, &mtr);
 
4538
 
 
4539
                if ((srv_locks_unsafe_for_binlog
 
4540
                     || trx->isolation_level == TRX_ISO_READ_COMMITTED)
 
4541
                    && !same_user_rec) {
 
4542
 
 
4543
                        /* Since we were not able to restore the cursor
 
4544
                        on the same user record, we cannot use
 
4545
                        row_unlock_for_mysql() to unlock any records, and
 
4546
                        we must thus reset the new rec lock info. Since
 
4547
                        in lock0lock.c we have blocked the inheriting of gap
 
4548
                        X-locks, we actually do not have any new record locks
 
4549
                        set in this case.
 
4550
 
 
4551
                        Note that if we were able to restore on the 'same'
 
4552
                        user record, it is still possible that we were actually
 
4553
                        waiting on a delete-marked record, and meanwhile
 
4554
                        it was removed by purge and inserted again by some
 
4555
                        other user. But that is no problem, because in
 
4556
                        rec_loop we will again try to set a lock, and
 
4557
                        new_rec_lock_info in trx will be right at the end. */
 
4558
 
 
4559
                        trx_reset_new_rec_lock_info(trx);
 
4560
                }
 
4561
 
 
4562
                mode = pcur->search_mode;
 
4563
 
 
4564
                goto rec_loop;
 
4565
        }
 
4566
 
 
4567
        thr->lock_state = QUE_THR_LOCK_NOLOCK;
 
4568
 
 
4569
#ifdef UNIV_SEARCH_DEBUG
 
4570
        /*      fputs("Using ", stderr);
 
4571
        dict_index_name_print(stderr, index);
 
4572
        fprintf(stderr, " cnt %lu ret value %lu err\n", cnt, err); */
 
4573
#endif /* UNIV_SEARCH_DEBUG */
 
4574
        goto func_exit;
 
4575
 
 
4576
normal_return:
 
4577
        /*-------------------------------------------------------------*/
 
4578
        que_thr_stop_for_mysql_no_error(thr, trx);
 
4579
 
 
4580
        mtr_commit(&mtr);
 
4581
 
 
4582
        if (prebuilt->n_fetch_cached > 0) {
 
4583
                row_sel_pop_cached_row_for_mysql(buf, prebuilt);
 
4584
 
 
4585
                err = DB_SUCCESS;
 
4586
        }
 
4587
 
 
4588
#ifdef UNIV_SEARCH_DEBUG
 
4589
        /*      fputs("Using ", stderr);
 
4590
        dict_index_name_print(stderr, index);
 
4591
        fprintf(stderr, " cnt %lu ret value %lu err\n", cnt, err); */
 
4592
#endif /* UNIV_SEARCH_DEBUG */
 
4593
        if (err == DB_SUCCESS) {
 
4594
                srv_n_rows_read++;
 
4595
        }
 
4596
 
 
4597
func_exit:
 
4598
        trx->op_info = "";
 
4599
        if (UNIV_LIKELY_NULL(heap)) {
 
4600
                mem_heap_free(heap);
 
4601
        }
 
4602
 
 
4603
        /* Set or reset the "did semi-consistent read" flag on return.
 
4604
        The flag did_semi_consistent_read is set if and only if
 
4605
        the record being returned was fetched with a semi-consistent read. */
 
4606
        ut_ad(prebuilt->row_read_type != ROW_READ_WITH_LOCKS
 
4607
              || !did_semi_consistent_read);
 
4608
 
 
4609
        if (UNIV_UNLIKELY(prebuilt->row_read_type != ROW_READ_WITH_LOCKS)) {
 
4610
                if (UNIV_UNLIKELY(did_semi_consistent_read)) {
 
4611
                        prebuilt->row_read_type = ROW_READ_DID_SEMI_CONSISTENT;
 
4612
                } else {
 
4613
                        prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
 
4614
                }
 
4615
        }
 
4616
        return(err);
 
4617
}
 
4618
 
 
4619
/***********************************************************************
 
4620
Checks if MySQL at the moment is allowed for this table to retrieve a
 
4621
consistent read result, or store it to the query cache. */
 
4622
UNIV_INTERN
 
4623
ibool
 
4624
row_search_check_if_query_cache_permitted(
 
4625
/*======================================*/
 
4626
                                        /* out: TRUE if storing or retrieving
 
4627
                                        from the query cache is permitted */
 
4628
        trx_t*          trx,            /* in: transaction object */
 
4629
        const char*     norm_name)      /* in: concatenation of database name,
 
4630
                                        '/' char, table name */
 
4631
{
 
4632
        dict_table_t*   table;
 
4633
        ibool           ret     = FALSE;
 
4634
 
 
4635
        table = dict_table_get(norm_name, FALSE);
 
4636
 
 
4637
        if (table == NULL) {
 
4638
 
 
4639
                return(FALSE);
 
4640
        }
 
4641
 
 
4642
        mutex_enter(&kernel_mutex);
 
4643
 
 
4644
        /* Start the transaction if it is not started yet */
 
4645
 
 
4646
        trx_start_if_not_started_low(trx);
 
4647
 
 
4648
        /* If there are locks on the table or some trx has invalidated the
 
4649
        cache up to our trx id, then ret = FALSE.
 
4650
        We do not check what type locks there are on the table, though only
 
4651
        IX type locks actually would require ret = FALSE. */
 
4652
 
 
4653
        if (UT_LIST_GET_LEN(table->locks) == 0
 
4654
            && ut_dulint_cmp(trx->id,
 
4655
                             table->query_cache_inv_trx_id) >= 0) {
 
4656
 
 
4657
                ret = TRUE;
 
4658
 
 
4659
                /* If the isolation level is high, assign a read view for the
 
4660
                transaction if it does not yet have one */
 
4661
 
 
4662
                if (trx->isolation_level >= TRX_ISO_REPEATABLE_READ
 
4663
                    && !trx->read_view) {
 
4664
 
 
4665
                        trx->read_view = read_view_open_now(
 
4666
                                trx->id, trx->global_read_view_heap);
 
4667
                        trx->global_read_view = trx->read_view;
 
4668
                }
 
4669
        }
 
4670
 
 
4671
        mutex_exit(&kernel_mutex);
 
4672
 
 
4673
        return(ret);
 
4674
}
 
4675
 
 
4676
/***********************************************************************
 
4677
Read the AUTOINC column from the current row. If the value is less than
 
4678
0 and the type is not unsigned then we reset the value to 0. */
 
4679
static
 
4680
ib_uint64_t
 
4681
row_search_autoinc_read_column(
 
4682
/*===========================*/
 
4683
                                        /* out: value read from the column */
 
4684
        dict_index_t*   index,          /* in: index to read from */
 
4685
        const rec_t*    rec,            /* in: current rec */
 
4686
        ulint           col_no,         /* in: column number */
 
4687
        ibool           unsigned_type)  /* in: signed or unsigned flag */
 
4688
{
 
4689
        ulint           len;
 
4690
        const byte*     data;
 
4691
        ib_uint64_t     value;
 
4692
        mem_heap_t*     heap = NULL;
 
4693
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
 
4694
        ulint*          offsets = offsets_;
 
4695
 
 
4696
        rec_offs_init(offsets_);
 
4697
 
 
4698
        offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
 
4699
 
 
4700
        data = rec_get_nth_field(rec, offsets, col_no, &len);
 
4701
 
 
4702
        ut_a(len != UNIV_SQL_NULL);
 
4703
        ut_a(len <= sizeof value);
 
4704
 
 
4705
        /* we assume AUTOINC value cannot be negative */
 
4706
        value = mach_read_int_type(data, len, unsigned_type);
 
4707
 
 
4708
        if (UNIV_LIKELY_NULL(heap)) {
 
4709
                mem_heap_free(heap);
 
4710
        }
 
4711
 
 
4712
        if (!unsigned_type && (ib_int64_t) value < 0) {
 
4713
                value = 0;
 
4714
        }
 
4715
 
 
4716
        return(value);
 
4717
}
 
4718
 
 
4719
/***********************************************************************
 
4720
Get the last row. */
 
4721
static
 
4722
const rec_t*
 
4723
row_search_autoinc_get_rec(
 
4724
/*=======================*/
 
4725
                                        /* out: current rec or NULL */
 
4726
        btr_pcur_t*     pcur,           /* in: the current cursor */
 
4727
        mtr_t*          mtr)            /* in: mini transaction */
 
4728
{
 
4729
        do {
 
4730
                const rec_t* rec = btr_pcur_get_rec(pcur);
 
4731
 
 
4732
                if (page_rec_is_user_rec(rec)) {
 
4733
                        return(rec);
 
4734
                }
 
4735
        } while (btr_pcur_move_to_prev(pcur, mtr));
 
4736
 
 
4737
        return(NULL);
 
4738
}
 
4739
 
 
4740
/***********************************************************************
 
4741
Read the max AUTOINC value from an index. */
 
4742
UNIV_INTERN
 
4743
ulint
 
4744
row_search_max_autoinc(
 
4745
/*===================*/
 
4746
                                        /* out: DB_SUCCESS if all OK else
 
4747
                                        error code, DB_RECORD_NOT_FOUND if
 
4748
                                        column name can't be found in index */
 
4749
        dict_index_t*   index,          /* in: index to search */
 
4750
        const char*     col_name,       /* in: name of autoinc column */
 
4751
        ib_uint64_t*    value)          /* out: AUTOINC value read */
 
4752
{
 
4753
        ulint           i;
 
4754
        ulint           n_cols;
 
4755
        dict_field_t*   dfield = NULL;
 
4756
        ulint           error = DB_SUCCESS;
 
4757
 
 
4758
        n_cols = dict_index_get_n_ordering_defined_by_user(index);
 
4759
 
 
4760
        /* Search the index for the AUTOINC column name */
 
4761
        for (i = 0; i < n_cols; ++i) {
 
4762
                dfield = dict_index_get_nth_field(index, i);
 
4763
 
 
4764
                if (strcmp(col_name, dfield->name) == 0) {
 
4765
                        break;
 
4766
                }
 
4767
        }
 
4768
 
 
4769
        *value = 0;
 
4770
 
 
4771
        /* Must find the AUTOINC column name */
 
4772
        if (i < n_cols && dfield) {
 
4773
                mtr_t           mtr;
 
4774
                btr_pcur_t      pcur;
 
4775
 
 
4776
                mtr_start(&mtr);
 
4777
 
 
4778
                /* Open at the high/right end (FALSE), and INIT
 
4779
                cursor (TRUE) */
 
4780
                btr_pcur_open_at_index_side(
 
4781
                        FALSE, index, BTR_SEARCH_LEAF, &pcur, TRUE, &mtr);
 
4782
 
 
4783
                if (page_get_n_recs(btr_pcur_get_page(&pcur)) > 0) {
 
4784
                        const rec_t*    rec;
 
4785
 
 
4786
                        rec = row_search_autoinc_get_rec(&pcur, &mtr);
 
4787
 
 
4788
                        if (rec != NULL) {
 
4789
                                ibool unsigned_type = (
 
4790
                                        dfield->col->prtype & DATA_UNSIGNED);
 
4791
 
 
4792
                                *value = row_search_autoinc_read_column(
 
4793
                                        index, rec, i, unsigned_type);
 
4794
                        }
 
4795
                }
 
4796
 
 
4797
                btr_pcur_close(&pcur);
 
4798
 
 
4799
                mtr_commit(&mtr);
 
4800
        } else {
 
4801
                error = DB_RECORD_NOT_FOUND;
 
4802
        }
 
4803
 
 
4804
        return(error);
 
4805
}