~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2008-10-28 08:36:02 UTC
  • mfrom: (520.4.13 merge-innodb-plugin)
  • Revision ID: brian@tangent.org-20081028083602-0p3zzlhlxr5q2sqo
Merging Monty's work

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
 
 
1675
        /* PHASE 5: Get the clustered index record, if needed and if we did
 
1676
        not do the search using the clustered index */
 
1677
 
 
1678
        if (plan->must_get_clust || cons_read_requires_clust_rec) {
 
1679
 
 
1680
                /* It was a non-clustered index and we must fetch also the
 
1681
                clustered index record */
 
1682
 
 
1683
                err = row_sel_get_clust_rec(node, plan, rec, thr, &clust_rec,
 
1684
                                            &mtr);
 
1685
                mtr_has_extra_clust_latch = TRUE;
 
1686
 
 
1687
                if (err != DB_SUCCESS) {
 
1688
 
 
1689
                        goto lock_wait_or_error;
 
1690
                }
 
1691
 
 
1692
                /* Retrieving the clustered record required a search:
 
1693
                increment the cost counter */
 
1694
 
 
1695
                cost_counter++;
 
1696
 
 
1697
                if (clust_rec == NULL) {
 
1698
                        /* The record did not exist in the read view */
 
1699
                        ut_ad(consistent_read);
 
1700
 
 
1701
                        goto next_rec;
 
1702
                }
 
1703
 
 
1704
                if (rec_get_deleted_flag(clust_rec,
 
1705
                                         dict_table_is_comp(plan->table))) {
 
1706
 
 
1707
                        /* The record is delete marked: we can skip it */
 
1708
 
 
1709
                        goto next_rec;
 
1710
                }
 
1711
 
 
1712
                if (node->can_get_updated) {
 
1713
 
 
1714
                        btr_pcur_store_position(&(plan->clust_pcur), &mtr);
 
1715
                }
 
1716
        }
 
1717
 
 
1718
        /* PHASE 6: Test the rest of search conditions */
 
1719
 
 
1720
        if (!row_sel_test_other_conds(plan)) {
 
1721
 
 
1722
                if (plan->unique_search) {
 
1723
 
 
1724
                        goto table_exhausted;
 
1725
                }
 
1726
 
 
1727
                goto next_rec;
 
1728
        }
 
1729
 
 
1730
        /* PHASE 7: We found a new qualifying row for the current table; push
 
1731
        the row if prefetch is on, or move to the next table in the join */
 
1732
 
 
1733
        plan->n_rows_fetched++;
 
1734
 
 
1735
        ut_ad(plan->pcur.latch_mode == node->latch_mode);
 
1736
 
 
1737
        if (node->select_will_do_update) {
 
1738
                /* This is a searched update and we can do the update in-place,
 
1739
                saving CPU time */
 
1740
 
 
1741
                row_upd_in_place_in_select(node, thr, &mtr);
 
1742
 
 
1743
                leaf_contains_updates = TRUE;
 
1744
 
 
1745
                /* When the database is in the online backup mode, the number
 
1746
                of log records for a single mtr should be small: increment the
 
1747
                cost counter to ensure it */
 
1748
 
 
1749
                cost_counter += 1 + (SEL_COST_LIMIT / 8);
 
1750
 
 
1751
                if (plan->unique_search) {
 
1752
 
 
1753
                        goto table_exhausted;
 
1754
                }
 
1755
 
 
1756
                goto next_rec;
 
1757
        }
 
1758
 
 
1759
        if ((plan->n_rows_fetched <= SEL_PREFETCH_LIMIT)
 
1760
            || plan->unique_search || plan->no_prefetch
 
1761
            || plan->table->big_rows) {
 
1762
 
 
1763
                /* No prefetch in operation: go to the next table */
 
1764
 
 
1765
                goto next_table;
 
1766
        }
 
1767
 
 
1768
        sel_push_prefetched_row(plan);
 
1769
 
 
1770
        if (plan->n_rows_prefetched == SEL_MAX_N_PREFETCH) {
 
1771
 
 
1772
                /* The prefetch buffer is now full */
 
1773
 
 
1774
                sel_pop_prefetched_row(plan);
 
1775
 
 
1776
                goto next_table;
 
1777
        }
 
1778
 
 
1779
next_rec:
 
1780
        ut_ad(!search_latch_locked);
 
1781
 
 
1782
        if (mtr_has_extra_clust_latch) {
 
1783
 
 
1784
                /* We must commit &mtr if we are moving to the next
 
1785
                non-clustered index record, because we could break the
 
1786
                latching order if we would access a different clustered
 
1787
                index page right away without releasing the previous. */
 
1788
 
 
1789
                goto commit_mtr_for_a_while;
 
1790
        }
 
1791
 
 
1792
        if (leaf_contains_updates
 
1793
            && btr_pcur_is_after_last_on_page(&plan->pcur)) {
 
1794
 
 
1795
                /* We must commit &mtr if we are moving to a different page,
 
1796
                because we have done updates to the x-latched leaf page, and
 
1797
                the latch would be released in btr_pcur_move_to_next, without
 
1798
                &mtr getting committed there */
 
1799
 
 
1800
                ut_ad(node->asc);
 
1801
 
 
1802
                goto commit_mtr_for_a_while;
 
1803
        }
 
1804
 
 
1805
        if (node->asc) {
 
1806
                moved = btr_pcur_move_to_next(&(plan->pcur), &mtr);
 
1807
        } else {
 
1808
                moved = btr_pcur_move_to_prev(&(plan->pcur), &mtr);
 
1809
        }
 
1810
 
 
1811
        if (!moved) {
 
1812
 
 
1813
                goto table_exhausted;
 
1814
        }
 
1815
 
 
1816
        cursor_just_opened = FALSE;
 
1817
 
 
1818
        /* END OF RECORD LOOP
 
1819
        ------------------ */
 
1820
        goto rec_loop;
 
1821
 
 
1822
next_table:
 
1823
        /* We found a record which satisfies the conditions: we can move to
 
1824
        the next table or return a row in the result set */
 
1825
 
 
1826
        ut_ad(btr_pcur_is_on_user_rec(&plan->pcur));
 
1827
 
 
1828
        if (plan->unique_search && !node->can_get_updated) {
 
1829
 
 
1830
                plan->cursor_at_end = TRUE;
 
1831
        } else {
 
1832
                ut_ad(!search_latch_locked);
 
1833
 
 
1834
                plan->stored_cursor_rec_processed = TRUE;
 
1835
 
 
1836
                btr_pcur_store_position(&(plan->pcur), &mtr);
 
1837
        }
 
1838
 
 
1839
        mtr_commit(&mtr);
 
1840
 
 
1841
        leaf_contains_updates = FALSE;
 
1842
        mtr_has_extra_clust_latch = FALSE;
 
1843
 
 
1844
next_table_no_mtr:
 
1845
        /* If we use 'goto' to this label, it means that the row was popped
 
1846
        from the prefetched rows stack, and &mtr is already committed */
 
1847
 
 
1848
        if (node->fetch_table + 1 == node->n_tables) {
 
1849
 
 
1850
                sel_eval_select_list(node);
 
1851
 
 
1852
                if (node->is_aggregate) {
 
1853
 
 
1854
                        goto table_loop;
 
1855
                }
 
1856
 
 
1857
                sel_assign_into_var_values(node->into_list, node);
 
1858
 
 
1859
                thr->run_node = que_node_get_parent(node);
 
1860
 
 
1861
                err = DB_SUCCESS;
 
1862
                goto func_exit;
 
1863
        }
 
1864
 
 
1865
        node->fetch_table++;
 
1866
 
 
1867
        /* When we move to the next table, we first reset the plan cursor:
 
1868
        we do not care about resetting it when we backtrack from a table */
 
1869
 
 
1870
        plan_reset_cursor(sel_node_get_nth_plan(node, node->fetch_table));
 
1871
 
 
1872
        goto table_loop;
 
1873
 
 
1874
table_exhausted:
 
1875
        /* The table cursor pcur reached the result set end: backtrack to the
 
1876
        previous table in the join if we do not have cached prefetched rows */
 
1877
 
 
1878
        plan->cursor_at_end = TRUE;
 
1879
 
 
1880
        mtr_commit(&mtr);
 
1881
 
 
1882
        leaf_contains_updates = FALSE;
 
1883
        mtr_has_extra_clust_latch = FALSE;
 
1884
 
 
1885
        if (plan->n_rows_prefetched > 0) {
 
1886
                /* The table became exhausted during a prefetch */
 
1887
 
 
1888
                sel_pop_prefetched_row(plan);
 
1889
 
 
1890
                goto next_table_no_mtr;
 
1891
        }
 
1892
 
 
1893
table_exhausted_no_mtr:
 
1894
        if (node->fetch_table == 0) {
 
1895
                err = DB_SUCCESS;
 
1896
 
 
1897
                if (node->is_aggregate && !node->aggregate_already_fetched) {
 
1898
 
 
1899
                        node->aggregate_already_fetched = TRUE;
 
1900
 
 
1901
                        sel_assign_into_var_values(node->into_list, node);
 
1902
 
 
1903
                        thr->run_node = que_node_get_parent(node);
 
1904
                } else {
 
1905
                        node->state = SEL_NODE_NO_MORE_ROWS;
 
1906
 
 
1907
                        thr->run_node = que_node_get_parent(node);
 
1908
                }
 
1909
 
 
1910
                goto func_exit;
 
1911
        }
 
1912
 
 
1913
        node->fetch_table--;
 
1914
 
 
1915
        goto table_loop;
 
1916
 
 
1917
stop_for_a_while:
 
1918
        /* Return control for a while to que_run_threads, so that runaway
 
1919
        queries can be canceled. NOTE that when we come here, we must, in a
 
1920
        locking read, have placed the necessary (possibly waiting request)
 
1921
        record lock on the cursor record or its successor: when we reposition
 
1922
        the cursor, this record lock guarantees that nobody can meanwhile have
 
1923
        inserted new records which should have appeared in the result set,
 
1924
        which would result in the phantom problem. */
 
1925
 
 
1926
        ut_ad(!search_latch_locked);
 
1927
 
 
1928
        plan->stored_cursor_rec_processed = FALSE;
 
1929
        btr_pcur_store_position(&(plan->pcur), &mtr);
 
1930
 
 
1931
        mtr_commit(&mtr);
 
1932
 
 
1933
#ifdef UNIV_SYNC_DEBUG
 
1934
        ut_ad(sync_thread_levels_empty_gen(TRUE));
 
1935
#endif /* UNIV_SYNC_DEBUG */
 
1936
        err = DB_SUCCESS;
 
1937
        goto func_exit;
 
1938
 
 
1939
commit_mtr_for_a_while:
 
1940
        /* Stores the cursor position and commits &mtr; this is used if
 
1941
        &mtr may contain latches which would break the latching order if
 
1942
        &mtr would not be committed and the latches released. */
 
1943
 
 
1944
        plan->stored_cursor_rec_processed = TRUE;
 
1945
 
 
1946
        ut_ad(!search_latch_locked);
 
1947
        btr_pcur_store_position(&(plan->pcur), &mtr);
 
1948
 
 
1949
        mtr_commit(&mtr);
 
1950
 
 
1951
        leaf_contains_updates = FALSE;
 
1952
        mtr_has_extra_clust_latch = FALSE;
 
1953
 
 
1954
#ifdef UNIV_SYNC_DEBUG
 
1955
        ut_ad(sync_thread_levels_empty_gen(TRUE));
 
1956
#endif /* UNIV_SYNC_DEBUG */
 
1957
 
 
1958
        goto table_loop;
 
1959
 
 
1960
lock_wait_or_error:
 
1961
        /* See the note at stop_for_a_while: the same holds for this case */
 
1962
 
 
1963
        ut_ad(!btr_pcur_is_before_first_on_page(&plan->pcur) || !node->asc);
 
1964
        ut_ad(!search_latch_locked);
 
1965
 
 
1966
        plan->stored_cursor_rec_processed = FALSE;
 
1967
        btr_pcur_store_position(&(plan->pcur), &mtr);
 
1968
 
 
1969
        mtr_commit(&mtr);
 
1970
 
 
1971
#ifdef UNIV_SYNC_DEBUG
 
1972
        ut_ad(sync_thread_levels_empty_gen(TRUE));
 
1973
#endif /* UNIV_SYNC_DEBUG */
 
1974
 
 
1975
func_exit:
 
1976
        if (search_latch_locked) {
 
1977
                rw_lock_s_unlock(&btr_search_latch);
 
1978
        }
 
1979
        if (UNIV_LIKELY_NULL(heap)) {
 
1980
                mem_heap_free(heap);
 
1981
        }
 
1982
        return(err);
 
1983
}
 
1984
 
 
1985
/**************************************************************************
 
1986
Performs a select step. This is a high-level function used in SQL execution
 
1987
graphs. */
 
1988
UNIV_INTERN
 
1989
que_thr_t*
 
1990
row_sel_step(
 
1991
/*=========*/
 
1992
                                /* out: query thread to run next or NULL */
 
1993
        que_thr_t*      thr)    /* in: query thread */
 
1994
{
 
1995
        ulint           i_lock_mode;
 
1996
        sym_node_t*     table_node;
 
1997
        sel_node_t*     node;
 
1998
        ulint           err;
 
1999
 
 
2000
        ut_ad(thr);
 
2001
 
 
2002
        node = thr->run_node;
 
2003
 
 
2004
        ut_ad(que_node_get_type(node) == QUE_NODE_SELECT);
 
2005
 
 
2006
        /* If this is a new time this node is executed (or when execution
 
2007
        resumes after wait for a table intention lock), set intention locks
 
2008
        on the tables, or assign a read view */
 
2009
 
 
2010
        if (node->into_list && (thr->prev_node == que_node_get_parent(node))) {
 
2011
 
 
2012
                node->state = SEL_NODE_OPEN;
 
2013
        }
 
2014
 
 
2015
        if (node->state == SEL_NODE_OPEN) {
 
2016
 
 
2017
                /* It may be that the current session has not yet started
 
2018
                its transaction, or it has been committed: */
 
2019
 
 
2020
                trx_start_if_not_started(thr_get_trx(thr));
 
2021
 
 
2022
                plan_reset_cursor(sel_node_get_nth_plan(node, 0));
 
2023
 
 
2024
                if (node->consistent_read) {
 
2025
                        /* Assign a read view for the query */
 
2026
                        node->read_view = trx_assign_read_view(
 
2027
                                thr_get_trx(thr));
 
2028
                } else {
 
2029
                        if (node->set_x_locks) {
 
2030
                                i_lock_mode = LOCK_IX;
 
2031
                        } else {
 
2032
                                i_lock_mode = LOCK_IS;
 
2033
                        }
 
2034
 
 
2035
                        table_node = node->table_list;
 
2036
 
 
2037
                        while (table_node) {
 
2038
                                err = lock_table(0, table_node->table,
 
2039
                                                 i_lock_mode, thr);
 
2040
                                if (err != DB_SUCCESS) {
 
2041
                                        thr_get_trx(thr)->error_state = err;
 
2042
 
 
2043
                                        return(NULL);
 
2044
                                }
 
2045
 
 
2046
                                table_node = que_node_get_next(table_node);
 
2047
                        }
 
2048
                }
 
2049
 
 
2050
                /* If this is an explicit cursor, copy stored procedure
 
2051
                variable values, so that the values cannot change between
 
2052
                fetches (currently, we copy them also for non-explicit
 
2053
                cursors) */
 
2054
 
 
2055
                if (node->explicit_cursor
 
2056
                    && UT_LIST_GET_FIRST(node->copy_variables)) {
 
2057
 
 
2058
                        row_sel_copy_input_variable_vals(node);
 
2059
                }
 
2060
 
 
2061
                node->state = SEL_NODE_FETCH;
 
2062
                node->fetch_table = 0;
 
2063
 
 
2064
                if (node->is_aggregate) {
 
2065
                        /* Reset the aggregate total values */
 
2066
                        sel_reset_aggregate_vals(node);
 
2067
                }
 
2068
        }
 
2069
 
 
2070
        err = row_sel(node, thr);
 
2071
 
 
2072
        /* NOTE! if queries are parallelized, the following assignment may
 
2073
        have problems; the assignment should be made only if thr is the
 
2074
        only top-level thr in the graph: */
 
2075
 
 
2076
        thr->graph->last_sel_node = node;
 
2077
 
 
2078
        if (err != DB_SUCCESS) {
 
2079
                thr_get_trx(thr)->error_state = err;
 
2080
 
 
2081
                return(NULL);
 
2082
        }
 
2083
 
 
2084
        return(thr);
 
2085
}
 
2086
 
 
2087
/**************************************************************************
 
2088
Performs a fetch for a cursor. */
 
2089
UNIV_INTERN
 
2090
que_thr_t*
 
2091
fetch_step(
 
2092
/*=======*/
 
2093
                                /* out: query thread to run next or NULL */
 
2094
        que_thr_t*      thr)    /* in: query thread */
 
