~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: David Axmark
  • Date: 2008-11-05 05:50:56 UTC
  • mto: (584.1.3 devel)
  • mto: This revision was merged to the branch mainline in revision 586.
  • Revision ID: davida@davids-laptop-20081105055056-bt8ajhvihu0j28kp
Changed NEWDATE to DATE. One failing test but I think its somewhere else in the code 
(func_math).

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
 
}