~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

Show diffs side-by-side

added added

removed removed

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