2095
{
 
2096
        sel_node_t*     sel_node;
 
2097
        fetch_node_t*   node;
 
2098
 
 
2099
        ut_ad(thr);
 
2100
 
 
2101
        node = thr->run_node;
 
2102
        sel_node = node->cursor_def;
 
2103
 
 
2104
        ut_ad(que_node_get_type(node) == QUE_NODE_FETCH);
 
2105
 
 
2106
        if (thr->prev_node != que_node_get_parent(node)) {
 
2107
 
 
2108
                if (sel_node->state != SEL_NODE_NO_MORE_ROWS) {
 
2109
 
 
2110
                        if (node->into_list) {
 
2111
                                sel_assign_into_var_values(node->into_list,
 
2112
                                                           sel_node);
 
2113
                        } else {
 
2114
                                void* ret = (*node->func->func)(
 
2115
                                        sel_node, node->func->arg);
 
2116
 
 
2117
                                if (!ret) {
 
2118
                                        sel_node->state
 
2119
                                                = SEL_NODE_NO_MORE_ROWS;
 
2120
                                }
 
2121
                        }
 
2122
                }
 
2123
 
 
2124
                thr->run_node = que_node_get_parent(node);
 
2125
 
 
2126
                return(thr);
 
2127
        }
 
2128
 
 
2129
        /* Make the fetch node the parent of the cursor definition for
 
2130
        the time of the fetch, so that execution knows to return to this
 
2131
        fetch node after a row has been selected or we know that there is
 
2132
        no row left */
 
2133
 
 
2134
        sel_node->common.parent = node;
 
2135
 
 
2136
        if (sel_node->state == SEL_NODE_CLOSED) {
 
2137
                fprintf(stderr,
 
2138
                        "InnoDB: Error: fetch called on a closed cursor\n");
 
2139
 
 
2140
                thr_get_trx(thr)->error_state = DB_ERROR;
 
2141
 
 
2142
                return(NULL);
 
2143
        }
 
2144
 
 
2145
        thr->run_node = sel_node;
 
2146
 
 
2147
        return(thr);
 
2148
}
 
2149
 
 
2150
/********************************************************************
 
2151
Sample callback function for fetch that prints each row.*/
 
2152
UNIV_INTERN
 
2153
void*
 
2154
row_fetch_print(
 
2155
/*============*/
 
2156
                                /* out: always returns non-NULL */
 
2157
        void*   row,            /* in:  sel_node_t* */
 
2158
        void*   user_arg)       /* in:  not used */
 
2159
{
 
2160
        sel_node_t*     node = row;
 
2161
        que_node_t*     exp;
 
2162
        ulint           i = 0;
 
2163
 
 
2164
        UT_NOT_USED(user_arg);
 
2165
 
 
2166
        fprintf(stderr, "row_fetch_print: row %p\n", row);
 
2167
 
 
2168
        exp = node->select_list;
 
2169
 
 
2170
        while (exp) {
 
2171
                dfield_t*       dfield = que_node_get_val(exp);
 
2172
                const dtype_t*  type = dfield_get_type(dfield);
 
2173
 
 
2174
                fprintf(stderr, " column %lu:\n", (ulong)i);
 
2175
 
 
2176
                dtype_print(type);
 
2177
                fprintf(stderr, "\n");
 
2178
 
 
2179
                if (dfield_get_len(dfield) != UNIV_SQL_NULL) {
 
2180
                        ut_print_buf(stderr, dfield_get_data(dfield),
 
2181
                                     dfield_get_len(dfield));
 
2182
                } else {
 
2183
                        fprintf(stderr, " <NULL>;");
 
2184
                }
 
2185
 
 
2186
                fprintf(stderr, "\n");
 
2187
 
 
2188
                exp = que_node_get_next(exp);
 
2189
                i++;
 
2190
        }
 
2191
 
 
2192
        return((void*)42);
 
2193
}
 
2194
 
 
2195
/********************************************************************
 
2196
Callback function for fetch that stores an unsigned 4 byte integer to the
 
2197
location pointed. The column's type must be DATA_INT, DATA_UNSIGNED, length
 
2198
= 4. */
 
2199
UNIV_INTERN
 
2200
void*
 
2201
row_fetch_store_uint4(
 
2202
/*==================*/
 
2203
                                /* out: always returns NULL */
 
2204
        void*   row,            /* in:  sel_node_t* */
 
2205
        void*   user_arg)       /* in:  data pointer */
 
2206
{
 
2207
        sel_node_t*     node = row;
 
2208
        ib_uint32_t*    val = user_arg;
 
2209
        ulint           tmp;
 
2210
 
 
2211
        dfield_t*       dfield = que_node_get_val(node->select_list);
 
2212
        const dtype_t*  type = dfield_get_type(dfield);
 
2213
        ulint           len = dfield_get_len(dfield);
 
2214
 
 
2215
        ut_a(dtype_get_mtype(type) == DATA_INT);
 
2216
        ut_a(dtype_get_prtype(type) & DATA_UNSIGNED);
 
2217
        ut_a(len == 4);
 
2218
 
 
2219
        tmp = mach_read_from_4(dfield_get_data(dfield));
 
2220
        *val = (ib_uint32_t) tmp;
 
2221
 
 
2222
        return(NULL);
 
2223
}
 
2224
 
 
2225
/***************************************************************
 
2226
Prints a row in a select result. */
 
2227
UNIV_INTERN
 
2228
que_thr_t*
 
2229
row_printf_step(
 
2230
/*============*/
 
2231
                                /* out: query thread to run next or NULL */
 
2232
        que_thr_t*      thr)    /* in: query thread */
 
2233
{
 
2234
        row_printf_node_t*      node;
 
2235
        sel_node_t*             sel_node;
 
2236
        que_node_t*             arg;
 
2237
 
 
2238
        ut_ad(thr);
 
2239
 
 
2240
        node = thr->run_node;
 
2241
 
 
2242
        sel_node = node->sel_node;
 
2243
 
 
2244
        ut_ad(que_node_get_type(node) == QUE_NODE_ROW_PRINTF);
 
2245
 
 
2246
        if (thr->prev_node == que_node_get_parent(node)) {
 
2247
 
 
2248
                /* Reset the cursor */
 
2249
                sel_node->state = SEL_NODE_OPEN;
 
2250
 
 
2251
                /* Fetch next row to print */
 
2252
 
 
2253
                thr->run_node = sel_node;
 
2254
 
 
2255
                return(thr);
 
2256
        }
 
2257
 
 
2258
        if (sel_node->state != SEL_NODE_FETCH) {
 
2259
 
 
2260
                ut_ad(sel_node->state == SEL_NODE_NO_MORE_ROWS);
 
2261
 
 
2262
                /* No more rows to print */
 
2263
 
 
2264
                thr->run_node = que_node_get_parent(node);
 
2265
 
 
2266
                return(thr);
 
2267
        }
 
2268
 
 
2269
        arg = sel_node->select_list;
 
2270
 
 
2271
        while (arg) {
 
2272
                dfield_print_also_hex(que_node_get_val(arg));
 
2273
 
 
2274
                fputs(" ::: ", stderr);
 
2275
 
 
2276
                arg = que_node_get_next(arg);
 
2277
        }
 
2278
 
 
2279
        putc('\n', stderr);
 
2280
 
 
2281
        /* Fetch next row to print */
 
2282
 
 
2283
        thr->run_node = sel_node;
 
2284
 
 
2285
        return(thr);
 
2286
}
 
2287
 
 
2288
/********************************************************************
 
2289
Converts a key value stored in MySQL format to an Innobase dtuple. The last
 
2290
field of the key value may be just a prefix of a fixed length field: hence
 
2291
the parameter key_len. But currently we do not allow search keys where the
 
2292
last field is only a prefix of the full key field len and print a warning if
 
2293
such appears. A counterpart of this function is
 
2294
ha_innobase::store_key_val_for_row() in ha_innodb.cc. */
 
2295
UNIV_INTERN
 
2296
void
 
2297
row_sel_convert_mysql_key_to_innobase(
 
2298
/*==================================*/
 
2299
        dtuple_t*       tuple,          /* in/out: tuple where to build;
 
2300
                                        NOTE: we assume that the type info
 
2301
                                        in the tuple is already according
 
2302
                                        to index! */
 
2303
        byte*           buf,            /* in: buffer to use in field
 
2304
                                        conversions */
 
2305
        ulint           buf_len,        /* in: buffer length */
 
2306
        dict_index_t*   index,          /* in: index of the key value */
 
2307
        const byte*     key_ptr,        /* in: MySQL key value */
 
2308
        ulint           key_len,        /* in: MySQL key value length */
 
2309
        trx_t*          trx)            /* in: transaction */
 
2310
{
 
2311
        byte*           original_buf    = buf;
 
2312
        const byte*     original_key_ptr = key_ptr;
 
2313
        dict_field_t*   field;
 
2314
        dfield_t*       dfield;
 
2315
        ulint           data_offset;
 
2316
        ulint           data_len;
 
2317
        ulint           data_field_len;
 
2318
        ibool           is_null;
 
2319
        const byte*     key_end;
 
2320
        ulint           n_fields = 0;
 
2321
 
 
2322
        /* For documentation of the key value storage format in MySQL, see
 
2323
        ha_innobase::store_key_val_for_row() in ha_innodb.cc. */
 
2324
 
 
2325
        key_end = key_ptr + key_len;
 
2326
 
 
2327
        /* Permit us to access any field in the tuple (ULINT_MAX): */
 
2328
 
 
2329
        dtuple_set_n_fields(tuple, ULINT_MAX);
 
2330
 
 
2331
        dfield = dtuple_get_nth_field(tuple, 0);
 
2332
        field = dict_index_get_nth_field(index, 0);
 
2333
 
 
2334
        if (UNIV_UNLIKELY(dfield_get_type(dfield)->mtype == DATA_SYS)) {
 
2335
                /* A special case: we are looking for a position in the
 
2336
                generated clustered index which InnoDB automatically added
 
2337
                to a table with no primary key: the first and the only
 
2338
                ordering column is ROW_ID which InnoDB stored to the key_ptr
 
2339
                buffer. */
 
2340
 
 
2341
                ut_a(key_len == DATA_ROW_ID_LEN);
 
2342
 
 
2343
                dfield_set_data(dfield, key_ptr, DATA_ROW_ID_LEN);
 
2344
 
 
2345
                dtuple_set_n_fields(tuple, 1);
 
2346
 
 
2347
                return;
 
2348
        }
 
2349
 
 
2350
        while (key_ptr < key_end) {
 
2351
 
 
2352
                ulint   type = dfield_get_type(dfield)->mtype;
 
2353
                ut_a(field->col->mtype == type);
 
2354
 
 
2355
                data_offset = 0;
 
2356
                is_null = FALSE;
 
2357
 
 
2358
                if (!(dfield_get_type(dfield)->prtype & DATA_NOT_NULL)) {
 
2359
                        /* The first byte in the field tells if this is
 
2360
                        an SQL NULL value */
 
2361
 
 
2362
                        data_offset = 1;
 
2363
 
 
2364
                        if (*key_ptr != 0) {
 
2365
                                dfield_set_null(dfield);
 
2366
 
 
2367
                                is_null = TRUE;
 
2368
                        }
 
2369
                }
 
2370
 
 
2371
                /* Calculate data length and data field total length */
 
2372
 
 
2373
                if (type == DATA_BLOB) {
 
2374
                        /* The key field is a column prefix of a BLOB or
 
2375
                        TEXT */
 
2376
 
 
2377
                        ut_a(field->prefix_len > 0);
 
2378
 
 
2379
                        /* MySQL stores the actual data length to the first 2
 
2380
                        bytes after the optional SQL NULL marker byte. The
 
2381
                        storage format is little-endian, that is, the most
 
2382
                        significant byte at a higher address. In UTF-8, MySQL
 
2383
                        seems to reserve field->prefix_len bytes for
 
2384
                        storing this field in the key value buffer, even
 
2385
                        though the actual value only takes data_len bytes
 
2386
                        from the start. */
 
2387
 
 
2388
                        data_len = key_ptr[data_offset]
 
2389
                                + 256 * key_ptr[data_offset + 1];
 
2390
                        data_field_len = data_offset + 2 + field->prefix_len;
 
2391
 
 
2392
                        data_offset += 2;
 
2393
 
 
2394
                        /* Now that we know the length, we store the column
 
2395
                        value like it would be a fixed char field */
 
2396
 
 
2397
                } else if (field->prefix_len > 0) {
 
2398
                        /* Looks like MySQL pads unused end bytes in the
 
2399
                        prefix with space. Therefore, also in UTF-8, it is ok
 
2400
                        to compare with a prefix containing full prefix_len
 
2401
                        bytes, and no need to take at most prefix_len / 3
 
2402
                        UTF-8 characters from the start.
 
2403
                        If the prefix is used as the upper end of a LIKE
 
2404
                        'abc%' query, then MySQL pads the end with chars
 
2405
                        0xff. TODO: in that case does it any harm to compare
 
2406
                        with the full prefix_len bytes. How do characters
 
2407
                        0xff in UTF-8 behave? */
 
2408
 
 
2409
                        data_len = field->prefix_len;
 
2410
                        data_field_len = data_offset + data_len;
 
2411
                } else {
 
2412
                        data_len = dfield_get_type(dfield)->len;
 
2413
                        data_field_len = data_offset + data_len;
 
2414
                }
 
2415
 
 
2416
                if (UNIV_UNLIKELY
 
2417
                    (dtype_get_mysql_type(dfield_get_type(dfield))
 
2418
                     == DATA_MYSQL_TRUE_VARCHAR)
 
2419
                    && UNIV_LIKELY(type != DATA_INT)) {
 
2420
                        /* In a MySQL key value format, a true VARCHAR is
 
2421
                        always preceded by 2 bytes of a length field.
 
2422
                        dfield_get_type(dfield)->len returns the maximum
 
2423
                        'payload' len in bytes. That does not include the
 
2424
                        2 bytes that tell the actual data length.
 
2425
 
 
2426
                        We added the check != DATA_INT to make sure we do
 
2427
                        not treat MySQL ENUM or SET as a true VARCHAR! */
 
2428
 
 
2429
                        data_len += 2;
 
2430
                        data_field_len += 2;
 
2431
                }
 
2432
 
 
2433
                /* Storing may use at most data_len bytes of buf */
 
2434
 
 
2435
                if (UNIV_LIKELY(!is_null)) {
 
2436
                        row_mysql_store_col_in_innobase_format(
 
2437
                                dfield, buf,
 
2438
                                FALSE, /* MySQL key value format col */
 
2439
                                key_ptr + data_offset, data_len,
 
2440
                                dict_table_is_comp(index->table));
 
2441
                        buf += data_len;
 
2442
                }
 
2443
 
 
2444
                key_ptr += data_field_len;
 
2445
 
 
2446
                if (UNIV_UNLIKELY(key_ptr > key_end)) {
 
2447
                        /* The last field in key was not a complete key field
 
2448
                        but a prefix of it.
 
2449
 
 
2450
                        Print a warning about this! HA_READ_PREFIX_LAST does
 
2451
                        not currently work in InnoDB with partial-field key
 
2452
                        value prefixes. Since MySQL currently uses a padding
 
2453
                        trick to calculate LIKE 'abc%' type queries there
 
2454
                        should never be partial-field prefixes in searches. */
 
2455
 
 
2456
                        ut_print_timestamp(stderr);
 
2457
 
 
2458
                        fputs("  InnoDB: Warning: using a partial-field"
 
2459
                              " key prefix in search.\n"
 
2460
                              "InnoDB: ", stderr);
 
2461
                        dict_index_name_print(stderr, trx, index);
 
2462
                        fprintf(stderr, ". Last data field length %lu bytes,\n"
 
2463
                                "InnoDB: key ptr now exceeds"
 
2464
                                " key end by %lu bytes.\n"
 
2465
                                "InnoDB: Key value in the MySQL format:\n",
 
2466
                                (ulong) data_field_len,
 
2467
                                (ulong) (key_ptr - key_end));
 
2468
                        fflush(stderr);
 
2469
                        ut_print_buf(stderr, original_key_ptr, key_len);
 
2470
                        fprintf(stderr, "\n");
 
2471
 
 
2472
                        if (!is_null) {
 
2473
                                ulint   len = dfield_get_len(dfield);
 
2474
                                dfield_set_len(dfield, len
 
2475
                                               - (ulint) (key_ptr - key_end));
 
2476
                        }
 
2477
                }
 
2478
 
 
2479
                n_fields++;
 
2480
                field++;
 
2481
                dfield++;
 
2482
        }
 
2483
 
 
2484
        ut_a(buf <= original_buf + buf_len);
 
2485
 
 
2486
        /* We set the length of tuple to n_fields: we assume that the memory
 
2487
        area allocated for it is big enough (usually bigger than n_fields). */
 
2488
 
 
2489
        dtuple_set_n_fields(tuple, n_fields);
 
2490
}
 
2491
 
 
2492
/******************************************************************
 
2493
Stores the row id to the prebuilt struct. */
 
2494
static
 
2495
void
 
2496
row_sel_store_row_id_to_prebuilt(
 
2497
/*=============================*/
 
2498
        row_prebuilt_t*         prebuilt,       /* in/out: prebuilt */
 
2499
        const rec_t*            index_rec,      /* in: record */
 
2500
        const dict_index_t*     index,          /* in: index of the record */
 
2501
        const ulint*            offsets)        /* in: rec_get_offsets
 
2502
                                                (index_rec, index) */
 
2503
{
 
2504
        const byte*     data;
 
2505
        ulint           len;
 
2506
 
 
2507
        ut_ad(rec_offs_validate(index_rec, index, offsets));
 
2508
 
 
2509
        data = rec_get_nth_field(
 
2510
                index_rec, offsets,
 
2511
                dict_index_get_sys_col_pos(index, DATA_ROW_ID), &len);
 
2512
 
 
2513
        if (UNIV_UNLIKELY(len != DATA_ROW_ID_LEN)) {
 
2514
                fprintf(stderr,
 
2515
                        "InnoDB: Error: Row id field is"
 
2516
                        " wrong length %lu in ", (ulong) len);
 
2517
                dict_index_name_print(stderr, prebuilt->trx, index);
 
2518
                fprintf(stderr, "\n"
 
2519
                        "InnoDB: Field number %lu, record:\n",
 
2520
                        (ulong) dict_index_get_sys_col_pos(index,
 
2521
                                                           DATA_ROW_ID));
 
2522
                rec_print_new(stderr, index_rec, offsets);
 
2523
                putc('\n', stderr);
 
2524
                ut_error;
 
2525
        }
 
2526
 
 
2527
        ut_memcpy(prebuilt->row_id, data, len);
 
2528
}
 
2529
 
 
2530
/******************************************************************
 
2531
Stores a non-SQL-NULL field in the MySQL format. The counterpart of this
 
2532
function is row_mysql_store_col_in_innobase_format() in row0mysql.c. */
 
2533
static
 
2534
void
 
2535
row_sel_field_store_in_mysql_format(
 
2536
/*================================*/
 
2537
        byte*           dest,   /* in/out: buffer where to store; NOTE
 
2538
                                that BLOBs are not in themselves
 
2539
                                stored here: the caller must allocate
 
2540
                                and copy the BLOB into buffer before,
 
2541
                                and pass the pointer to the BLOB in
 
2542
                                'data' */
 
2543
        const mysql_row_templ_t* templ,
 
2544
                                /* in: MySQL column template.
 
2545
                                Its following fields are referenced:
 
2546
                                type, is_unsigned, mysql_col_len,
 
2547
                                mbminlen, mbmaxlen */
 
2548
        const byte*     data,   /* in: data to store */
 
2549
        ulint           len)    /* in: length of the data */
 
2550
{
 
2551
        byte*   ptr;
 
2552
        byte*   field_end;
 
2553
        byte*   pad_ptr;
 
2554
 
 
2555
        ut_ad(len != UNIV_SQL_NULL);
 
2556
 
 
2557
        switch (templ->type) {
 
2558
        case DATA_INT:
 
2559
                /* Convert integer data from Innobase to a little-endian
 
2560
                format, sign bit restored to normal */
 
2561
 
 
2562
                ptr = dest + len;
 
2563
 
 
2564
                for (;;) {
 
2565
                        ptr--;
 
2566
                        *ptr = *data;
 
2567
                        if (ptr == dest) {
 
2568
                                break;
 
2569
                        }
 
2570
                        data++;
 
2571
                }
 
2572
 
 
2573
                if (!templ->is_unsigned) {
 
2574
                        dest[len - 1] = (byte) (dest[len - 1] ^ 128);
 
2575
                }
 
2576
 
 
2577
                ut_ad(templ->mysql_col_len == len);
 
2578
                break;
 
2579
 
 
2580
        case DATA_VARCHAR:
 
2581
        case DATA_VARMYSQL:
 
2582
        case DATA_BINARY:
 
2583
                field_end = dest + templ->mysql_col_len;
 
2584
 
 
2585
                if (templ->mysql_type == DATA_MYSQL_TRUE_VARCHAR) {
 
2586
                        /* This is a >= 5.0.3 type true VARCHAR. Store the
 
2587
                        length of the data to the first byte or the first
 
2588
                        two bytes of dest. */
 
2589
 
 
2590
                        dest = row_mysql_store_true_var_len(
 
2591
                                dest, len, templ->mysql_length_bytes);
 
2592
                }
 
2593
 
 
2594
                /* Copy the actual data */
 
2595
                ut_memcpy(dest, data, len);
 
2596
 
 
2597
                /* Pad with trailing spaces. We pad with spaces also the
 
2598
                unused end of a >= 5.0.3 true VARCHAR column, just in case
 
2599
                MySQL expects its contents to be deterministic. */
 
2600
 
 
2601
                pad_ptr = dest + len;
 
2602
 
 
2603
                ut_ad(templ->mbminlen <= templ->mbmaxlen);
 
2604
 
 
2605
                /* We handle UCS2 charset strings differently. */
 
2606
                if (templ->mbminlen == 2) {
 
2607
                        /* A space char is two bytes, 0x0020 in UCS2 */
 
2608
 
 
2609
                        if (len & 1) {
 
2610
                                /* A 0x20 has been stripped from the column.
 
2611
                                Pad it back. */
 
2612
 
 
2613
                                if (pad_ptr < field_end) {
 
2614
                                        *pad_ptr = 0x20;
 
2615
                                        pad_ptr++;
 
2616
                                }
 
2617
                        }
 
2618
 
 
2619
                        /* Pad the rest of the string with 0x0020 */
 
2620
 
 
2621
                        while (pad_ptr < field_end) {
 
2622
                                *pad_ptr = 0x00;
 
2623
                                pad_ptr++;
 
2624
                                *pad_ptr = 0x20;
 
2625
                                pad_ptr++;
 
2626
                        }
 
2627
                } else {
 
2628
                        ut_ad(templ->mbminlen == 1);
 
2629
                        /* space=0x20 */
 
2630
 
 
2631
                        memset(pad_ptr, 0x20, field_end - pad_ptr);
 
2632
                }
 
2633
                break;
 
2634
 
 
2635
        case DATA_BLOB:
 
2636
                /* Store a pointer to the BLOB buffer to dest: the BLOB was
 
2637
                already copied to the buffer in row_sel_store_mysql_rec */
 
2638
 
 
2639
                row_mysql_store_blob_ref(dest, templ->mysql_col_len, data,
 
2640
                                         len);
 
2641
                break;
 
2642
 
 
2643
        case DATA_MYSQL:
 
2644
                memcpy(dest, data, len);
 
2645
 
 
2646
                ut_ad(templ->mysql_col_len >= len);
 
2647
                ut_ad(templ->mbmaxlen >= templ->mbminlen);
 
2648
 
 
2649
                ut_ad(templ->mbmaxlen > templ->mbminlen
 
2650
                      || templ->mysql_col_len == len);
 
2651
                /* The following assertion would fail for old tables
 
2652
                containing UTF-8 ENUM columns due to Bug #9526. */
 
2653
                ut_ad(!templ->mbmaxlen
 
2654
                      || !(templ->mysql_col_len % templ->mbmaxlen));
 
2655
                ut_ad(len * templ->mbmaxlen >= templ->mysql_col_len);
 
2656
 
 
2657
                if (templ->mbminlen != templ->mbmaxlen) {
 
2658
                        /* Pad with spaces. This undoes the stripping
 
2659
                        done in row0mysql.ic, function
 
2660
                        row_mysql_store_col_in_innobase_format(). */
 
2661
 
 
2662
                        memset(dest + len, 0x20, templ->mysql_col_len - len);
 
2663
                }
 
2664
                break;
 
2665
 
 
2666
        default:
 
2667
#ifdef UNIV_DEBUG
 
2668
        case DATA_SYS_CHILD:
 
2669
        case DATA_SYS:
 
2670
                /* These column types should never be shipped to MySQL. */
 
2671
                ut_ad(0);
 
2672
 
 
2673
        case DATA_CHAR:
 
2674
        case DATA_FIXBINARY:
 
2675
        case DATA_FLOAT:
 
2676
        case DATA_DOUBLE:
 
2677
        case DATA_DECIMAL:
 
2678
                /* Above are the valid column types for MySQL data. */
 
2679
#endif /* UNIV_DEBUG */
 
2680
                ut_ad(templ->mysql_col_len == len);
 
2681
                memcpy(dest, data, len);
 
2682
        }
 
2683
}
 
2684
 
 
2685
/******************************************************************
 
2686
Convert a row in the Innobase format to a row in the MySQL format.
 
2687
Note that the template in prebuilt may advise us to copy only a few
 
2688
columns to mysql_rec, other columns are left blank. All columns may not
 
2689
be needed in the query. */
 
2690
static
 
2691
ibool
 
2692
row_sel_store_mysql_rec(
 
2693
/*====================*/
 
2694
                                        /* out: TRUE if success, FALSE if
 
2695
                                        could not allocate memory for a BLOB
 
2696
                                        (though we may also assert in that
 
2697
                                        case) */
 
2698
        byte*           mysql_rec,      /* out: row in the MySQL format */
 
2699
        row_prebuilt_t* prebuilt,       /* in: prebuilt struct */
 
2700
        const rec_t*    rec,            /* in: Innobase record in the index
 
2701
                                        which was described in prebuilt's
 
2702
                                        template; must be protected by
 
2703
                                        a page latch */
 
2704
        const ulint*    offsets,        /* in: array returned by
 
2705
                                        rec_get_offsets() */
 
2706
        ulint start_field_no,
 
2707
        ulint end_field_no)
 
2708
{
 
2709
        mysql_row_templ_t*      templ;
 
2710
        mem_heap_t*             extern_field_heap       = NULL;
 
2711
        mem_heap_t*             heap;
 
2712
        const byte*             data;
 
2713
        ulint                   len;
 
2714
        ulint                   i;
 
2715
 
 
2716
        ut_ad(prebuilt->mysql_template);
 
2717
        ut_ad(rec_offs_validate(rec, NULL, offsets));
 
2718
 
 
2719
        if (UNIV_LIKELY_NULL(prebuilt->blob_heap)) {
 
2720
                mem_heap_free(prebuilt->blob_heap);
 
2721
                prebuilt->blob_heap = NULL;
 
2722
        }
 
2723
 
 
2724
        for (i = start_field_no; i < end_field_no /* prebuilt->n_template */; i++) {
 
2725
 
 
2726
                templ = prebuilt->mysql_template + i;
 
2727
 
 
2728
                if (UNIV_UNLIKELY(rec_offs_nth_extern(offsets,
 
2729
                                                      templ->rec_field_no))) {
 
2730
 
 
2731
                        /* Copy an externally stored field to the temporary
 
2732
                        heap */
 
2733
 
 
2734
                        ut_a(!prebuilt->trx->has_search_latch);
 
2735
 
 
2736
                        if (UNIV_UNLIKELY(templ->type == DATA_BLOB)) {
 
2737
                                if (prebuilt->blob_heap == NULL) {
 
2738
                                        prebuilt->blob_heap = mem_heap_create(
 
2739
                                                UNIV_PAGE_SIZE);
 
2740
                                }
 
2741
 
 
2742
                                heap = prebuilt->blob_heap;
 
2743
                        } else {
 
2744
                                extern_field_heap
 
2745
                                        = mem_heap_create(UNIV_PAGE_SIZE);
 
2746
 
 
2747
                                heap = extern_field_heap;
 
2748
                        }
 
2749
 
 
2750
                        /* NOTE: if we are retrieving a big BLOB, we may
 
2751
                        already run out of memory in the next call, which
 
2752
                        causes an assert */
 
2753
 
 
2754
                        data = btr_rec_copy_externally_stored_field(
 
2755
                                rec, offsets,
 
2756
                                dict_table_zip_size(prebuilt->table),
 
2757
                                templ->rec_field_no, &len, heap);
 
2758
 
 
2759
                        ut_a(len != UNIV_SQL_NULL);
 
2760
                } else {
 
2761
                        /* Field is stored in the row. */
 
2762
 
 
2763
                        data = rec_get_nth_field(rec, offsets,
 
2764
                                                 templ->rec_field_no, &len);
 
2765
 
 
2766
                        if (UNIV_UNLIKELY(templ->type == DATA_BLOB)
 
2767
                            && len != UNIV_SQL_NULL) {
 
2768
 
 
2769
                                /* It is a BLOB field locally stored in the
 
2770
                                InnoDB record: we MUST copy its contents to
 
2771
                                prebuilt->blob_heap here because later code
 
2772
                                assumes all BLOB values have been copied to a
 
2773
                                safe place. */
 
2774
 
 
2775
                                if (prebuilt->blob_heap == NULL) {
 
2776
                                        prebuilt->blob_heap = mem_heap_create(
 
2777
                                                UNIV_PAGE_SIZE);
 
2778
                                }
 
2779
 
 
2780
                                data = memcpy(mem_heap_alloc(
 
2781
                                                prebuilt->blob_heap, len),
 
2782
                                                data, len);
 
2783
                        }
 
2784
                }
 
2785
 
 
2786
                if (len != UNIV_SQL_NULL) {
 
2787
                        row_sel_field_store_in_mysql_format(
 
2788
                                mysql_rec + templ->mysql_col_offset,
 
2789
                                templ, data, len);
 
2790
 
 
2791
                        /* Cleanup */
 
2792
                        if (extern_field_heap) {
 
2793
                                mem_heap_free(extern_field_heap);
 
2794
                                extern_field_heap = NULL;
 
2795
                        }
 
2796
 
 
2797
                        if (templ->mysql_null_bit_mask) {
 
2798
                                /* It is a nullable column with a non-NULL
 
2799
                                value */
 
2800
                                mysql_rec[templ->mysql_null_byte_offset]
 
2801
                                        &= ~(byte) templ->mysql_null_bit_mask;
 
2802
                        }
 
2803
                } else {
 
2804
                        /* MySQL seems to assume the field for an SQL NULL
 
2805
                        value is set to zero or space. Not taking this into
 
2806
                        account caused seg faults with NULL BLOB fields, and
 
2807
                        bug number 154 in the MySQL bug database: GROUP BY
 
2808
                        and DISTINCT could treat NULL values inequal. */
 
2809
                        int     pad_char;
 
2810
 
 
2811
                        mysql_rec[templ->mysql_null_byte_offset]
 
2812
                                |= (byte) templ->mysql_null_bit_mask;
 
2813
                        switch (templ->type) {
 
2814
                        case DATA_VARCHAR:
 
2815
                        case DATA_BINARY:
 
2816
                        case DATA_VARMYSQL:
 
2817
                                if (templ->mysql_type
 
2818
                                    == DATA_MYSQL_TRUE_VARCHAR) {
 
2819
                                        /* This is a >= 5.0.3 type
 
2820
                                        true VARCHAR.  Zero the field. */
 
2821
                                        pad_char = 0x00;
 
2822
                                        break;
 
2823
                                }
 
2824
                                /* Fall through */
 
2825
                        case DATA_CHAR:
 
2826
                        case DATA_FIXBINARY:
 
2827
                        case DATA_MYSQL:
 
2828
                                /* MySQL pads all string types (except
 
2829
                                BLOB, TEXT and true VARCHAR) with space. */
 
2830
                                if (UNIV_UNLIKELY(templ->mbminlen == 2)) {
 
2831
                                        /* Treat UCS2 as a special case. */
 
2832
                                        byte* d = mysql_rec
 
2833
                                                + templ->mysql_col_offset;
 
2834
                                        len = templ->mysql_col_len;
 
2835
                                        /* There are two UCS2 bytes per char,
 
2836
                                        so the length has to be even. */
 
2837
                                        ut_a(!(len & 1));
 
2838
                                        /* Pad with 0x0020. */
 
2839
                                        while (len) {
 
2840
                                                *d++ = 0x00;
 
2841
                                                *d++ = 0x20;
 
2842
                                                len -= 2;
 
2843
                                        }
 
2844
                                        continue;
 
2845
                                }
 
2846
                                pad_char = 0x20;
 
2847
                                break;
 
2848
                        default:
 
2849
                                pad_char = 0x00;
 
2850
                                break;
 
2851
                        }
 
2852
 
 
2853
                        ut_ad(!pad_char || templ->mbminlen == 1);
 
2854
                        memset(mysql_rec + templ->mysql_col_offset,
 
2855
                               pad_char, templ->mysql_col_len);
 
2856
                }
 
2857
        }
 
2858
 
 
2859
        return(TRUE);
 
2860
}
 
2861
 
 
2862
/*************************************************************************
 
2863
Builds a previous version of a clustered index record for a consistent read */
 
2864
static
 
2865
ulint
 
2866
row_sel_build_prev_vers_for_mysql(
 
2867
/*==============================*/
 
2868
                                        /* out: DB_SUCCESS or error code */
 
2869
        read_view_t*    read_view,      /* in: read view */
 
2870
        dict_index_t*   clust_index,    /* in: clustered index */
 
2871
        row_prebuilt_t* prebuilt,       /* in: prebuilt struct */
 
2872
        const rec_t*    rec,            /* in: record in a clustered index */
 
2873
        ulint**         offsets,        /* in/out: offsets returned by
 
2874
                                        rec_get_offsets(rec, clust_index) */
 
2875
        mem_heap_t**    offset_heap,    /* in/out: memory heap from which
 
2876
                                        the offsets are allocated */
 
2877
        rec_t**         old_vers,       /* out: old version, or NULL if the
 
2878
                                        record does not exist in the view:
 
2879
                                        i.e., it was freshly inserted
 
2880
                                        afterwards */
 
2881
        mtr_t*          mtr)            /* in: mtr */
 
2882
{
 
2883
        ulint   err;
 
2884
 
 
2885
        if (prebuilt->old_vers_heap) {
 
2886
                mem_heap_empty(prebuilt->old_vers_heap);
 
2887
        } else {
 
2888
                prebuilt->old_vers_heap = mem_heap_create(200);
 
2889
        }
 
2890
 
 
2891
        err = row_vers_build_for_consistent_read(
 
2892
                rec, mtr, clust_index, offsets, read_view, offset_heap,
 
2893
                prebuilt->old_vers_heap, old_vers);
 
2894
        return(err);
 
2895
}
 
2896
 
 
2897
/*************************************************************************
 
2898
Retrieves the clustered index record corresponding to a record in a
 
2899
non-clustered index. Does the necessary locking. Used in the MySQL
 
2900
interface. */
 
2901
static
 
2902
ulint
 
2903
row_sel_get_clust_rec_for_mysql(
 
2904
/*============================*/
 
2905
                                /* out: DB_SUCCESS or error code */
 
2906
        row_prebuilt_t* prebuilt,/* in: prebuilt struct in the handle */
 
2907
        dict_index_t*   sec_index,/* in: secondary index where rec resides */
 
2908
        const rec_t*    rec,    /* in: record in a non-clustered index; if
 
2909
                                this is a locking read, then rec is not
 
2910
                                allowed to be delete-marked, and that would
 
2911
                                not make sense either */
 
2912
        que_thr_t*      thr,    /* in: query thread */
 
2913
        const rec_t**   out_rec,/* out: clustered record or an old version of
 
2914
                                it, NULL if the old version did not exist
 
2915
                                in the read view, i.e., it was a fresh
 
2916
                                inserted version */
 
2917
        ulint**         offsets,/* in: offsets returned by
 
2918
                                rec_get_offsets(rec, sec_index);
 
2919
                                out: offsets returned by
 
2920
                                rec_get_offsets(out_rec, clust_index) */
 
2921
        mem_heap_t**    offset_heap,/* in/out: memory heap from which
 
2922
                                the offsets are allocated */
 
2923
        mtr_t*          mtr)    /* in: mtr used to get access to the
 
2924
                                non-clustered record; the same mtr is used to
 
2925
                                access the clustered index */
 
2926
{
 
2927
        dict_index_t*   clust_index;
 
2928
        const rec_t*    clust_rec;
 
2929
        rec_t*          old_vers;
 
2930
        ulint           err;
 
2931
        trx_t*          trx;
 
2932
 
 
2933
        *out_rec = NULL;
 
2934
        trx = thr_get_trx(thr);
 
2935
 
 
2936
        row_build_row_ref_in_tuple(prebuilt->clust_ref, rec,
 
2937
                                   sec_index, *offsets, trx);
 
2938
 
 
2939
        clust_index = dict_table_get_first_index(sec_index->table);
 
2940
 
 
2941
        btr_pcur_open_with_no_init(clust_index, prebuilt->clust_ref,
 
2942
                                   PAGE_CUR_LE, BTR_SEARCH_LEAF,
 
2943
                                   prebuilt->clust_pcur, 0, mtr);
 
2944
 
 
2945
        clust_rec = btr_pcur_get_rec(prebuilt->clust_pcur);
 
2946
 
 
2947
        prebuilt->clust_pcur->trx_if_known = trx;
 
2948
 
 
2949
        /* Note: only if the search ends up on a non-infimum record is the
 
2950
        low_match value the real match to the search tuple */
 
2951
 
 
2952
        if (!page_rec_is_user_rec(clust_rec)
 
2953
            || btr_pcur_get_low_match(prebuilt->clust_pcur)
 
2954
            < dict_index_get_n_unique(clust_index)) {
 
2955
 
 
2956
                /* In a rare case it is possible that no clust rec is found
 
2957
                for a delete-marked secondary index record: if in row0umod.c
 
2958
                in row_undo_mod_remove_clust_low() we have already removed
 
2959
                the clust rec, while purge is still cleaning and removing
 
2960
                secondary index records associated with earlier versions of
 
2961
                the clustered index record. In that case we know that the
 
2962
                clustered index record did not exist in the read view of
 
2963
                trx. */
 
2964
 
 
2965
                if (!rec_get_deleted_flag(rec,
 
2966
                                          dict_table_is_comp(sec_index->table))
 
2967
                    || prebuilt->select_lock_type != LOCK_NONE) {
 
2968
                        ut_print_timestamp(stderr);
 
2969
                        fputs("  InnoDB: error clustered record"
 
2970
                              " for sec rec not found\n"
 
2971
                              "InnoDB: ", stderr);
 
2972
                        dict_index_name_print(stderr, trx, sec_index);
 
2973
                        fputs("\n"
 
2974
                              "InnoDB: sec index record ", stderr);
 
2975
                        rec_print(stderr, rec, sec_index);
 
2976
                        fputs("\n"
 
2977
                              "InnoDB: clust index record ", stderr);
 
2978
                        rec_print(stderr, clust_rec, clust_index);
 
2979
                        putc('\n', stderr);
 
2980
                        trx_print(stderr, trx, 600);
 
2981
 
 
2982
                        fputs("\n"
 
2983
                              "InnoDB: Submit a detailed bug report"
 
2984
                              " to http://bugs.mysql.com\n", stderr);
 
2985
                }
 
2986
 
 
2987
                clust_rec = NULL;
 
2988
 
 
2989
                goto func_exit;
 
2990
        }
 
2991
 
 
2992
        *offsets = rec_get_offsets(clust_rec, clust_index, *offsets,
 
2993
                                   ULINT_UNDEFINED, offset_heap);
 
2994
 
 
2995
        if (prebuilt->select_lock_type != LOCK_NONE) {
 
2996
                /* Try to place a lock on the index record; we are searching
 
2997
                the clust rec with a unique condition, hence
 
2998
                we set a LOCK_REC_NOT_GAP type lock */
 
2999
 
 
3000
                err = lock_clust_rec_read_check_and_lock(
 
3001
                        0, btr_pcur_get_block(prebuilt->clust_pcur),
 
3002
                        clust_rec, clust_index, *offsets,
 
3003
                        prebuilt->select_lock_type, LOCK_REC_NOT_GAP, thr);
 
3004
                if (err != DB_SUCCESS) {
 
3005
 
 
3006
                        goto err_exit;
 
3007
                }
 
3008
        } else {
 
3009
                /* This is a non-locking consistent read: if necessary, fetch
 
3010
                a previous version of the record */
 
3011
 
 
3012
                old_vers = NULL;
 
3013
 
 
3014
                /* If the isolation level allows reading of uncommitted data,
 
3015
                then we never look for an earlier version */
 
3016
 
 
3017
                if (trx->isolation_level > TRX_ISO_READ_UNCOMMITTED
 
3018
                    && !lock_clust_rec_cons_read_sees(
 
3019
                            clust_rec, clust_index, *offsets,
 
3020
                            trx->read_view)) {
 
3021
 
 
3022
                        /* The following call returns 'offsets' associated with
 
3023
                        'old_vers' */
 
3024
                        err = row_sel_build_prev_vers_for_mysql(
 
3025
                                trx->read_view, clust_index, prebuilt,
 
3026
                                clust_rec, offsets, offset_heap, &old_vers,
 
3027
                                mtr);
 
3028
 
 
3029
                        if (err != DB_SUCCESS || old_vers == NULL) {
 
3030
 
 
3031
                                goto err_exit;
 
3032
                        }
 
3033
 
 
3034
                        clust_rec = old_vers;
 
3035
                }
 
3036
 
 
3037
                /* If we had to go to an earlier version of row or the
 
3038
                secondary index record is delete marked, then it may be that
 
3039
                the secondary index record corresponding to clust_rec
 
3040
                (or old_vers) is not rec; in that case we must ignore
 
3041
                such row because in our snapshot rec would not have existed.
 
3042
                Remember that from rec we cannot see directly which transaction
 
3043
                id corresponds to it: we have to go to the clustered index
 
3044
                record. A query where we want to fetch all rows where
 
3045
                the secondary index value is in some interval would return
 
3046
                a wrong result if we would not drop rows which we come to
 
3047
                visit through secondary index records that would not really
 
3048
                exist in our snapshot. */
 
3049
 
 
3050
                if (clust_rec
 
3051
                    && (old_vers
 
3052
                        || rec_get_deleted_flag(rec, dict_table_is_comp(
 
3053
                                                        sec_index->table)))
 
3054
                    && !row_sel_sec_rec_is_for_clust_rec(
 
3055
                            rec, sec_index, clust_rec, clust_index)) {
 
3056
                        clust_rec = NULL;
 
3057
#ifdef UNIV_SEARCH_DEBUG
 
3058
                } else {
 
3059
                        ut_a(clust_rec == NULL
 
3060
                             || row_sel_sec_rec_is_for_clust_rec(
 
3061
                                     rec, sec_index, clust_rec, clust_index));
 
3062
#endif
 
3063
                }
 
3064
        }
 
3065
 
 
3066
func_exit:
 
3067
        *out_rec = clust_rec;
 
3068
 
 
3069
        if (prebuilt->select_lock_type == LOCK_X) {
 
3070
                /* We may use the cursor in update: store its position */
 
3071
 
 
3072
                btr_pcur_store_position(prebuilt->clust_pcur, mtr);
 
3073
        }
 
3074
 
 
3075
        err = DB_SUCCESS;
 
3076
err_exit:
 
3077
        return(err);
 
3078
}
 
3079
 
 
3080
/************************************************************************
 
3081
Restores cursor position after it has been stored. We have to take into
 
3082
account that the record cursor was positioned on may have been deleted.
 
3083
Then we may have to move the cursor one step up or down. */
 
3084
static
 
3085
ibool
 
3086
sel_restore_position_for_mysql(
 
3087
/*===========================*/
 
3088
                                        /* out: TRUE if we may need to
 
3089
                                        process the record the cursor is
 
3090
                                        now positioned on (i.e. we should
 
3091
                                        not go to the next record yet) */
 
3092
        ibool*          same_user_rec,  /* out: TRUE if we were able to restore
 
3093
                                        the cursor on a user record with the
 
3094
                                        same ordering prefix in in the
 
3095
                                        B-tree index */
 
3096
        ulint           latch_mode,     /* in: latch mode wished in
 
3097
                                        restoration */
 
3098
        btr_pcur_t*     pcur,           /* in: cursor whose position
 
3099
                                        has been stored */
 
3100
        ibool           moves_up,       /* in: TRUE if the cursor moves up
 
3101
                                        in the index */
 
3102
        mtr_t*          mtr)            /* in: mtr; CAUTION: may commit
 
3103
                                        mtr temporarily! */
 
3104
{
 
3105
        ibool   success;
 
3106
        ulint   relative_position;
 
3107
 
 
3108
        relative_position = pcur->rel_pos;
 
3109
 
 
3110
        success = btr_pcur_restore_position(latch_mode, pcur, mtr);
 
3111
 
 
3112
        *same_user_rec = success;
 
3113
 
 
3114
        if (relative_position == BTR_PCUR_ON) {
 
3115
                if (success) {
 
3116
                        return(FALSE);
 
3117
                }
 
3118
 
 
3119
                if (moves_up) {
 
3120
                        btr_pcur_move_to_next(pcur, mtr);
 
3121
                }
 
3122
 
 
3123
                return(TRUE);
 
3124
        }
 
3125
 
 
3126
        if (relative_position == BTR_PCUR_AFTER
 
3127
            || relative_position == BTR_PCUR_AFTER_LAST_IN_TREE) {
 
3128
 
 
3129
                if (moves_up) {
 
3130
                        return(TRUE);
 
3131
                }
 
3132
 
 
3133
                if (btr_pcur_is_on_user_rec(pcur)) {
 
3134
                        btr_pcur_move_to_prev(pcur, mtr);
 
3135
                }
 
3136
 
 
3137
                return(TRUE);
 
3138
        }
 
3139
 
 
3140
        ut_ad(relative_position == BTR_PCUR_BEFORE
 
3141
              || relative_position == BTR_PCUR_BEFORE_FIRST_IN_TREE);
 
3142
 
 
3143
        if (moves_up && btr_pcur_is_on_user_rec(pcur)) {
 
3144
                btr_pcur_move_to_next(pcur, mtr);
 
3145
        }
 
3146
 
 
3147
        return(TRUE);
 
3148
}
 
3149
 
 
3150
/************************************************************************
 
3151
Pops a cached row for MySQL from the fetch cache. */
 
3152
UNIV_INLINE
 
3153
void
 
3154
row_sel_pop_cached_row_for_mysql(
 
3155
/*=============================*/
 
3156
        byte*           buf,            /* in/out: buffer where to copy the
 
3157
                                        row */
 
3158
        row_prebuilt_t* prebuilt)       /* in: prebuilt struct */
 
3159
{
 
3160
        ulint                   i;
 
3161
        mysql_row_templ_t*      templ;
 
3162
        byte*                   cached_rec;
 
3163
        ut_ad(prebuilt->n_fetch_cached > 0);
 
3164
        ut_ad(prebuilt->mysql_prefix_len <= prebuilt->mysql_row_len);
 
3165
 
 
3166
        if (UNIV_UNLIKELY(prebuilt->keep_other_fields_on_keyread)) {
 
3167
                /* Copy cache record field by field, don't touch fields that
 
3168
                are not covered by current key */
 
3169
                cached_rec = prebuilt->fetch_cache[
 
3170
                        prebuilt->fetch_cache_first];
 
3171
 
 
3172
                for (i = 0; i < prebuilt->n_template; i++) {
 
3173
                        templ = prebuilt->mysql_template + i;
 
3174
                        ut_memcpy(buf + templ->mysql_col_offset,
 
3175
                                  cached_rec + templ->mysql_col_offset,
 
3176
                                  templ->mysql_col_len);
 
3177
                        /* Copy NULL bit of the current field from cached_rec
 
3178
                        to buf */
 
3179
                        if (templ->mysql_null_bit_mask) {
 
3180
                                buf[templ->mysql_null_byte_offset]
 
3181
                                        ^= (buf[templ->mysql_null_byte_offset]
 
3182
                                            ^ cached_rec[templ->mysql_null_byte_offset])
 
3183
                                        & (byte)templ->mysql_null_bit_mask;
 
3184
                        }
 
3185
                }
 
3186
        }
 
3187
        else {
 
3188
                ut_memcpy(buf,
 
3189
                          prebuilt->fetch_cache[prebuilt->fetch_cache_first],
 
3190
                          prebuilt->mysql_prefix_len);
 
3191
        }
 
3192
        prebuilt->n_fetch_cached--;
 
3193
        prebuilt->fetch_cache_first++;
 
3194
 
 
3195
        if (prebuilt->n_fetch_cached == 0) {
 
3196
                prebuilt->fetch_cache_first = 0;
 
3197
        }
 
3198
}
 
3199
 
 
3200
/************************************************************************
 
3201
Pushes a row for MySQL to the fetch cache. */
 
3202
UNIV_INLINE
 
3203
void
 
3204
row_sel_push_cache_row_for_mysql(
 
3205
/*=============================*/
 
3206
        row_prebuilt_t* prebuilt,       /* in: prebuilt struct */
 
3207
        const rec_t*    rec,            /* in: record to push; must
 
3208
                                        be protected by a page latch */
 
3209
        const ulint*    offsets,        /* in: rec_get_offsets() */
 
3210
        ulint           start_field_no, /* psergy: start from this field */
 
3211
        byte*           remainder_buf)  /* if above !=0 -> where to take
 
3212
                                           prev fields */
 
3213
{
 
3214
        byte*   buf;
 
3215
        ulint   i;
 
3216
 
 
3217
        ut_ad(prebuilt->n_fetch_cached < MYSQL_FETCH_CACHE_SIZE);
 
3218
        ut_ad(rec_offs_validate(rec, NULL, offsets));
 
3219
        ut_a(!prebuilt->templ_contains_blob);
 
3220
 
 
3221
        if (prebuilt->fetch_cache[0] == NULL) {
 
3222
                /* Allocate memory for the fetch cache */
 
3223
 
 
3224
                for (i = 0; i < MYSQL_FETCH_CACHE_SIZE; i++) {
 
3225
 
 
3226
                        /* A user has reported memory corruption in these
 
3227
                        buffers in Linux. Put magic numbers there to help
 
3228
                        to track a possible bug. */
 
3229
 
 
3230
                        buf = mem_alloc(prebuilt->mysql_row_len + 8);
 
3231
 
 
3232
                        prebuilt->fetch_cache[i] = buf + 4;
 
3233
 
 
3234
                        mach_write_to_4(buf, ROW_PREBUILT_FETCH_MAGIC_N);
 
3235
                        mach_write_to_4(buf + 4 + prebuilt->mysql_row_len,
 
3236
                                        ROW_PREBUILT_FETCH_MAGIC_N);
 
3237
                }
 
3238
        }
 
3239
 
 
3240
        ut_ad(prebuilt->fetch_cache_first == 0);
 
3241
 
 
3242
        if (UNIV_UNLIKELY(!row_sel_store_mysql_rec(
 
3243
                                  prebuilt->fetch_cache[
 
3244
                                          prebuilt->n_fetch_cached],
 
3245
                                  prebuilt, rec, offsets, start_field_no,
 
3246
                                  prebuilt->n_template))) {
 
3247
                ut_error;
 
3248
        }
 
3249
 
 
3250
        if (start_field_no) {
 
3251
          for (i=0; i < start_field_no; i++) {
 
3252
            register ulint offs;
 
3253
            mysql_row_templ_t* templ;
 
3254
            templ = prebuilt->mysql_template + i;
 
3255
 
 
3256
            if (templ->mysql_null_bit_mask) {
 
3257
              offs= templ->mysql_null_byte_offset;
 
3258
              *(prebuilt->fetch_cache[prebuilt->n_fetch_cached] + offs) ^=
 
3259
                (*(remainder_buf + offs) & templ->mysql_null_bit_mask);
 
3260
            }
 
3261
            offs= templ->mysql_col_offset;
 
3262
            memcpy(prebuilt->fetch_cache[prebuilt->n_fetch_cached] + offs,
 
3263
                   remainder_buf + offs,
 
3264
                   templ->mysql_col_len);
 
3265
          }
 
3266
        }
 
3267
 
 
3268
 
 
3269
        prebuilt->n_fetch_cached++;
 
3270
}
 
3271
 
 
3272
/*************************************************************************
 
3273
Tries to do a shortcut to fetch a clustered index record with a unique key,
 
3274
using the hash index if possible (not always). We assume that the search
 
3275
mode is PAGE_CUR_GE, it is a consistent read, there is a read view in trx,
 
3276
btr search latch has been locked in S-mode. */
 
3277
static
 
3278
ulint
 
3279
row_sel_try_search_shortcut_for_mysql(
 
3280
/*==================================*/
 
3281
                                /* out: SEL_FOUND, SEL_EXHAUSTED, SEL_RETRY */
 
3282
        const rec_t**   out_rec,/* out: record if found */
 
3283
        row_prebuilt_t* prebuilt,/* in: prebuilt struct */
 
3284
        ulint**         offsets,/* in/out: for rec_get_offsets(*out_rec) */
 
3285
        mem_heap_t**    heap,   /* in/out: heap for rec_get_offsets() */
 
3286
        mtr_t*          mtr)    /* in: started mtr */
 
3287
{
 
3288
        dict_index_t*   index           = prebuilt->index;
 
3289
        const dtuple_t* search_tuple    = prebuilt->search_tuple;
 
3290
        btr_pcur_t*     pcur            = prebuilt->pcur;
 
3291
        trx_t*          trx             = prebuilt->trx;
 
3292
        const rec_t*    rec;
 
3293
 
 
3294
        ut_ad(dict_index_is_clust(index));
 
3295
        ut_ad(!prebuilt->templ_contains_blob);
 
3296
 
 
3297
        btr_pcur_open_with_no_init(index, search_tuple, PAGE_CUR_GE,
 
3298
                                   BTR_SEARCH_LEAF, pcur,
 
3299
#ifndef UNIV_SEARCH_DEBUG
 
3300
                                   RW_S_LATCH,
 
3301
#else
 
3302
                                   0,
 
3303
#endif
 
3304
                                   mtr);
 
3305
        rec = btr_pcur_get_rec(pcur);
 
3306
 
 
3307
        if (!page_rec_is_user_rec(rec)) {
 
3308
 
 
3309
                return(SEL_RETRY);
 
3310
        }
 
3311
 
 
3312
        /* As the cursor is now placed on a user record after a search with
 
3313
        the mode PAGE_CUR_GE, the up_match field in the cursor tells how many
 
3314
        fields in the user record matched to the search tuple */
 
3315
 
 
3316
        if (btr_pcur_get_up_match(pcur) < dtuple_get_n_fields(search_tuple)) {
 
3317
 
 
3318
                return(SEL_EXHAUSTED);
 
3319
        }
 
3320
 
 
3321
        /* This is a non-locking consistent read: if necessary, fetch
 
3322
        a previous version of the record */
 
3323
 
 
3324
        *offsets = rec_get_offsets(rec, index, *offsets,
 
3325
                                   ULINT_UNDEFINED, heap);
 
3326
 
 
3327
        if (!lock_clust_rec_cons_read_sees(rec, index,
 
3328
                                           *offsets, trx->read_view)) {
 
3329
 
 
3330
                return(SEL_RETRY);
 
3331
        }
 
3332
 
 
3333
        if (rec_get_deleted_flag(rec, dict_table_is_comp(index->table))) {
 
3334
 
 
3335
                return(SEL_EXHAUSTED);
 
3336
        }
 
3337
 
 
3338
        *out_rec = rec;
 
3339
 
 
3340
        return(SEL_FOUND);
 
3341
}
 
3342
 
 
3343
/************************************************************************
 
3344
Searches for rows in the database. This is used in the interface to
 
3345
MySQL. This function opens a cursor, and also implements fetch next
 
3346
and fetch prev. NOTE that if we do a search with a full key value
 
3347
from a unique index (ROW_SEL_EXACT), then we will not store the cursor
 
3348
position and fetch next or fetch prev must not be tried to the cursor! */
 
3349
UNIV_INTERN
 
3350
ulint
 
3351
row_search_for_mysql(
 
3352
/*=================*/
 
3353
                                        /* out: DB_SUCCESS,
 
3354
                                        DB_RECORD_NOT_FOUND,
 
3355
                                        DB_END_OF_INDEX, DB_DEADLOCK,
 
3356
                                        DB_LOCK_TABLE_FULL, DB_CORRUPTION,
 
3357
                                        or DB_TOO_BIG_RECORD */
 
3358
        byte*           buf,            /* in/out: buffer for the fetched
 
3359
                                        row in the MySQL format */
 
3360
        ulint           mode,           /* in: search mode PAGE_CUR_L, ... */
 
3361
        row_prebuilt_t* prebuilt,       /* in: prebuilt struct for the
 
3362
                                        table handle; this contains the info
 
3363
                                        of search_tuple, index; if search
 
3364
                                        tuple contains 0 fields then we
 
3365
                                        position the cursor at the start or
 
3366
                                        the end of the index, depending on
 
3367
                                        'mode' */
 
3368
        ulint           match_mode,     /* in: 0 or ROW_SEL_EXACT or
 
3369
                                        ROW_SEL_EXACT_PREFIX */
 
3370
        ulint           direction)      /* in: 0 or ROW_SEL_NEXT or
 
3371
                                        ROW_SEL_PREV; NOTE: if this is != 0,
 
3372
                                        then prebuilt must have a pcur
 
3373
                                        with stored position! In opening of a
 
3374
                                        cursor 'direction' should be 0. */
 
3375
{
 
3376
        dict_index_t*   index           = prebuilt->index;
 
3377
        ibool           comp            = dict_table_is_comp(index->table);
 
3378
        const dtuple_t* search_tuple    = prebuilt->search_tuple;
 
3379
        btr_pcur_t*     pcur            = prebuilt->pcur;
 
3380
        trx_t*          trx             = prebuilt->trx;
 
3381
        dict_index_t*   clust_index;
 
3382
        que_thr_t*      thr;
 
3383
        const rec_t*    rec;
 
3384
        const rec_t*    result_rec;
 
3385
        const rec_t*    clust_rec;
 
3386
        ulint           err                             = DB_SUCCESS;
 
3387
        ibool           unique_search                   = FALSE;
 
3388
        ibool           unique_search_from_clust_index  = FALSE;
 
3389
        ibool           mtr_has_extra_clust_latch       = FALSE;
 
3390
        ibool           moves_up                        = FALSE;
 
3391
        ibool           set_also_gap_locks              = TRUE;
 
3392
        /* if the query is a plain locking SELECT, and the isolation level
 
3393
        is <= TRX_ISO_READ_COMMITTED, then this is set to FALSE */
 
3394
        ibool           did_semi_consistent_read        = FALSE;
 
3395
        /* if the returned record was locked and we did a semi-consistent
 
3396
        read (fetch the newest committed version), then this is set to
 
3397
        TRUE */
 
3398
#ifdef UNIV_SEARCH_DEBUG
 
3399
        ulint           cnt                             = 0;
 
3400
#endif /* UNIV_SEARCH_DEBUG */
 
3401
        ulint           next_offs;
 
3402
        ibool           same_user_rec;
 
3403
        mtr_t           mtr;
 
3404
        mem_heap_t*     heap                            = NULL;
 
3405
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
 
3406
        ulint*          offsets                         = offsets_;
 
3407
        ibool           some_fields_in_buffer;
 
3408
        ibool           get_clust_rec= 0;
 
3409
 
 
3410
        rec_offs_init(offsets_);
 
3411
 
 
3412
        ut_ad(index && pcur && search_tuple);
 
3413
        ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
 
3414
 
 
3415
        if (UNIV_UNLIKELY(prebuilt->table->ibd_file_missing)) {
 
3416
                ut_print_timestamp(stderr);
 
3417
                fprintf(stderr, "  InnoDB: Error:\n"
 
3418
                        "InnoDB: MySQL is trying to use a table handle"
 
3419
                        " but the .ibd file for\n"
 
3420
                        "InnoDB: table %s does not exist.\n"
 
3421
                        "InnoDB: Have you deleted the .ibd file"
 
3422
                        " from the database directory under\n"
 
3423
                        "InnoDB: the MySQL datadir, or have you used"
 
3424
                        " DISCARD TABLESPACE?\n"
 
3425
                        "InnoDB: Look from\n"
 
3426
                        "InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
 
3427
                        "innodb-troubleshooting.html\n"
 
3428
                        "InnoDB: how you can resolve the problem.\n",
 
3429
                        prebuilt->table->name);
 
3430
 
 
3431
                return(DB_ERROR);
 
3432
        }
 
3433
 
 
3434
        if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) {
 
3435
                fprintf(stderr,
 
3436
                        "InnoDB: Error: trying to free a corrupt\n"
 
3437
                        "InnoDB: table handle. Magic n %lu, table name ",
 
3438
                        (ulong) prebuilt->magic_n);
 
3439
                ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
 
3440
                putc('\n', stderr);
 
3441
 
 
3442
                mem_analyze_corruption(prebuilt);
 
3443
 
 
3444
                ut_error;
 
3445
        }
 
3446
 
 
3447
#if 0
 
3448
        /* August 19, 2005 by Heikki: temporarily disable this error
 
3449
        print until the cursor lock count is done correctly.
 
3450
        See bugs #12263 and #12456!*/
 
3451
 
 
3452
        if (trx->n_mysql_tables_in_use == 0
 
3453
            && UNIV_UNLIKELY(prebuilt->select_lock_type == LOCK_NONE)) {
 
3454
                /* Note that if MySQL uses an InnoDB temp table that it
 
3455
                created inside LOCK TABLES, then n_mysql_tables_in_use can
 
3456
                be zero; in that case select_lock_type is set to LOCK_X in
 
3457
                ::start_stmt. */
 
3458
 
 
3459
                fputs("InnoDB: Error: MySQL is trying to perform a SELECT\n"
 
3460
                      "InnoDB: but it has not locked"
 
3461
                      " any tables in ::external_lock()!\n",
 
3462
                      stderr);
 
3463
                trx_print(stderr, trx, 600);
 
3464
                fputc('\n', stderr);
 
3465
        }
 
3466
#endif
 
3467
 
 
3468
#if 0
 
3469
        fprintf(stderr, "Match mode %lu\n search tuple ",
 
3470
                (ulong) match_mode);
 
3471
        dtuple_print(search_tuple);
 
3472
        fprintf(stderr, "N tables locked %lu\n",
 
3473
                (ulong) trx->mysql_n_tables_locked);
 
3474
#endif
 
3475
        /*-------------------------------------------------------------*/
 
3476
        /* PHASE 0: Release a possible s-latch we are holding on the
 
3477
        adaptive hash index latch if there is someone waiting behind */
 
3478
 
 
3479
        if (UNIV_UNLIKELY(btr_search_latch.writer != RW_LOCK_NOT_LOCKED)
 
3480
            && trx->has_search_latch) {
 
3481
 
 
3482
                /* There is an x-latch request on the adaptive hash index:
 
3483
                release the s-latch to reduce starvation and wait for
 
3484
                BTR_SEA_TIMEOUT rounds before trying to keep it again over
 
3485
                calls from MySQL */
 
3486
 
 
3487
                rw_lock_s_unlock(&btr_search_latch);
 
3488
                trx->has_search_latch = FALSE;
 
3489
 
 
3490
                trx->search_latch_timeout = BTR_SEA_TIMEOUT;
 
3491
        }
 
3492
 
 
3493
        /* Reset the new record lock info if srv_locks_unsafe_for_binlog
 
3494
        is set or session is using a READ COMMITED isolation level. Then
 
3495
        we are able to remove the record locks set here on an individual
 
3496
        row. */
 
3497
 
 
3498
        if ((srv_locks_unsafe_for_binlog
 
3499
             || trx->isolation_level == TRX_ISO_READ_COMMITTED)
 
3500
            && prebuilt->select_lock_type != LOCK_NONE) {
 
3501
 
 
3502
                trx_reset_new_rec_lock_info(trx);
 
3503
        }
 
3504
 
 
3505
        /*-------------------------------------------------------------*/
 
3506
        /* PHASE 1: Try to pop the row from the prefetch cache */
 
3507
 
 
3508
        if (UNIV_UNLIKELY(direction == 0)) {
 
3509
                trx->op_info = "starting index read";
 
3510
 
 
3511
                prebuilt->n_rows_fetched = 0;
 
3512
                prebuilt->n_fetch_cached = 0;
 
3513
                prebuilt->fetch_cache_first = 0;
 
3514
 
 
3515
                if (prebuilt->sel_graph == NULL) {
 
3516
                        /* Build a dummy select query graph */
 
3517
                        row_prebuild_sel_graph(prebuilt);
 
3518
                }
 
3519
        } else {
 
3520
                trx->op_info = "fetching rows";
 
3521
 
 
3522
                if (prebuilt->n_rows_fetched == 0) {
 
3523
                        prebuilt->fetch_direction = direction;
 
3524
                }
 
3525
 
 
3526
                if (UNIV_UNLIKELY(direction != prebuilt->fetch_direction)) {
 
3527
                        if (UNIV_UNLIKELY(prebuilt->n_fetch_cached > 0)) {
 
3528
                                ut_error;
 
3529
                                /* TODO: scrollable cursor: restore cursor to
 
3530
                                the place of the latest returned row,
 
3531
                                or better: prevent caching for a scroll
 
3532
                                cursor! */
 
3533
                        }
 
3534
 
 
3535
                        prebuilt->n_rows_fetched = 0;
 
3536
                        prebuilt->n_fetch_cached = 0;
 
3537
                        prebuilt->fetch_cache_first = 0;
 
3538
 
 
3539
                } else if (UNIV_LIKELY(prebuilt->n_fetch_cached > 0)) {
 
3540
                        row_sel_pop_cached_row_for_mysql(buf, prebuilt);
 
3541
 
 
3542
                        prebuilt->n_rows_fetched++;
 
3543
 
 
3544
                        srv_n_rows_read++;
 
3545
                        err = DB_SUCCESS;
 
3546
                        goto func_exit;
 
3547
                }
 
3548
 
 
3549
                if (prebuilt->fetch_cache_first > 0
 
3550
                    && prebuilt->fetch_cache_first < MYSQL_FETCH_CACHE_SIZE) {
 
3551
 
 
3552
                        /* The previous returned row was popped from the fetch
 
3553
                        cache, but the cache was not full at the time of the
 
3554
                        popping: no more rows can exist in the result set */
 
3555
 
 
3556
                        err = DB_RECORD_NOT_FOUND;
 
3557
                        goto func_exit;
 
3558
                }
 
3559
 
 
3560
                prebuilt->n_rows_fetched++;
 
3561
 
 
3562
                if (prebuilt->n_rows_fetched > 1000000000) {
 
3563
                        /* Prevent wrap-over */
 
3564
                        prebuilt->n_rows_fetched = 500000000;
 
3565
                }
 
3566
 
 
3567
                mode = pcur->search_mode;
 
3568
        }
 
3569
 
 
3570
        /* In a search where at most one record in the index may match, we
 
3571
        can use a LOCK_REC_NOT_GAP type record lock when locking a
 
3572
        non-delete-marked matching record.
 
3573
 
 
3574
        Note that in a unique secondary index there may be different
 
3575
        delete-marked versions of a record where only the primary key
 
3576
        values differ: thus in a secondary index we must use next-key
 
3577
        locks when locking delete-marked records. */
 
3578
 
 
3579
        if (match_mode == ROW_SEL_EXACT
 
3580
            && dict_index_is_unique(index)
 
3581
            && dtuple_get_n_fields(search_tuple)
 
3582
            == dict_index_get_n_unique(index)
 
3583
            && (dict_index_is_clust(index)
 
3584
                || !dtuple_contains_null(search_tuple))) {
 
3585
 
 
3586
                /* Note above that a UNIQUE secondary index can contain many
 
3587
                rows with the same key value if one of the columns is the SQL
 
3588
                null. A clustered index under MySQL can never contain null
 
3589
                columns because we demand that all the columns in primary key
 
3590
                are non-null. */
 
3591
 
 
3592
                unique_search = TRUE;
 
3593
 
 
3594
                /* Even if the condition is unique, MySQL seems to try to
 
3595
                retrieve also a second row if a primary key contains more than
 
3596
                1 column. Return immediately if this is not a HANDLER
 
3597
                command. */
 
3598
 
 
3599
                if (UNIV_UNLIKELY(direction != 0
 
3600
                                  && !prebuilt->used_in_HANDLER)) {
 
3601
 
 
3602
                        err = DB_RECORD_NOT_FOUND;
 
3603
                        goto func_exit;
 
3604
                }
 
3605
        }
 
3606
 
 
3607
        mtr_start(&mtr);
 
3608
 
 
3609
        /*-------------------------------------------------------------*/
 
3610
        /* PHASE 2: Try fast adaptive hash index search if possible */
 
3611
 
 
3612
        /* Next test if this is the special case where we can use the fast
 
3613
        adaptive hash index to try the search. Since we must release the
 
3614
        search system latch when we retrieve an externally stored field, we
 
3615
        cannot use the adaptive hash index in a search in the case the row
 
3616
        may be long and there may be externally stored fields */
 
3617
 
 
3618
        if (UNIV_UNLIKELY(direction == 0)
 
3619
            && unique_search
 
3620
            && dict_index_is_clust(index)
 
3621
            && !prebuilt->templ_contains_blob
 
3622
            && !prebuilt->used_in_HANDLER
 
3623
            && (prebuilt->mysql_row_len < UNIV_PAGE_SIZE / 8)) {
 
3624
 
 
3625
                mode = PAGE_CUR_GE;
 
3626
 
 
3627
                unique_search_from_clust_index = TRUE;
 
3628
 
 
3629
                if (trx->mysql_n_tables_locked == 0
 
3630
                    && prebuilt->select_lock_type == LOCK_NONE
 
3631
                    && trx->isolation_level > TRX_ISO_READ_UNCOMMITTED
 
3632
                    && trx->read_view) {
 
3633
 
 
3634
                        /* This is a SELECT query done as a consistent read,
 
3635
                        and the read view has already been allocated:
 
3636
                        let us try a search shortcut through the hash
 
3637
                        index.
 
3638
                        NOTE that we must also test that
 
3639
                        mysql_n_tables_locked == 0, because this might
 
3640
                        also be INSERT INTO ... SELECT ... or
 
3641
                        CREATE TABLE ... SELECT ... . Our algorithm is
 
3642
                        NOT prepared to inserts interleaved with the SELECT,
 
3643
                        and if we try that, we can deadlock on the adaptive
 
3644
                        hash index semaphore! */
 
3645
 
 
3646
#ifndef UNIV_SEARCH_DEBUG
 
3647
                        if (!trx->has_search_latch) {
 
3648
                                rw_lock_s_lock(&btr_search_latch);
 
3649
                                trx->has_search_latch = TRUE;
 
3650
                        }
 
3651
#endif
 
3652
                        switch (row_sel_try_search_shortcut_for_mysql(
 
3653
                                        &rec, prebuilt, &offsets, &heap,
 
3654
                                        &mtr)) {
 
3655
                        case SEL_FOUND:
 
3656
#ifdef UNIV_SEARCH_DEBUG
 
3657
                                ut_a(0 == cmp_dtuple_rec(search_tuple,
 
3658
                                                         rec, offsets));
 
3659
#endif
 
3660
                                /* At this point, rec is protected by
 
3661
                                a page latch that was acquired by
 
3662
                                row_sel_try_search_shortcut_for_mysql().
 
3663
                                The latch will not be released until
 
3664
                                mtr_commit(&mtr). */
 
3665
 
 
3666
                                if (!row_sel_store_mysql_rec(buf, prebuilt,
 
3667
                                                             rec, offsets, 0,
 
3668
                                                             prebuilt->n_template)) {
 
3669
                                        err = DB_TOO_BIG_RECORD;
 
3670
 
 
3671
                                        /* We let the main loop to do the
 
3672
                                        error handling */
 
3673
                                        goto shortcut_fails_too_big_rec;
 
3674
                                }
 
3675
 
 
3676
                                mtr_commit(&mtr);
 
3677
 
 
3678
                                /* ut_print_name(stderr, index->name);
 
3679
                                fputs(" shortcut\n", stderr); */
 
3680
 
 
3681
                                srv_n_rows_read++;
 
3682
 
 
3683
                                err = DB_SUCCESS;
 
3684
                                goto release_search_latch_if_needed;
 
3685
 
 
3686
                        case SEL_EXHAUSTED:
 
3687
                                mtr_commit(&mtr);
 
3688
 
 
3689
                                /* ut_print_name(stderr, index->name);
 
3690
                                fputs(" record not found 2\n", stderr); */
 
3691
 
 
3692
                                err = DB_RECORD_NOT_FOUND;
 
3693
release_search_latch_if_needed:
 
3694
                                if (trx->search_latch_timeout > 0
 
3695
                                    && trx->has_search_latch) {
 
3696
 
 
3697
                                        trx->search_latch_timeout--;
 
3698
 
 
3699
                                        rw_lock_s_unlock(&btr_search_latch);
 
3700
                                        trx->has_search_latch = FALSE;
 
3701
                                }
 
3702
 
 
3703
                                /* NOTE that we do NOT store the cursor
 
3704
                                position */
 
3705
                                goto func_exit;
 
3706
 
 
3707
                        case SEL_RETRY:
 
3708
                                break;
 
3709
 
 
3710
                        default:
 
3711
                                ut_ad(0);
 
3712
                        }
 
3713
shortcut_fails_too_big_rec:
 
3714
                        mtr_commit(&mtr);
 
3715
                        mtr_start(&mtr);
 
3716
                }
 
3717
        }
 
3718
 
 
3719
        /*-------------------------------------------------------------*/
 
3720
        /* PHASE 3: Open or restore index cursor position */
 
3721
 
 
3722
        if (trx->has_search_latch) {
 
3723
                rw_lock_s_unlock(&btr_search_latch);
 
3724
                trx->has_search_latch = FALSE;
 
3725
        }
 
3726
 
 
3727
        trx_start_if_not_started(trx);
 
3728
 
 
3729
        if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
 
3730
            && prebuilt->select_lock_type != LOCK_NONE
 
3731
            && trx->mysql_thd != NULL
 
3732
            && trx->mysql_query_str != NULL
 
3733
            && *trx->mysql_query_str != NULL) {
 
3734
 
 
3735
                /* Scan the MySQL query string; check if SELECT is the first
 
3736
                word there */
 
3737
 
 
3738
                if (dict_str_starts_with_keyword(
 
3739
                            trx->mysql_thd, *trx->mysql_query_str, "SELECT")) {
 
3740
                        /* It is a plain locking SELECT and the isolation
 
3741
                        level is low: do not lock gaps */
 
3742
 
 
3743
                        set_also_gap_locks = FALSE;
 
3744
                }
 
3745
        }
 
3746
 
 
3747
        /* Note that if the search mode was GE or G, then the cursor
 
3748
        naturally moves upward (in fetch next) in alphabetical order,
 
3749
        otherwise downward */
 
3750
 
 
3751
        if (UNIV_UNLIKELY(direction == 0)) {
 
3752
                if (mode == PAGE_CUR_GE || mode == PAGE_CUR_G) {
 
3753
                        moves_up = TRUE;
 
3754
                }
 
3755
        } else if (direction == ROW_SEL_NEXT) {
 
3756
                moves_up = TRUE;
 
3757
        }
 
3758
 
 
3759
        thr = que_fork_get_first_thr(prebuilt->sel_graph);
 
3760
 
 
3761
        que_thr_move_to_run_state_for_mysql(thr, trx);
 
3762
 
 
3763
        clust_index = dict_table_get_first_index(index->table);
 
3764
 
 
3765
        if (UNIV_LIKELY(direction != 0)) {
 
3766
                ibool   need_to_process = sel_restore_position_for_mysql(
 
3767
                        &same_user_rec, BTR_SEARCH_LEAF,
 
3768
                        pcur, moves_up, &mtr);
 
3769
 
 
3770
                if (UNIV_UNLIKELY(need_to_process)) {
 
3771
                        if (UNIV_UNLIKELY(prebuilt->row_read_type
 
3772
                                          == ROW_READ_DID_SEMI_CONSISTENT)) {
 
3773
                                /* We did a semi-consistent read,
 
3774
                                but the record was removed in
 
3775
                                the meantime. */
 
3776
                                prebuilt->row_read_type
 
3777
                                        = ROW_READ_TRY_SEMI_CONSISTENT;
 
3778
                        }
 
3779
                } else if (UNIV_LIKELY(prebuilt->row_read_type
 
3780
                                       != ROW_READ_DID_SEMI_CONSISTENT)) {
 
3781
 
 
3782
                        /* The cursor was positioned on the record
 
3783
                        that we returned previously.  If we need
 
3784
                        to repeat a semi-consistent read as a
 
3785
                        pessimistic locking read, the record
 
3786
                        cannot be skipped. */
 
3787
 
 
3788
                        goto next_rec;
 
3789
                }
 
3790
 
 
3791
        } else if (dtuple_get_n_fields(search_tuple) > 0) {
 
3792
 
 
3793
                btr_pcur_open_with_no_init(index, search_tuple, mode,
 
3794
                                           BTR_SEARCH_LEAF,
 
3795
                                           pcur, 0, &mtr);
 
3796
 
 
3797
                pcur->trx_if_known = trx;
 
3798
 
 
3799
                rec = btr_pcur_get_rec(pcur);
 
3800
 
 
3801
                if (!moves_up
 
3802
                    && !page_rec_is_supremum(rec)
 
3803
                    && set_also_gap_locks
 
3804
                    && !(srv_locks_unsafe_for_binlog
 
3805
                         || trx->isolation_level == TRX_ISO_READ_COMMITTED)
 
3806
                    && prebuilt->select_lock_type != LOCK_NONE) {
 
3807
 
 
3808
                        /* Try to place a gap lock on the next index record
 
3809
                        to prevent phantoms in ORDER BY ... DESC queries */
 
3810
                        const rec_t*    next = page_rec_get_next_const(rec);
 
3811
 
 
3812
                        offsets = rec_get_offsets(next, index, offsets,
 
3813
                                                  ULINT_UNDEFINED, &heap);
 
3814
                        err = sel_set_rec_lock(btr_pcur_get_block(pcur),
 
3815
                                               next, index, offsets,
 
3816
                                               prebuilt->select_lock_type,
 
3817
                                               LOCK_GAP, thr);
 
3818
 
 
3819
                        if (err != DB_SUCCESS) {
 
3820
 
 
3821
                                goto lock_wait_or_error;
 
3822
                        }
 
3823
                }
 
3824
        } else {
 
3825
                if (mode == PAGE_CUR_G) {
 
3826
                        btr_pcur_open_at_index_side(
 
3827
                                TRUE, index, BTR_SEARCH_LEAF, pcur, FALSE,
 
3828
                                &mtr);
 
3829
                } else if (mode == PAGE_CUR_L) {
 
3830
                        btr_pcur_open_at_index_side(
 
3831
                                FALSE, index, BTR_SEARCH_LEAF, pcur, FALSE,
 
3832
                                &mtr);
 
3833
                }
 
3834
        }
 
3835
 
 
3836
        if (!prebuilt->sql_stat_start) {
 
3837
                /* No need to set an intention lock or assign a read view */
 
3838
 
 
3839
                if (trx->read_view == NULL
 
3840
                    && prebuilt->select_lock_type == LOCK_NONE) {
 
3841
 
 
3842
                        fputs("InnoDB: Error: MySQL is trying to"
 
3843
                              " perform a consistent read\n"
 
3844
                              "InnoDB: but the read view is not assigned!\n",
 
3845
                              stderr);
 
3846
                        trx_print(stderr, trx, 600);
 
3847
                        fputc('\n', stderr);
 
3848
                        ut_a(0);
 
3849
                }
 
3850
        } else if (prebuilt->select_lock_type == LOCK_NONE) {
 
3851
                /* This is a consistent read */
 
3852
                /* Assign a read view for the query */
 
3853
 
 
3854
                trx_assign_read_view(trx);
 
3855
                prebuilt->sql_stat_start = FALSE;
 
3856
        } else {
 
3857
                ulint   lock_mode;
 
3858
                if (prebuilt->select_lock_type == LOCK_S) {
 
3859
                        lock_mode = LOCK_IS;
 
3860
                } else {
 
3861
                        lock_mode = LOCK_IX;
 
3862
                }
 
3863
                err = lock_table(0, index->table, lock_mode, thr);
 
3864
 
 
3865
                if (err != DB_SUCCESS) {
 
3866
 
 
3867
                        goto lock_wait_or_error;
 
3868
                }
 
3869
                prebuilt->sql_stat_start = FALSE;
 
3870
        }
 
3871
 
 
3872
rec_loop:
 
3873
        /*-------------------------------------------------------------*/
 
3874
        /* PHASE 4: Look for matching records in a loop */
 
3875
 
 
3876
        rec = btr_pcur_get_rec(pcur);
 
3877
        ut_ad(!!page_rec_is_comp(rec) == comp);
 
3878
#ifdef UNIV_SEARCH_DEBUG
 
3879
        /*
 
3880
        fputs("Using ", stderr);
 
3881
        dict_index_name_print(stderr, index);
 
3882
        fprintf(stderr, " cnt %lu ; Page no %lu\n", cnt,
 
3883
        page_get_page_no(page_align(rec)));
 
3884
        rec_print(rec);
 
3885
        */
 
3886
#endif /* UNIV_SEARCH_DEBUG */
 
3887
 
 
3888
        if (page_rec_is_infimum(rec)) {
 
3889
 
 
3890
                /* The infimum record on a page cannot be in the result set,
 
3891
                and neither can a record lock be placed on it: we skip such
 
3892
                a record. */
 
3893
 
 
3894
                goto next_rec;
 
3895
        }
 
3896
 
 
3897
        if (page_rec_is_supremum(rec)) {
 
3898
 
 
3899
                if (set_also_gap_locks
 
3900
                    && !(srv_locks_unsafe_for_binlog
 
3901
                         || trx->isolation_level == TRX_ISO_READ_COMMITTED)
 
3902
                    && prebuilt->select_lock_type != LOCK_NONE) {
 
3903
 
 
3904
                        /* Try to place a lock on the index record */
 
3905
 
 
3906
                        /* If innodb_locks_unsafe_for_binlog option is used
 
3907
                        or this session is using a READ COMMITTED isolation
 
3908
                        level we do not lock gaps. Supremum record is really
 
3909
                        a gap and therefore we do not set locks there. */
 
3910
 
 
3911
                        offsets = rec_get_offsets(rec, index, offsets,
 
3912
                                                  ULINT_UNDEFINED, &heap);
 
3913
                        err = sel_set_rec_lock(btr_pcur_get_block(pcur),
 
3914
                                               rec, index, offsets,
 
3915
                                               prebuilt->select_lock_type,
 
3916
                                               LOCK_ORDINARY, thr);
 
3917
 
 
3918
                        if (err != DB_SUCCESS) {
 
3919
 
 
3920
                                goto lock_wait_or_error;
 
3921
                        }
 
3922
                }
 
3923
                /* A page supremum record cannot be in the result set: skip
 
3924
                it now that we have placed a possible lock on it */
 
3925
 
 
3926
                goto next_rec;
 
3927
        }
 
3928
 
 
3929
        /*-------------------------------------------------------------*/
 
3930
        /* Do sanity checks in case our cursor has bumped into page
 
3931
        corruption */
 
3932
 
 
3933
        if (comp) {
 
3934
                next_offs = rec_get_next_offs(rec, TRUE);
 
3935
                if (UNIV_UNLIKELY(next_offs < PAGE_NEW_SUPREMUM)) {
 
3936
 
 
3937
                        goto wrong_offs;
 
3938
                }
 
3939
        } else {
 
3940
                next_offs = rec_get_next_offs(rec, FALSE);
 
3941
                if (UNIV_UNLIKELY(next_offs < PAGE_OLD_SUPREMUM)) {
 
3942
 
 
3943
                        goto wrong_offs;
 
3944
                }
 
3945
        }
 
3946
 
 
3947
        if (UNIV_UNLIKELY(next_offs >= UNIV_PAGE_SIZE - PAGE_DIR)) {
 
3948
 
 
3949
wrong_offs:
 
3950
                if (srv_force_recovery == 0 || moves_up == FALSE) {
 
3951
                        ut_print_timestamp(stderr);
 
3952
                        buf_page_print(page_align(rec), 0);
 
3953
                        fprintf(stderr,
 
3954
                                "\nInnoDB: rec address %p,"
 
3955
                                " buf block fix count %lu\n",
 
3956
                                (void*) rec, (ulong)
 
3957
                                btr_cur_get_block(btr_pcur_get_btr_cur(pcur))
 
3958
                                ->page.buf_fix_count);
 
3959
                        fprintf(stderr,
 
3960
                                "InnoDB: Index corruption: rec offs %lu"
 
3961
                                " next offs %lu, page no %lu,\n"
 
3962
                                "InnoDB: ",
 
3963
                                (ulong) page_offset(rec),
 
3964
                                (ulong) next_offs,
 
3965
                                (ulong) page_get_page_no(page_align(rec)));
 
3966
                        dict_index_name_print(stderr, trx, index);
 
3967
                        fputs(". Run CHECK TABLE. You may need to\n"
 
3968
                              "InnoDB: restore from a backup, or"
 
3969
                              " dump + drop + reimport the table.\n",
 
3970
                              stderr);
 
3971
 
 
3972
                        err = DB_CORRUPTION;
 
3973
 
 
3974
                        goto lock_wait_or_error;
 
3975
                } else {
 
3976
                        /* The user may be dumping a corrupt table. Jump
 
3977
                        over the corruption to recover as much as possible. */
 
3978
 
 
3979
                        fprintf(stderr,
 
3980
                                "InnoDB: Index corruption: rec offs %lu"
 
3981
                                " next offs %lu, page no %lu,\n"
 
3982
                                "InnoDB: ",
 
3983
                                (ulong) page_offset(rec),
 
3984
                                (ulong) next_offs,
 
3985
                                (ulong) page_get_page_no(page_align(rec)));
 
3986
                        dict_index_name_print(stderr, trx, index);
 
3987
                        fputs(". We try to skip the rest of the page.\n",
 
3988
                              stderr);
 
3989
 
 
3990
                        btr_pcur_move_to_last_on_page(pcur, &mtr);
 
3991
 
 
3992
                        goto next_rec;
 
3993
                }
 
3994
        }
 
3995
        /*-------------------------------------------------------------*/
 
3996
 
 
3997
        /* Calculate the 'offsets' associated with 'rec' */
 
3998
 
 
3999
        offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
 
4000
 
 
4001
        if (UNIV_UNLIKELY(srv_force_recovery > 0)) {
 
4002
                if (!rec_validate(rec, offsets)
 
4003
                    || !btr_index_rec_validate(rec, index, FALSE)) {
 
4004
                        fprintf(stderr,
 
4005
                                "InnoDB: Index corruption: rec offs %lu"
 
4006
                                " next offs %lu, page no %lu,\n"
 
4007
                                "InnoDB: ",
 
4008
                                (ulong) page_offset(rec),
 
4009
                                (ulong) next_offs,
 
4010
                                (ulong) page_get_page_no(page_align(rec)));
 
4011
                        dict_index_name_print(stderr, trx, index);
 
4012
                        fputs(". We try to skip the record.\n",
 
4013
                              stderr);
 
4014
 
 
4015
                        goto next_rec;
 
4016
                }
 
4017
        }
 
4018
 
 
4019
        /* Note that we cannot trust the up_match value in the cursor at this
 
4020
        place because we can arrive here after moving the cursor! Thus
 
4021
        we have to recompare rec and search_tuple to determine if they
 
4022
        match enough. */
 
4023
 
 
4024
        if (match_mode == ROW_SEL_EXACT) {
 
4025
                /* Test if the index record matches completely to search_tuple
 
4026
                in prebuilt: if not, then we return with DB_RECORD_NOT_FOUND */
 
4027
 
 
4028
                /* fputs("Comparing rec and search tuple\n", stderr); */
 
4029
 
 
4030
                if (0 != cmp_dtuple_rec(search_tuple, rec, offsets)) {
 
4031
 
 
4032
                        if (set_also_gap_locks
 
4033
                            && !(srv_locks_unsafe_for_binlog
 
4034
                                 || trx->isolation_level
 
4035
                                 == TRX_ISO_READ_COMMITTED)
 
4036
                            && prebuilt->select_lock_type != LOCK_NONE) {
 
4037
 
 
4038
                                /* Try to place a gap lock on the index
 
4039
                                record only if innodb_locks_unsafe_for_binlog
 
4040
                                option is not set or this session is not
 
4041
                                using a READ COMMITTED isolation level. */
 
4042
 
 
4043
                                err = sel_set_rec_lock(
 
4044
                                        btr_pcur_get_block(pcur),
 
4045
                                        rec, index, offsets,
 
4046
                                        prebuilt->select_lock_type, LOCK_GAP,
 
4047
                                        thr);
 
4048
 
 
4049
                                if (err != DB_SUCCESS) {
 
4050
 
 
4051
                                        goto lock_wait_or_error;
 
4052
                                }
 
4053
                        }
 
4054
 
 
4055
                        btr_pcur_store_position(pcur, &mtr);
 
4056
 
 
4057
                        err = DB_RECORD_NOT_FOUND;
 
4058
                        /* ut_print_name(stderr, index->name);
 
4059
                        fputs(" record not found 3\n", stderr); */
 
4060
 
 
4061
                        goto normal_return;
 
4062
                }
 
4063
 
 
4064
        } else if (match_mode == ROW_SEL_EXACT_PREFIX) {
 
4065
 
 
4066
                if (!cmp_dtuple_is_prefix_of_rec(search_tuple, rec, offsets)) {
 
4067
 
 
4068
                        if (set_also_gap_locks
 
4069
                            && !(srv_locks_unsafe_for_binlog
 
4070
                                 || trx->isolation_level
 
4071
                                 == TRX_ISO_READ_COMMITTED)
 
4072
                            && prebuilt->select_lock_type != LOCK_NONE) {
 
4073
 
 
4074
                                /* Try to place a gap lock on the index
 
4075
                                record only if innodb_locks_unsafe_for_binlog
 
4076
                                option is not set or this session is not
 
4077
                                using a READ COMMITTED isolation level. */
 
4078
 
 
4079
                                err = sel_set_rec_lock(
 
4080
                                        btr_pcur_get_block(pcur),
 
4081
                                        rec, index, offsets,
 
4082
                                        prebuilt->select_lock_type, LOCK_GAP,
 
4083
                                        thr);
 
4084
 
 
4085
                                if (err != DB_SUCCESS) {
 
4086
 
 
4087
                                        goto lock_wait_or_error;
 
4088
                                }
 
4089
                        }
 
4090
 
 
4091
                        btr_pcur_store_position(pcur, &mtr);
 
4092
 
 
4093
                        err = DB_RECORD_NOT_FOUND;
 
4094
                        /* ut_print_name(stderr, index->name);
 
4095
                        fputs(" record not found 4\n", stderr); */
 
4096
 
 
4097
                        goto normal_return;
 
4098
                }
 
4099
        }
 
4100
 
 
4101
        /* We are ready to look at a possible new index entry in the result
 
4102
        set: the cursor is now placed on a user record */
 
4103
 
 
4104
        if (prebuilt->select_lock_type != LOCK_NONE) {
 
4105
                /* Try to place a lock on the index record; note that delete
 
4106
                marked records are a special case in a unique search. If there
 
4107
                is a non-delete marked record, then it is enough to lock its
 
4108
                existence with LOCK_REC_NOT_GAP. */
 
4109
 
 
4110
                /* If innodb_locks_unsafe_for_binlog option is used
 
4111
                or this session is using a READ COMMITED isolation
 
4112
                level we lock only the record, i.e., next-key locking is
 
4113
                not used. */
 
4114
 
 
4115
                ulint   lock_type;
 
4116
 
 
4117
                if (!set_also_gap_locks
 
4118
                    || srv_locks_unsafe_for_binlog
 
4119
                    || trx->isolation_level == TRX_ISO_READ_COMMITTED
 
4120
                    || (unique_search
 
4121
                        && !UNIV_UNLIKELY(rec_get_deleted_flag(rec, comp)))) {
 
4122
 
 
4123
                        goto no_gap_lock;
 
4124
                } else {
 
4125
                        lock_type = LOCK_ORDINARY;
 
4126
                }
 
4127
 
 
4128
                /* If we are doing a 'greater or equal than a primary key
 
4129
                value' search from a clustered index, and we find a record
 
4130
                that has that exact primary key value, then there is no need
 
4131
                to lock the gap before the record, because no insert in the
 
4132
                gap can be in our search range. That is, no phantom row can
 
4133
                appear that way.
 
4134
 
 
4135
                An example: if col1 is the primary key, the search is WHERE
 
4136
                col1 >= 100, and we find a record where col1 = 100, then no
 
4137
                need to lock the gap before that record. */
 
4138
 
 
4139
                if (index == clust_index
 
4140
                    && mode == PAGE_CUR_GE
 
4141
                    && direction == 0
 
4142
                    && dtuple_get_n_fields_cmp(search_tuple)
 
4143
                    == dict_index_get_n_unique(index)
 
4144
                    && 0 == cmp_dtuple_rec(search_tuple, rec, offsets)) {
 
4145
no_gap_lock:
 
4146
                        lock_type = LOCK_REC_NOT_GAP;
 
4147
                }
 
4148
 
 
4149
                err = sel_set_rec_lock(btr_pcur_get_block(pcur),
 
4150
                                       rec, index, offsets,
 
4151
                                       prebuilt->select_lock_type,
 
4152
                                       lock_type, thr);
 
4153
 
 
4154
                switch (err) {
 
4155
                        const rec_t*    old_vers;
 
4156
                case DB_SUCCESS:
 
4157
                        break;
 
4158
                case DB_LOCK_WAIT:
 
4159
                        if (UNIV_LIKELY(prebuilt->row_read_type
 
4160
                                        != ROW_READ_TRY_SEMI_CONSISTENT)
 
4161
                            || index != clust_index) {
 
4162
 
 
4163
                                goto lock_wait_or_error;
 
4164
                        }
 
4165
 
 
4166
                        /* The following call returns 'offsets'
 
4167
                        associated with 'old_vers' */
 
4168
                        err = row_sel_build_committed_vers_for_mysql(
 
4169
                                clust_index, prebuilt, rec,
 
4170
                                &offsets, &heap, &old_vers, &mtr);
 
4171
 
 
4172
                        if (err != DB_SUCCESS) {
 
4173
 
 
4174
                                goto lock_wait_or_error;
 
4175
                        }
 
4176
 
 
4177
                        mutex_enter(&kernel_mutex);
 
4178
                        if (trx->was_chosen_as_deadlock_victim) {
 
4179
                                mutex_exit(&kernel_mutex);
 
4180
                                err = DB_DEADLOCK;
 
4181
 
 
4182
                                goto lock_wait_or_error;
 
4183
                        }
 
4184
                        if (UNIV_LIKELY(trx->wait_lock != NULL)) {
 
4185
                                lock_cancel_waiting_and_release(
 
4186
                                        trx->wait_lock);
 
4187
                                trx_reset_new_rec_lock_info(trx);
 
4188
                        } else {
 
4189
                                mutex_exit(&kernel_mutex);
 
4190
 
 
4191
                                /* The lock was granted while we were
 
4192
                                searching for the last committed version.
 
4193
                                Do a normal locking read. */
 
4194
 
 
4195
                                offsets = rec_get_offsets(rec, index, offsets,
 
4196
                                                          ULINT_UNDEFINED,
 
4197
                                                          &heap);
 
4198
                                err = DB_SUCCESS;
 
4199
                                break;
 
4200
                        }
 
4201
                        mutex_exit(&kernel_mutex);
 
4202
 
 
4203
                        if (old_vers == NULL) {
 
4204
                                /* The row was not yet committed */
 
4205
 
 
4206
                                goto next_rec;
 
4207
                        }
 
4208
 
 
4209
                        did_semi_consistent_read = TRUE;
 
4210
                        rec = old_vers;
 
4211
                        break;
 
4212
                default:
 
4213
 
 
4214
                        goto lock_wait_or_error;
 
4215
                }
 
4216
        } else {
 
4217
                /* This is a non-locking consistent read: if necessary, fetch
 
4218
                a previous version of the record */
 
4219
 
 
4220
                if (trx->isolation_level == TRX_ISO_READ_UNCOMMITTED) {
 
4221
 
 
4222
                        /* Do nothing: we let a non-locking SELECT read the
 
4223
                        latest version of the record */
 
4224
 
 
4225
                } else if (index == clust_index) {
 
4226
 
 
4227
                        /* Fetch a previous version of the row if the current
 
4228
                        one is not visible in the snapshot; if we have a very
 
4229
                        high force recovery level set, we try to avoid crashes
 
4230
                        by skipping this lookup */
 
4231
 
 
4232
                        if (UNIV_LIKELY(srv_force_recovery < 5)
 
4233
                            && !lock_clust_rec_cons_read_sees(
 
4234
                                    rec, index, offsets, trx->read_view)) {
 
4235
 
 
4236
                                rec_t*  old_vers;
 
4237
                                /* The following call returns 'offsets'
 
4238
                                associated with 'old_vers' */
 
4239
                                err = row_sel_build_prev_vers_for_mysql(
 
4240
                                        trx->read_view, clust_index,
 
4241
                                        prebuilt, rec, &offsets, &heap,
 
4242
                                        &old_vers, &mtr);
 
4243
 
 
4244
                                if (err != DB_SUCCESS) {
 
4245
 
 
4246
                                        goto lock_wait_or_error;
 
4247
                                }
 
4248
 
 
4249
                                if (old_vers == NULL) {
 
4250
                                        /* The row did not exist yet in
 
4251
                                        the read view */
 
4252
 
 
4253
                                        goto next_rec;
 
4254
                                }
 
4255
 
 
4256
                                rec = old_vers;
 
4257
                        }
 
4258
                } else if (!lock_sec_rec_cons_read_sees(rec, trx->read_view)) {
 
4259
                        /* We are looking into a non-clustered index,
 
4260
                        and to get the right version of the record we
 
4261
                        have to look also into the clustered index: this
 
4262
                        is necessary, because we can only get the undo
 
4263
                        information via the clustered index record. */
 
4264
 
 
4265
                        ut_ad(index != clust_index);
 
4266
                        get_clust_rec= TRUE;
 
4267
                        goto idx_cond_check;
 
4268
                }
 
4269
        }
 
4270
 
 
4271
        /* NOTE that at this point rec can be an old version of a clustered
 
4272
        index record built for a consistent read. We cannot assume after this
 
4273
        point that rec is on a buffer pool page. Functions like
 
4274
        page_rec_is_comp() cannot be used! */
 
4275
 
 
4276
        if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, comp))) {
 
4277
 
 
4278
                /* The record is delete-marked: we can skip it */
 
4279
 
 
4280
                if ((srv_locks_unsafe_for_binlog
 
4281
                     || trx->isolation_level == TRX_ISO_READ_COMMITTED)
 
4282
                    && prebuilt->select_lock_type != LOCK_NONE
 
4283
                    && !did_semi_consistent_read) {
 
4284
 
 
4285
                        /* No need to keep a lock on a delete-marked record
 
4286
                        if we do not want to use next-key locking. */
 
4287
 
 
4288
                        row_unlock_for_mysql(prebuilt, TRUE);
 
4289
                }
 
4290
 
 
4291
                /* This is an optimization to skip setting the next key lock
 
4292
                on the record that follows this delete-marked record. This
 
4293
                optimization works because of the unique search criteria
 
4294
                which precludes the presence of a range lock between this
 
4295
                delete marked record and the record following it.
 
4296
 
 
4297
                For now this is applicable only to clustered indexes while
 
4298
                doing a unique search. There is scope for further optimization
 
4299
                applicable to unique secondary indexes. Current behaviour is
 
4300
                to widen the scope of a lock on an already delete marked record
 
4301
                if the same record is deleted twice by the same transaction */
 
4302
                if (index == clust_index && unique_search) {
 
4303
                        err = DB_RECORD_NOT_FOUND;
 
4304
 
 
4305
                        goto normal_return;
 
4306
                }
 
4307
 
 
4308
                goto next_rec;
 
4309
        }
 
4310
 
 
4311
idx_cond_check:
 
4312
        if (prebuilt->idx_cond_func)
 
4313
        {
 
4314
          int res;
 
4315
          ut_ad(prebuilt->template_type != ROW_DRIZZLE_DUMMY_TEMPLATE);
 
4316
          offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
 
4317
          row_sel_store_mysql_rec(buf, prebuilt, rec,
 
4318
                                  offsets, 0, prebuilt->n_index_fields);
 
4319
          res= prebuilt->idx_cond_func(prebuilt->idx_cond_func_arg);
 
4320
          if (res == 0)
 
4321
            goto next_rec;
 
4322
          if (res == 2)
 
4323
          {
 
4324
            err = DB_RECORD_NOT_FOUND;
 
4325
            goto idx_cond_failed;
 
4326
          }
 
4327
        }
 
4328
 
 
4329
        /* Get the clustered index record if needed, if we did not do the
 
4330
        search using the clustered index. */
 
4331
 
 
4332
        if (get_clust_rec || (index != clust_index &&
 
4333
            prebuilt->need_to_access_clustered)) {
 
4334
 
 
4335
                /* We use a 'goto' to the preceding label if a consistent
 
4336
                read of a secondary index record requires us to look up old
 
4337
                versions of the associated clustered index record. */
 
4338
 
 
4339
                ut_ad(rec_offs_validate(rec, index, offsets));
 
4340
 
 
4341
                /* It was a non-clustered index and we must fetch also the
 
4342
                clustered index record */
 
4343
 
 
4344
                mtr_has_extra_clust_latch = TRUE;
 
4345
 
 
4346
                /* The following call returns 'offsets' associated with
 
4347
                'clust_rec'. Note that 'clust_rec' can be an old version
 
4348
                built for a consistent read. */
 
4349
 
 
4350
                err = row_sel_get_clust_rec_for_mysql(prebuilt, index, rec,
 
4351
                                                      thr, &clust_rec,
 
4352
                                                      &offsets, &heap, &mtr);
 
4353
                if (err != DB_SUCCESS) {
 
4354
 
 
4355
                        goto lock_wait_or_error;
 
4356
                }
 
4357
 
 
4358
                if (clust_rec == NULL) {
 
4359
                        /* The record did not exist in the read view */
 
4360
                        ut_ad(prebuilt->select_lock_type == LOCK_NONE);
 
4361
 
 
4362
                        goto next_rec;
 
4363
                }
 
4364
 
 
4365
                if (UNIV_UNLIKELY(rec_get_deleted_flag(clust_rec, comp))) {
 
4366
 
 
4367
                        /* The record is delete marked: we can skip it */
 
4368
 
 
4369
                        if ((srv_locks_unsafe_for_binlog
 
4370
                             || trx->isolation_level == TRX_ISO_READ_COMMITTED)
 
4371
                            && prebuilt->select_lock_type != LOCK_NONE) {
 
4372
 
 
4373
                                /* No need to keep a lock on a delete-marked
 
4374
                                record if we do not want to use next-key
 
4375
                                locking. */
 
4376
 
 
4377
                                row_unlock_for_mysql(prebuilt, TRUE);
 
4378
                        }
 
4379
 
 
4380
                        goto next_rec;
 
4381
                }
 
4382
 
 
4383
                if (prebuilt->need_to_access_clustered) {
 
4384
 
 
4385
                        result_rec = clust_rec;
 
4386
 
 
4387
                        ut_ad(rec_offs_validate(result_rec, clust_index,
 
4388
                                                offsets));
 
4389
                } else {
 
4390
                        /* We used 'offsets' for the clust rec, recalculate
 
4391
                        them for 'rec' */
 
4392
                        offsets = rec_get_offsets(rec, index, offsets,
 
4393
                                                  ULINT_UNDEFINED, &heap);
 
4394
                        result_rec = rec;
 
4395
                }
 
4396
        } else {
 
4397
                result_rec = rec;
 
4398
        }
 
4399
 
 
4400
        /* We found a qualifying record 'result_rec'. At this point,
 
4401
        'offsets' are associated with 'result_rec'. */
 
4402
 
 
4403
        ut_ad(rec_offs_validate(result_rec,
 
4404
                                result_rec != rec ? clust_index : index,
 
4405
                                offsets));
 
4406
 
 
4407
        /* At this point, the clustered index record is protected
 
4408
        by a page latch that was acquired when pcur was positioned.
 
4409
        The latch will not be released until mtr_commit(&mtr). */
 
4410
 
 
4411
        if ((match_mode == ROW_SEL_EXACT
 
4412
             || prebuilt->n_rows_fetched >= MYSQL_FETCH_CACHE_THRESHOLD)
 
4413
            && prebuilt->select_lock_type == LOCK_NONE
 
4414
            && !prebuilt->templ_contains_blob
 
4415
            && !prebuilt->clust_index_was_generated
 
4416
            && !prebuilt->used_in_HANDLER
 
4417
            && prebuilt->template_type
 
4418
            != ROW_MYSQL_DUMMY_TEMPLATE) {
 
4419
 
 
4420
                /* Inside an update, for example, we do not cache rows,
 
4421
                since we may use the cursor position to do the actual
 
4422
                update, that is why we require ...lock_type == LOCK_NONE.
 
4423
                Since we keep space in prebuilt only for the BLOBs of
 
4424
                a single row, we cannot cache rows in the case there
 
4425
                are BLOBs in the fields to be fetched. In HANDLER we do
 
4426
                not cache rows because there the cursor is a scrollable
 
4427
                cursor. */
 
4428
                some_fields_in_buffer= (index != clust_index &&
 
4429
                                        prebuilt->idx_cond_func);
 
4430
 
 
4431
                row_sel_push_cache_row_for_mysql(prebuilt, result_rec,
 
4432
                                                 offsets,
 
4433
                                                 some_fields_in_buffer?
 
4434
                                                 prebuilt->n_index_fields: 0,
 
4435
                                                 buf);
 
4436
                if (prebuilt->n_fetch_cached == MYSQL_FETCH_CACHE_SIZE) {
 
4437
 
 
4438
                        goto got_row;
 
4439
                }
 
4440
 
 
4441
                goto next_rec;
 
4442
        } else {
 
4443
                if (prebuilt->template_type == ROW_MYSQL_DUMMY_TEMPLATE) {
 
4444
                        memcpy(buf + 4, result_rec
 
4445
                               - rec_offs_extra_size(offsets),
 
4446
                               rec_offs_size(offsets));
 
4447
                        mach_write_to_4(buf,
 
4448
                                        rec_offs_extra_size(offsets) + 4);
 
4449
                } else {
 
4450
                        if (!row_sel_store_mysql_rec(buf, prebuilt,
 
4451
                                                     result_rec, offsets,
 
4452
                                                     prebuilt->idx_cond_func?
 
4453
                                                     prebuilt->n_index_fields: 0,
 
4454
                                                     prebuilt->n_template)) {
 
4455
                                err = DB_TOO_BIG_RECORD;
 
4456
 
 
4457
                                goto lock_wait_or_error;
 
4458
                        }
 
4459
                }
 
4460
 
 
4461
                if (prebuilt->clust_index_was_generated) {
 
4462
                        if (result_rec != rec) {
 
4463
                                offsets = rec_get_offsets(
 
4464
                                        rec, index, offsets, ULINT_UNDEFINED,
 
4465
                                        &heap);
 
4466
                        }
 
4467
                        row_sel_store_row_id_to_prebuilt(prebuilt, rec,
 
4468
                                                         index, offsets);
 
4469
                }
 
4470
        }
 
4471
 
 
4472
        /* From this point on, 'offsets' are invalid. */
 
4473
 
 
4474
got_row:
 
4475
        /* We have an optimization to save CPU time: if this is a consistent
 
4476
        read on a unique condition on the clustered index, then we do not
 
4477
        store the pcur position, because any fetch next or prev will anyway
 
4478
        return 'end of file'. Exceptions are locking reads and the MySQL
 
4479
        HANDLER command where the user can move the cursor with PREV or NEXT
 
4480
        even after a unique search. */
 
4481
 
 
4482
idx_cond_failed:
 
4483
        if (!unique_search_from_clust_index
 
4484
            || prebuilt->select_lock_type != LOCK_NONE
 
4485
            || prebuilt->used_in_HANDLER) {
 
4486
 
 
4487
                /* Inside an update always store the cursor position */
 
4488
 
 
4489
                btr_pcur_store_position(pcur, &mtr);
 
4490
        }
 
4491
 
 
4492
        err = DB_SUCCESS;
 
4493
 
 
4494
        goto normal_return;
 
4495
 
 
4496
next_rec:
 
4497
        /* Reset the old and new "did semi-consistent read" flags. */
 
4498
        if (UNIV_UNLIKELY(prebuilt->row_read_type
 
4499
                          == ROW_READ_DID_SEMI_CONSISTENT)) {
 
4500
                prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
 
4501
        }
 
4502
        did_semi_consistent_read = FALSE;
 
4503
 
 
4504
        if (UNIV_UNLIKELY(srv_locks_unsafe_for_binlog
 
4505
                          || trx->isolation_level == TRX_ISO_READ_COMMITTED)
 
4506
            && prebuilt->select_lock_type != LOCK_NONE) {
 
4507
 
 
4508
                trx_reset_new_rec_lock_info(trx);
 
4509
        }
 
4510
 
 
4511
        /*-------------------------------------------------------------*/
 
4512
        /* PHASE 5: Move the cursor to the next index record */
 
4513
 
 
4514
        if (UNIV_UNLIKELY(mtr_has_extra_clust_latch)) {
 
4515
                /* We must commit mtr if we are moving to the next
 
4516
                non-clustered index record, because we could break the
 
4517
                latching order if we would access a different clustered
 
4518
                index page right away without releasing the previous. */
 
4519
 
 
4520
                btr_pcur_store_position(pcur, &mtr);
 
4521
 
 
4522
                mtr_commit(&mtr);
 
4523
                mtr_has_extra_clust_latch = FALSE;
 
4524
 
 
4525
                mtr_start(&mtr);
 
4526
                if (sel_restore_position_for_mysql(&same_user_rec,
 
4527
                                                   BTR_SEARCH_LEAF,
 
4528
                                                   pcur, moves_up, &mtr)) {
 
4529
#ifdef UNIV_SEARCH_DEBUG
 
4530
                        cnt++;
 
4531
#endif /* UNIV_SEARCH_DEBUG */
 
4532
 
 
4533
                        goto rec_loop;
 
4534
                }
 
4535
        }
 
4536
 
 
4537
        if (moves_up) {
 
4538
                if (UNIV_UNLIKELY(!btr_pcur_move_to_next(pcur, &mtr))) {
 
4539
not_moved:
 
4540
                        btr_pcur_store_position(pcur, &mtr);
 
4541
 
 
4542
                        if (match_mode != 0) {
 
4543
                                err = DB_RECORD_NOT_FOUND;
 
4544
                        } else {
 
4545
                                err = DB_END_OF_INDEX;
 
4546
                        }
 
4547
 
 
4548
                        goto normal_return;
 
4549
                }
 
4550
        } else {
 
4551
                if (UNIV_UNLIKELY(!btr_pcur_move_to_prev(pcur, &mtr))) {
 
4552
                        goto not_moved;
 
4553
                }
 
4554
        }
 
4555
 
 
4556
#ifdef UNIV_SEARCH_DEBUG
 
4557
        cnt++;
 
4558
#endif /* UNIV_SEARCH_DEBUG */
 
4559
 
 
4560
        goto rec_loop;
 
4561
 
 
4562
lock_wait_or_error:
 
4563
        /* Reset the old and new "did semi-consistent read" flags. */
 
4564
        if (UNIV_UNLIKELY(prebuilt->row_read_type
 
4565
                          == ROW_READ_DID_SEMI_CONSISTENT)) {
 
4566
                prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
 
4567
        }
 
4568
        did_semi_consistent_read = FALSE;
 
4569
 
 
4570
        /*-------------------------------------------------------------*/
 
4571
 
 
4572
        btr_pcur_store_position(pcur, &mtr);
 
4573
 
 
4574
        mtr_commit(&mtr);
 
4575
        mtr_has_extra_clust_latch = FALSE;
 
4576
 
 
4577
        trx->error_state = err;
 
4578
 
 
4579
        /* The following is a patch for MySQL */
 
4580
 
 
4581
        que_thr_stop_for_mysql(thr);
 
4582
 
 
4583
        thr->lock_state = QUE_THR_LOCK_ROW;
 
4584
 
 
4585
        if (row_mysql_handle_errors(&err, trx, thr, NULL)) {
 
4586
                /* It was a lock wait, and it ended */
 
4587
 
 
4588
                thr->lock_state = QUE_THR_LOCK_NOLOCK;
 
4589
                mtr_start(&mtr);
 
4590
 
 
4591
                sel_restore_position_for_mysql(&same_user_rec,
 
4592
                                               BTR_SEARCH_LEAF, pcur,
 
4593
                                               moves_up, &mtr);
 
4594
 
 
4595
                if ((srv_locks_unsafe_for_binlog
 
4596
                     || trx->isolation_level == TRX_ISO_READ_COMMITTED)
 
4597
                    && !same_user_rec) {
 
4598
 
 
4599
                        /* Since we were not able to restore the cursor
 
4600
                        on the same user record, we cannot use
 
4601
                        row_unlock_for_mysql() to unlock any records, and
 
4602
                        we must thus reset the new rec lock info. Since
 
4603
                        in lock0lock.c we have blocked the inheriting of gap
 
4604
                        X-locks, we actually do not have any new record locks
 
4605
                        set in this case.
 
4606
 
 
4607
                        Note that if we were able to restore on the 'same'
 
4608
                        user record, it is still possible that we were actually
 
4609
                        waiting on a delete-marked record, and meanwhile
 
4610
                        it was removed by purge and inserted again by some
 
4611
                        other user. But that is no problem, because in
 
4612
                        rec_loop we will again try to set a lock, and
 
4613
                        new_rec_lock_info in trx will be right at the end. */
 
4614
 
 
4615
                        trx_reset_new_rec_lock_info(trx);
 
4616
                }
 
4617
 
 
4618
                mode = pcur->search_mode;
 
4619
 
 
4620
                goto rec_loop;
 
4621
        }
 
4622
 
 
4623
        thr->lock_state = QUE_THR_LOCK_NOLOCK;
 
4624
 
 
4625
#ifdef UNIV_SEARCH_DEBUG
 
4626
        /*      fputs("Using ", stderr);
 
4627
        dict_index_name_print(stderr, index);
 
4628
        fprintf(stderr, " cnt %lu ret value %lu err\n", cnt, err); */
 
4629
#endif /* UNIV_SEARCH_DEBUG */
 
4630
        goto func_exit;
 
4631
 
 
4632
normal_return:
 
4633
        /*-------------------------------------------------------------*/
 
4634
        que_thr_stop_for_mysql_no_error(thr, trx);
 
4635
 
 
4636
        mtr_commit(&mtr);
 
4637
 
 
4638
        if (prebuilt->n_fetch_cached > 0) {
 
4639
                row_sel_pop_cached_row_for_mysql(buf, prebuilt);
 
4640
 
 
4641
                err = DB_SUCCESS;
 
4642
        }
 
4643
 
 
4644
#ifdef UNIV_SEARCH_DEBUG
 
4645
        /*      fputs("Using ", stderr);
 
4646
        dict_index_name_print(stderr, index);
 
4647
        fprintf(stderr, " cnt %lu ret value %lu err\n", cnt, err); */
 
4648
#endif /* UNIV_SEARCH_DEBUG */
 
4649
        if (err == DB_SUCCESS) {
 
4650
                srv_n_rows_read++;
 
4651
        }
 
4652
 
 
4653
func_exit:
 
4654
        trx->op_info = "";
 
4655
        if (UNIV_LIKELY_NULL(heap)) {
 
4656
                mem_heap_free(heap);
 
4657
        }
 
4658
 
 
4659
        /* Set or reset the "did semi-consistent read" flag on return.
 
4660
        The flag did_semi_consistent_read is set if and only if
 
4661
        the record being returned was fetched with a semi-consistent read. */
 
4662
        ut_ad(prebuilt->row_read_type != ROW_READ_WITH_LOCKS
 
4663
              || !did_semi_consistent_read);
 
4664
 
 
4665
        if (UNIV_UNLIKELY(prebuilt->row_read_type != ROW_READ_WITH_LOCKS)) {
 
4666
                if (UNIV_UNLIKELY(did_semi_consistent_read)) {
 
4667
                        prebuilt->row_read_type = ROW_READ_DID_SEMI_CONSISTENT;
 
4668
                } else {
 
4669
                        prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
 
4670
                }
 
4671
        }
 
4672
        return(err);
 
4673
}
 
4674
 
 
4675
/***********************************************************************
 
4676
Checks if MySQL at the moment is allowed for this table to retrieve a
 
4677
consistent read result, or store it to the query cache. */
 
4678
UNIV_INTERN
 
4679
ibool
 
4680
row_search_check_if_query_cache_permitted(
 
4681
/*======================================*/
 
4682
                                        /* out: TRUE if storing or retrieving
 
4683
                                        from the query cache is permitted */
 
4684
        trx_t*          trx,            /* in: transaction object */
 
4685
        const char*     norm_name)      /* in: concatenation of database name,
 
4686
                                        '/' char, table name */
 
4687
{
 
4688
        dict_table_t*   table;
 
4689
        ibool           ret     = FALSE;
 
4690
 
 
4691
        table = dict_table_get(norm_name, FALSE);
 
4692
 
 
4693
        if (table == NULL) {
 
4694
 
 
4695
                return(FALSE);
 
4696
        }
 
4697
 
 
4698
        mutex_enter(&kernel_mutex);
 
4699
 
 
4700
        /* Start the transaction if it is not started yet */
 
4701
 
 
4702
        trx_start_if_not_started_low(trx);
 
4703
 
 
4704
        /* If there are locks on the table or some trx has invalidated the
 
4705
        cache up to our trx id, then ret = FALSE.
 
4706
        We do not check what type locks there are on the table, though only
 
4707
        IX type locks actually would require ret = FALSE. */
 
4708
 
 
4709
        if (UT_LIST_GET_LEN(table->locks) == 0
 
4710
            && ut_dulint_cmp(trx->id,
 
4711
                             table->query_cache_inv_trx_id) >= 0) {
 
4712
 
 
4713
                ret = TRUE;
 
4714
 
 
4715
                /* If the isolation level is high, assign a read view for the
 
4716
                transaction if it does not yet have one */
 
4717
 
 
4718
                if (trx->isolation_level >= TRX_ISO_REPEATABLE_READ
 
4719
                    && !trx->read_view) {
 
4720
 
 
4721
                        trx->read_view = read_view_open_now(
 
4722
                                trx->id, trx->global_read_view_heap);
 
4723
                        trx->global_read_view = trx->read_view;
 
4724
                }
 
4725
        }
 
4726
 
 
4727
        mutex_exit(&kernel_mutex);
 
4728
 
 
4729
        return(ret);
 
4730
}
 
4731
 
 
4732
/***********************************************************************
 
4733
Read the AUTOINC column from the current row. If the value is less than
 
4734
0 and the type is not unsigned then we reset the value to 0. */
 
4735
static
 
4736
ib_uint64_t
 
4737
row_search_autoinc_read_column(
 
4738
/*===========================*/
 
4739
                                        /* out: value read from the column */
 
4740
        dict_index_t*   index,          /* in: index to read from */
 
4741
        const rec_t*    rec,            /* in: current rec */
 
4742
        ulint           col_no,         /* in: column number */
 
4743
        ibool           unsigned_type)  /* in: signed or unsigned flag */
 
4744
{
 
4745
        ulint           len;
 
4746
        const byte*     data;
 
4747
        ib_uint64_t     value;
 
4748
        mem_heap_t*     heap = NULL;
 
4749
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
 
4750
        ulint*          offsets = offsets_;
 
4751
 
 
4752
        rec_offs_init(offsets_);
 
4753
 
 
4754
        offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
 
4755
 
 
4756
        data = rec_get_nth_field(rec, offsets, col_no, &len);
 
4757
 
 
4758
        ut_a(len != UNIV_SQL_NULL);
 
4759
        ut_a(len <= sizeof value);
 
4760
 
 
4761
        /* we assume AUTOINC value cannot be negative */
 
4762
        value = mach_read_int_type(data, len, unsigned_type);
 
4763
 
 
4764
        if (UNIV_LIKELY_NULL(heap)) {
 
4765
                mem_heap_free(heap);
 
4766
        }
 
4767
 
 
4768
        if (!unsigned_type && (ib_int64_t) value < 0) {
 
4769
                value = 0;
 
4770
        }
 
4771
 
 
4772
        return(value);
 
4773
}
 
4774
 
 
4775
/***********************************************************************
 
4776
Get the last row. */
 
4777
static
 
4778
const rec_t*
 
4779
row_search_autoinc_get_rec(
 
4780
/*=======================*/
 
4781
                                        /* out: current rec or NULL */
 
4782
        btr_pcur_t*     pcur,           /* in: the current cursor */
 
4783
        mtr_t*          mtr)            /* in: mini transaction */
 
4784
{
 
4785
        do {
 
4786
                const rec_t* rec = btr_pcur_get_rec(pcur);
 
4787
 
 
4788
                if (page_rec_is_user_rec(rec)) {
 
4789
                        return(rec);
 
4790
                }
 
4791
        } while (btr_pcur_move_to_prev(pcur, mtr));
 
4792
 
 
4793
        return(NULL);
 
4794
}
 
4795
 
 
4796
/***********************************************************************
 
4797
Read the max AUTOINC value from an index. */
 
4798
UNIV_INTERN
 
4799
ulint
 
4800
row_search_max_autoinc(
 
4801
/*===================*/
 
4802
                                        /* out: DB_SUCCESS if all OK else
 
4803
                                        error code, DB_RECORD_NOT_FOUND if
 
4804
                                        column name can't be found in index */
 
4805
        dict_index_t*   index,          /* in: index to search */
 
4806
        const char*     col_name,       /* in: name of autoinc column */
 
4807
        ib_uint64_t*    value)          /* out: AUTOINC value read */
 
4808
{
 
4809
        ulint           i;
 
4810
        ulint           n_cols;
 
4811
        dict_field_t*   dfield = NULL;
 
4812
        ulint           error = DB_SUCCESS;
 
4813
 
 
4814
        n_cols = dict_index_get_n_ordering_defined_by_user(index);
 
4815
 
 
4816
        /* Search the index for the AUTOINC column name */
 
4817
        for (i = 0; i < n_cols; ++i) {
 
4818
                dfield = dict_index_get_nth_field(index, i);
 
4819
 
 
4820
                if (strcmp(col_name, dfield->name) == 0) {
 
4821
                        break;
 
4822
                }
 
4823
        }
 
4824
 
 
4825
        *value = 0;
 
4826
 
 
4827
        /* Must find the AUTOINC column name */
 
4828
        if (i < n_cols && dfield) {
 
4829
                mtr_t           mtr;
 
4830
                btr_pcur_t      pcur;
 
4831
 
 
4832
                mtr_start(&mtr);
 
4833
 
 
4834
                /* Open at the high/right end (FALSE), and INIT
 
4835
                cursor (TRUE) */
 
4836
                btr_pcur_open_at_index_side(
 
4837
                        FALSE, index, BTR_SEARCH_LEAF, &pcur, TRUE, &mtr);
 
4838
 
 
4839
                if (page_get_n_recs(btr_pcur_get_page(&pcur)) > 0) {
 
4840
                        const rec_t*    rec;
 
4841
 
 
4842
                        rec = row_search_autoinc_get_rec(&pcur, &mtr);
 
4843
 
 
4844
                        if (rec != NULL) {
 
4845
                                ibool unsigned_type = (
 
4846
                                        dfield->col->prtype & DATA_UNSIGNED);
 
4847
 
 
4848
                                *value = row_search_autoinc_read_column(
 
4849
                                        index, rec, i, unsigned_type);
 
4850
                        }
 
4851
                }
 
4852
 
 
4853
                btr_pcur_close(&pcur);
 
4854
 
 
4855
                mtr_commit(&mtr);
 
4856
        } else {
 
4857
                error = DB_RECORD_NOT_FOUND;
 
4858
        }
 
4859
 
 
4860
        return(error);
 
4861
}