~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Monty Taylor
  • Date: 2009-04-14 19:16:51 UTC
  • mto: (997.2.5 mordred)
  • mto: This revision was merged to the branch mainline in revision 994.
  • Revision ID: mordred@inaugust.com-20090414191651-ltbww6hpqks8k7qk
Clarified instructions in README.

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
 
24
24
*****************************************************************************/
25
25
 
26
 
/***************************************************//**
27
 
@file row/row0sel.c
 
26
/*******************************************************
28
27
Select
29
28
 
30
29
Created 12/19/1997 Heikki Tuuri
75
74
#define SEL_EXHAUSTED   1
76
75
#define SEL_RETRY       2
77
76
 
78
 
/********************************************************************//**
 
77
/************************************************************************
79
78
Returns TRUE if the user-defined column in a secondary index record
80
79
is alphabetically the same as the corresponding BLOB column in the clustered
81
80
index record.
82
81
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 */
 
82
fields are compared with collation! */
85
83
static
86
84
ibool
87
85
row_sel_sec_rec_is_for_blob(
88
86
/*========================*/
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
 
87
                                        /* out: TRUE if the columns
 
88
                                        are equal */
 
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
96
                                        the clustered index column, including
97
97
                                        the BLOB pointer; the clustered
98
98
                                        index record must be covered by
99
99
                                        a lock or a page latch to protect it
100
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 */
 
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
105
{
106
106
        ulint   len;
107
107
        byte    buf[DICT_MAX_INDEX_COL_LEN];
125
125
        return(!cmp_data_data(mtype, prtype, buf, len, sec_field, sec_len));
126
126
}
127
127
 
128
 
/********************************************************************//**
 
128
/************************************************************************
129
129
Returns TRUE if the user-defined column values in a secondary index record
130
130
are alphabetically the same as the corresponding columns in the clustered
131
131
index record.
132
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 */
 
133
fields are compared with collation! */
136
134
static
137
135
ibool
138
136
row_sel_sec_rec_is_for_clust_rec(
139
137
/*=============================*/
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;
 
138
                                        /* out: TRUE if the secondary
 
139
                                        record is equal to the corresponding
 
140
                                        fields in the clustered record,
 
141
                                        when compared with collation */
 
142
        const rec_t*    sec_rec,        /* in: secondary index record */
 
143
        dict_index_t*   sec_index,      /* in: secondary index */
 
144
        const rec_t*    clust_rec,      /* in: clustered index record;
143
145
                                        must be protected by a lock or
144
146
                                        a page latch against deletion
145
147
                                        in rollback or purge */
146
 
        dict_index_t*   clust_index)    /*!< in: clustered index */
 
148
        dict_index_t*   clust_index)    /* in: clustered index */
147
149
{
148
150
        const byte*     sec_field;
149
151
        ulint           sec_len;
236
238
        return(is_equal);
237
239
}
238
240
 
239
 
/*********************************************************************//**
240
 
Creates a select node struct.
241
 
@return own: select node struct */
 
241
/*************************************************************************
 
242
Creates a select node struct. */
242
243
UNIV_INTERN
243
244
sel_node_t*
244
245
sel_node_create(
245
246
/*============*/
246
 
        mem_heap_t*     heap)   /*!< in: memory heap where created */
 
247
                                /* out, own: select node struct */
 
248
        mem_heap_t*     heap)   /* in: memory heap where created */
247
249
{
248
250
        sel_node_t*     node;
249
251
 
256
258
        return(node);
257
259
}
258
260
 
259
 
/*********************************************************************//**
 
261
/*************************************************************************
260
262
Frees the memory private to a select node when a query graph is freed,
261
263
does not free the heap where the node was originally created. */
262
264
UNIV_INTERN
263
265
void
264
266
sel_node_free_private(
265
267
/*==================*/
266
 
        sel_node_t*     node)   /*!< in: select node struct */
 
268
        sel_node_t*     node)   /* in: select node struct */
267
269
{
268
270
        ulint   i;
269
271
        plan_t* plan;
282
284
        }
283
285
}
284
286
 
285
 
/*********************************************************************//**
 
287
/*************************************************************************
286
288
Evaluates the values in a select list. If there are aggregate functions,
287
289
their argument value is added to the aggregate total. */
288
290
UNIV_INLINE
289
291
void
290
292
sel_eval_select_list(
291
293
/*=================*/
292
 
        sel_node_t*     node)   /*!< in: select node */
 
294
        sel_node_t*     node)   /* in: select node */
293
295
{
294
296
        que_node_t*     exp;
295
297
 
302
304
        }
303
305
}
304
306
 
305
 
/*********************************************************************//**
 
307
/*************************************************************************
306
308
Assigns the values in the select list to the possible into-variables in
307
309
SELECT ... INTO ... */
308
310
UNIV_INLINE
309
311
void
310
312
sel_assign_into_var_values(
311
313
/*=======================*/
312
 
        sym_node_t*     var,    /*!< in: first variable in a list of variables */
313
 
        sel_node_t*     node)   /*!< in: select node */
 
314
        sym_node_t*     var,    /* in: first variable in a list of variables */
 
315
        sel_node_t*     node)   /* in: select node */
314
316
{
315
317
        que_node_t*     exp;
316
318
 
331
333
        }
332
334
}
333
335
 
334
 
/*********************************************************************//**
 
336
/*************************************************************************
335
337
Resets the aggregate value totals in the select list of an aggregate type
336
338
query. */
337
339
UNIV_INLINE
338
340
void
339
341
sel_reset_aggregate_vals(
340
342
/*=====================*/
341
 
        sel_node_t*     node)   /*!< in: select node */
 
343
        sel_node_t*     node)   /* in: select node */
342
344
{
343
345
        func_node_t*    func_node;
344
346
 
355
357
        node->aggregate_already_fetched = FALSE;
356
358
}
357
359
 
358
 
/*********************************************************************//**
 
360
/*************************************************************************
359
361
Copies the input variable values when an explicit cursor is opened. */
360
362
UNIV_INLINE
361
363
void
362
364
row_sel_copy_input_variable_vals(
363
365
/*=============================*/
364
 
        sel_node_t*     node)   /*!< in: select node */
 
366
        sel_node_t*     node)   /* in: select node */
365
367
{
366
368
        sym_node_t*     var;
367
369
 
376
378
        }
377
379
}
378
380
 
379
 
/*********************************************************************//**
 
381
/*************************************************************************
380
382
Fetches the column values from a record. */
381
383
static
382
384
void
383
385
row_sel_fetch_columns(
384
386
/*==================*/
385
 
        dict_index_t*   index,  /*!< in: record index */
386
 
        const rec_t*    rec,    /*!< in: record in a clustered or non-clustered
 
387
        dict_index_t*   index,  /* in: record index */
 
388
        const rec_t*    rec,    /* in: record in a clustered or non-clustered
387
389
                                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
        const ulint*    offsets,/* in: rec_get_offsets(rec, index) */
 
391
        sym_node_t*     column) /* in: first column in a column list, or
390
392
                                NULL */
391
393
{
392
394
        dfield_t*       val;
455
457
        }
456
458
}
457
459
 
458
 
/*********************************************************************//**
 
460
/*************************************************************************
459
461
Allocates a prefetch buffer for a column when prefetch is first time done. */
460
462
static
461
463
void
462
464
sel_col_prefetch_buf_alloc(
463
465
/*=======================*/
464
 
        sym_node_t*     column) /*!< in: symbol table node for a column */
 
466
        sym_node_t*     column) /* in: symbol table node for a column */
465
467
{
466
468
        sel_buf_t*      sel_buf;
467
469
        ulint           i;
479
481
        }
480
482
}
481
483
 
482
 
/*********************************************************************//**
 
484
/*************************************************************************
483
485
Frees a prefetch buffer for a column, including the dynamically allocated
484
486
memory for data stored there. */
485
487
UNIV_INTERN
486
488
void
487
489
sel_col_prefetch_buf_free(
488
490
/*======================*/
489
 
        sel_buf_t*      prefetch_buf)   /*!< in, own: prefetch buffer */
 
491
        sel_buf_t*      prefetch_buf)   /* in, own: prefetch buffer */
490
492
{
491
493
        sel_buf_t*      sel_buf;
492
494
        ulint           i;
501
503
        }
502
504
}
503
505
 
504
 
/*********************************************************************//**
 
506
/*************************************************************************
505
507
Pops the column values for a prefetched, cached row from the column prefetch
506
508
buffers and places them to the val fields in the column nodes. */
507
509
static
508
510
void
509
511
sel_pop_prefetched_row(
510
512
/*===================*/
511
 
        plan_t* plan)   /*!< in: plan node for a table */
 
513
        plan_t* plan)   /* in: plan node for a table */
512
514
{
513
515
        sym_node_t*     column;
514
516
        sel_buf_t*      sel_buf;
563
565
        plan->first_prefetched++;
564
566
}
565
567
 
566
 
/*********************************************************************//**
 
568
/*************************************************************************
567
569
Pushes the column values for a prefetched, cached row to the column prefetch
568
570
buffers from the val fields in the column nodes. */
569
571
UNIV_INLINE
570
572
void
571
573
sel_push_prefetched_row(
572
574
/*====================*/
573
 
        plan_t* plan)   /*!< in: plan node for a table */
 
575
        plan_t* plan)   /* in: plan node for a table */
574
576
{
575
577
        sym_node_t*     column;
576
578
        sel_buf_t*      sel_buf;
635
637
        }
636
638
}
637
639
 
638
 
/*********************************************************************//**
639
 
Builds a previous version of a clustered index record for a consistent read
640
 
@return DB_SUCCESS or error code */
 
640
/*************************************************************************
 
641
Builds a previous version of a clustered index record for a consistent read */
641
642
static
642
643
ulint
643
644
row_sel_build_prev_vers(
644
645
/*====================*/
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
 
646
                                        /* out: DB_SUCCESS or error code */
 
647
        read_view_t*    read_view,      /* in: read view */
 
648
        dict_index_t*   index,          /* in: plan node for table */
 
649
        rec_t*          rec,            /* in: record in a clustered index */
 
650
        ulint**         offsets,        /* in/out: offsets returned by
649
651
                                        rec_get_offsets(rec, plan->index) */
650
 
        mem_heap_t**    offset_heap,    /*!< in/out: memory heap from which
 
652
        mem_heap_t**    offset_heap,    /* in/out: memory heap from which
651
653
                                        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
        mem_heap_t**    old_vers_heap,  /* out: old version heap to use */
 
655
        rec_t**         old_vers,       /* out: old version, or NULL if the
654
656
                                        record does not exist in the view:
655
657
                                        i.e., it was freshly inserted
656
658
                                        afterwards */
657
 
        mtr_t*          mtr)            /*!< in: mtr */
 
659
        mtr_t*          mtr)            /* in: mtr */
658
660
{
659
661
        ulint   err;
660
662
 
670
672
        return(err);
671
673
}
672
674
 
673
 
/*********************************************************************//**
 
675
/*************************************************************************
674
676
Builds the last committed version of a clustered index record for a
675
 
semi-consistent read.
676
 
@return DB_SUCCESS or error code */
 
677
semi-consistent read. */
677
678
static
678
679
ulint
679
680
row_sel_build_committed_vers_for_mysql(
680
681
/*===================================*/
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
 
682
                                        /* out: DB_SUCCESS or error code */
 
683
        dict_index_t*   clust_index,    /* in: clustered index */
 
684
        row_prebuilt_t* prebuilt,       /* in: prebuilt struct */
 
685
        const rec_t*    rec,            /* in: record in a clustered index */
 
686
        ulint**         offsets,        /* in/out: offsets returned by
685
687
                                        rec_get_offsets(rec, clust_index) */
686
 
        mem_heap_t**    offset_heap,    /*!< in/out: memory heap from which
 
688
        mem_heap_t**    offset_heap,    /* in/out: memory heap from which
687
689
                                        the offsets are allocated */
688
 
        const rec_t**   old_vers,       /*!< out: old version, or NULL if the
 
690
        const rec_t**   old_vers,       /* out: old version, or NULL if the
689
691
                                        record does not exist in the view:
690
692
                                        i.e., it was freshly inserted
691
693
                                        afterwards */
692
 
        mtr_t*          mtr)            /*!< in: mtr */
 
694
        mtr_t*          mtr)            /* in: mtr */
693
695
{
694
696
        ulint   err;
695
697
 
705
707
        return(err);
706
708
}
707
709
 
708
 
/*********************************************************************//**
 
710
/*************************************************************************
709
711
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
through has been exhausted. */
712
713
UNIV_INLINE
713
714
ibool
714
715
row_sel_test_end_conds(
715
716
/*===================*/
716
 
        plan_t* plan)   /*!< in: plan for the table; the column values must
 
717
                        /* out: TRUE if row passed the tests */
 
718
        plan_t* plan)   /* in: plan for the table; the column values must
717
719
                        already have been retrieved and the right sides of
718
720
                        comparisons evaluated */
719
721
{
743
745
        return(TRUE);
744
746
}
745
747
 
746
 
/*********************************************************************//**
747
 
Tests the other conditions.
748
 
@return TRUE if row passed the tests */
 
748
/*************************************************************************
 
749
Tests the other conditions. */
749
750
UNIV_INLINE
750
751
ibool
751
752
row_sel_test_other_conds(
752
753
/*=====================*/
753
 
        plan_t* plan)   /*!< in: plan for the table; the column values must
 
754
                        /* out: TRUE if row passed the tests */
 
755
        plan_t* plan)   /* in: plan for the table; the column values must
754
756
                        already have been retrieved */
755
757
{
756
758
        func_node_t*    cond;
771
773
        return(TRUE);
772
774
}
773
775
 
774
 
/*********************************************************************//**
 
776
/*************************************************************************
775
777
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
non-clustered index. Does the necessary locking. */
778
779
static
779
780
ulint
780
781
row_sel_get_clust_rec(
781
782
/*==================*/
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
 
783
                                /* out: DB_SUCCESS or error code */
 
784
        sel_node_t*     node,   /* in: select_node */
 
785
        plan_t*         plan,   /* in: plan node for table */
 
786
        rec_t*          rec,    /* in: record in a non-clustered index */
 
787
        que_thr_t*      thr,    /* in: query thread */
 
788
        rec_t**         out_rec,/* out: clustered record or an old version of
787
789
                                it, NULL if the old version did not exist
788
790
                                in the read view, i.e., it was a fresh
789
791
                                inserted version */
790
 
        mtr_t*          mtr)    /*!< in: mtr used to get access to the
 
792
        mtr_t*          mtr)    /* in: mtr used to get access to the
791
793
                                non-clustered record; the same mtr is used to
792
794
                                access the clustered index */
793
795
{
935
937
        return(err);
936
938
}
937
939
 
938
 
/*********************************************************************//**
939
 
Sets a lock on a record.
940
 
@return DB_SUCCESS or error code */
 
940
/*************************************************************************
 
941
Sets a lock on a record. */
941
942
UNIV_INLINE
942
943
ulint
943
944
sel_set_rec_lock(
944
945
/*=============*/
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
 
946
                                        /* out: DB_SUCCESS or error code */
 
947
        const buf_block_t*      block,  /* in: buffer block of rec */
 
948
        const rec_t*            rec,    /* in: record */
 
949
        dict_index_t*           index,  /* in: index */
 
950
        const ulint*            offsets,/* in: rec_get_offsets(rec, index) */
 
951
        ulint                   mode,   /* in: lock mode */
 
952
        ulint                   type,   /* in: LOCK_ORDINARY, LOCK_GAP, or
951
953
                                        LOC_REC_NOT_GAP */
952
 
        que_thr_t*              thr)    /*!< in: query thread */
 
954
        que_thr_t*              thr)    /* in: query thread */
953
955
{
954
956
        trx_t*  trx;
955
957
        ulint   err;
974
976
        return(err);
975
977
}
976
978
 
977
 
/*********************************************************************//**
 
979
/*************************************************************************
978
980
Opens a pcur to a table index. */
979
981
static
980
982
void
981
983
row_sel_open_pcur(
982
984
/*==============*/
983
 
        plan_t*         plan,           /*!< in: table plan */
 
985
        plan_t*         plan,           /* in: table plan */
984
986
        ibool           search_latch_locked,
985
 
                                        /*!< in: TRUE if the thread currently
 
987
                                        /* in: TRUE if the thread currently
986
988
                                        has the search latch locked in
987
989
                                        s-mode */
988
 
        mtr_t*          mtr)            /*!< in: mtr */
 
990
        mtr_t*          mtr)            /* in: mtr */
989
991
{
990
992
        dict_index_t*   index;
991
993
        func_node_t*    cond;
1049
1051
        plan->pcur_is_open = TRUE;
1050
1052
}
1051
1053
 
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 */
 
1054
/*************************************************************************
 
1055
Restores a stored pcur position to a table index. */
1058
1056
static
1059
1057
ibool
1060
1058
row_sel_restore_pcur_pos(
1061
1059
/*=====================*/
1062
 
        plan_t*         plan,   /*!< in: table plan */
1063
 
        mtr_t*          mtr)    /*!< in: mtr */
 
1060
                                /* out: TRUE if the cursor should be moved to
 
1061
                                the next record after we return from this
 
1062
                                function (moved to the previous, in the case
 
1063
                                of a descending cursor) without processing
 
1064
                                again the current cursor record */
 
1065
        plan_t*         plan,   /* in: table plan */
 
1066
        mtr_t*          mtr)    /* in: mtr */
1064
1067
{
1065
1068
        ibool   equal_position;
1066
1069
        ulint   relative_position;
1144
1147
        return(TRUE);
1145
1148
}
1146
1149
 
1147
 
/*********************************************************************//**
 
1150
/*************************************************************************
1148
1151
Resets a plan cursor to a closed state. */
1149
1152
UNIV_INLINE
1150
1153
void
1151
1154
plan_reset_cursor(
1152
1155
/*==============*/
1153
 
        plan_t* plan)   /*!< in: plan */
 
1156
        plan_t* plan)   /* in: plan */
1154
1157
{
1155
1158
        plan->pcur_is_open = FALSE;
1156
1159
        plan->cursor_at_end = FALSE;
1158
1161
        plan->n_rows_prefetched = 0;
1159
1162
}
1160
1163
 
1161
 
/*********************************************************************//**
 
1164
/*************************************************************************
1162
1165
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 */
 
1166
using the hash index if possible (not always). */
1165
1167
static
1166
1168
ulint
1167
1169
row_sel_try_search_shortcut(
1168
1170
/*========================*/
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
                                /* out: SEL_FOUND, SEL_EXHAUSTED, SEL_RETRY */
 
1172
        sel_node_t*     node,   /* in: select node for a consistent read */
 
1173
        plan_t*         plan,   /* in: plan for a unique search in clustered
1171
1174
                                index */
1172
 
        mtr_t*          mtr)    /*!< in: mtr */
 
1175
        mtr_t*          mtr)    /* in: mtr */
1173
1176
{
1174
1177
        dict_index_t*   index;
1175
1178
        rec_t*          rec;
1260
1263
        return(ret);
1261
1264
}
1262
1265
 
1263
 
/*********************************************************************//**
1264
 
Performs a select step.
1265
 
@return DB_SUCCESS or error code */
 
1266
/*************************************************************************
 
1267
Performs a select step. */
1266
1268
static
1267
1269
ulint
1268
1270
row_sel(
1269
1271
/*====*/
1270
 
        sel_node_t*     node,   /*!< in: select node */
1271
 
        que_thr_t*      thr)    /*!< in: query thread */
 
1272
                                /* out: DB_SUCCESS or error code */
 
1273
        sel_node_t*     node,   /* in: select node */
 
1274
        que_thr_t*      thr)    /* in: query thread */
1272
1275
{
1273
1276
        dict_index_t*   index;
1274
1277
        plan_t*         plan;
1689
1692
                goto next_rec;
1690
1693
        }
1691
1694
 
 
1695
 
1692
1696
        /* PHASE 5: Get the clustered index record, if needed and if we did
1693
1697
        not do the search using the clustered index */
1694
1698
 
1961
1965
        return(err);
1962
1966
}
1963
1967
 
1964
 
/**********************************************************************//**
 
1968
/**************************************************************************
1965
1969
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 */
 
1970
graphs. */
1968
1971
UNIV_INTERN
1969
1972
que_thr_t*
1970
1973
row_sel_step(
1971
1974
/*=========*/
1972
 
        que_thr_t*      thr)    /*!< in: query thread */
 
1975
                                /* out: query thread to run next or NULL */
 
1976
        que_thr_t*      thr)    /* in: query thread */
1973
1977
{
1974
1978
        ulint           i_lock_mode;
1975
1979
        sym_node_t*     table_node;
2063
2067
        return(thr);
2064
2068
}
2065
2069
 
2066
 
/**********************************************************************//**
2067
 
Performs a fetch for a cursor.
2068
 
@return query thread to run next or NULL */
 
2070
/**************************************************************************
 
2071
Performs a fetch for a cursor. */
2069
2072
UNIV_INTERN
2070
2073
que_thr_t*
2071
2074
fetch_step(
2072
2075
/*=======*/
2073
 
        que_thr_t*      thr)    /*!< in: query thread */
 
2076
                                /* out: query thread to run next or NULL */
 
2077
        que_thr_t*      thr)    /* in: query thread */
2074
2078
{
2075
2079
        sel_node_t*     sel_node;
2076
2080
        fetch_node_t*   node;
2126
2130
        return(thr);
2127
2131
}
2128
2132
 
2129
 
/****************************************************************//**
2130
 
Sample callback function for fetch that prints each row.
2131
 
@return always returns non-NULL */
 
2133
/********************************************************************
 
2134
Sample callback function for fetch that prints each row.*/
2132
2135
UNIV_INTERN
2133
2136
void*
2134
2137
row_fetch_print(
2135
2138
/*============*/
2136
 
        void*   row,            /*!< in:  sel_node_t* */
2137
 
        void*   user_arg)       /*!< in:  not used */
 
2139
                                /* out: always returns non-NULL */
 
2140
        void*   row,            /* in:  sel_node_t* */
 
2141
        void*   user_arg)       /* in:  not used */
2138
2142
{
2139
2143
        sel_node_t*     node = row;
2140
2144
        que_node_t*     exp;
2170
2174
        return((void*)42);
2171
2175
}
2172
2176
 
2173
 
/****************************************************************//**
 
2177
/********************************************************************
2174
2178
Callback function for fetch that stores an unsigned 4 byte integer to the
2175
2179
location pointed. The column's type must be DATA_INT, DATA_UNSIGNED, length
2176
 
= 4.
2177
 
@return always returns NULL */
 
2180
= 4. */
2178
2181
UNIV_INTERN
2179
2182
void*
2180
2183
row_fetch_store_uint4(
2181
2184
/*==================*/
2182
 
        void*   row,            /*!< in:  sel_node_t* */
2183
 
        void*   user_arg)       /*!< in:  data pointer */
 
2185
                                /* out: always returns NULL */
 
2186
        void*   row,            /* in:  sel_node_t* */
 
2187
        void*   user_arg)       /* in:  data pointer */
2184
2188
{
2185
2189
        sel_node_t*     node = row;
2186
2190
        ib_uint32_t*    val = user_arg;
2200
2204
        return(NULL);
2201
2205
}
2202
2206
 
2203
 
/***********************************************************//**
2204
 
Prints a row in a select result.
2205
 
@return query thread to run next or NULL */
 
2207
/***************************************************************
 
2208
Prints a row in a select result. */
2206
2209
UNIV_INTERN
2207
2210
que_thr_t*
2208
2211
row_printf_step(
2209
2212
/*============*/
2210
 
        que_thr_t*      thr)    /*!< in: query thread */
 
2213
                                /* out: query thread to run next or NULL */
 
2214
        que_thr_t*      thr)    /* in: query thread */
2211
2215
{
2212
2216
        row_printf_node_t*      node;
2213
2217
        sel_node_t*             sel_node;
2263
2267
        return(thr);
2264
2268
}
2265
2269
 
2266
 
/****************************************************************//**
 
2270
/********************************************************************
2267
2271
Converts a key value stored in MySQL format to an Innobase dtuple. The last
2268
2272
field of the key value may be just a prefix of a fixed length field: hence
2269
2273
the parameter key_len. But currently we do not allow search keys where the
2274
2278
void
2275
2279
row_sel_convert_mysql_key_to_innobase(
2276
2280
/*==================================*/
2277
 
        dtuple_t*       tuple,          /*!< in/out: tuple where to build;
 
2281
        dtuple_t*       tuple,          /* in/out: tuple where to build;
2278
2282
                                        NOTE: we assume that the type info
2279
2283
                                        in the tuple is already according
2280
2284
                                        to index! */
2281
 
        byte*           buf,            /*!< in: buffer to use in field
 
2285
        byte*           buf,            /* in: buffer to use in field
2282
2286
                                        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 */
 
2287
        ulint           buf_len,        /* in: buffer length */
 
2288
        dict_index_t*   index,          /* in: index of the key value */
 
2289
        const byte*     key_ptr,        /* in: MySQL key value */
 
2290
        ulint           key_len,        /* in: MySQL key value length */
 
2291
        trx_t*          trx)            /* in: transaction */
2288
2292
{
2289
2293
        byte*           original_buf    = buf;
2290
2294
        const byte*     original_key_ptr = key_ptr;
2467
2471
        dtuple_set_n_fields(tuple, n_fields);
2468
2472
}
2469
2473
 
2470
 
/**************************************************************//**
 
2474
/******************************************************************
2471
2475
Stores the row id to the prebuilt struct. */
2472
2476
static
2473
2477
void
2474
2478
row_sel_store_row_id_to_prebuilt(
2475
2479
/*=============================*/
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
        row_prebuilt_t*         prebuilt,       /* in/out: prebuilt */
 
2481
        const rec_t*            index_rec,      /* in: record */
 
2482
        const dict_index_t*     index,          /* in: index of the record */
 
2483
        const ulint*            offsets)        /* in: rec_get_offsets
2480
2484
                                                (index_rec, index) */
2481
2485
{
2482
2486
        const byte*     data;
2505
2509
        ut_memcpy(prebuilt->row_id, data, len);
2506
2510
}
2507
2511
 
2508
 
/**************************************************************//**
 
2512
/******************************************************************
2509
2513
Stores a non-SQL-NULL field in the MySQL format. The counterpart of this
2510
2514
function is row_mysql_store_col_in_innobase_format() in row0mysql.c. */
2511
2515
static
2512
2516
void
2513
2517
row_sel_field_store_in_mysql_format(
2514
2518
/*================================*/
2515
 
        byte*           dest,   /*!< in/out: buffer where to store; NOTE
 
2519
        byte*           dest,   /* in/out: buffer where to store; NOTE
2516
2520
                                that BLOBs are not in themselves
2517
2521
                                stored here: the caller must allocate
2518
2522
                                and copy the BLOB into buffer before,
2519
2523
                                and pass the pointer to the BLOB in
2520
2524
                                'data' */
2521
2525
        const mysql_row_templ_t* templ,
2522
 
                                /*!< in: MySQL column template.
 
2526
                                /* in: MySQL column template.
2523
2527
                                Its following fields are referenced:
2524
2528
                                type, is_unsigned, mysql_col_len,
2525
2529
                                mbminlen, mbmaxlen */
2526
 
        const byte*     data,   /*!< in: data to store */
2527
 
        ulint           len)    /*!< in: length of the data */
 
2530
        const byte*     data,   /* in: data to store */
 
2531
        ulint           len)    /* in: length of the data */
2528
2532
{
2529
2533
        byte*   ptr;
2530
2534
        byte*   field_end;
2660
2664
        }
2661
2665
}
2662
2666
 
2663
 
/**************************************************************//**
 
2667
/******************************************************************
2664
2668
Convert a row in the Innobase format to a row in the MySQL format.
2665
2669
Note that the template in prebuilt may advise us to copy only a few
2666
2670
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) */
 
2671
be needed in the query. */
2670
2672
static
2671
2673
ibool
2672
2674
row_sel_store_mysql_rec(
2673
2675
/*====================*/
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
 
2676
                                        /* out: TRUE if success, FALSE if
 
2677
                                        could not allocate memory for a BLOB
 
2678
                                        (though we may also assert in that
 
2679
                                        case) */
 
2680
        byte*           mysql_rec,      /* out: row in the MySQL format */
 
2681
        row_prebuilt_t* prebuilt,       /* in: prebuilt struct */
 
2682
        const rec_t*    rec,            /* in: Innobase record in the index
2677
2683
                                        which was described in prebuilt's
2678
2684
                                        template; must be protected by
2679
2685
                                        a page latch */
2680
 
        const ulint*    offsets)        /*!< in: array returned by
 
2686
        const ulint*    offsets,        /* in: array returned by
2681
2687
                                        rec_get_offsets() */
 
2688
        ulint start_field_no,
 
2689
        ulint end_field_no)
2682
2690
{
2683
2691
        mysql_row_templ_t*      templ;
2684
2692
        mem_heap_t*             extern_field_heap       = NULL;
2696
2704
                prebuilt->blob_heap = NULL;
2697
2705
        }
2698
2706
 
2699
 
        for (i = 0; i < prebuilt->n_template ; i++) {
 
2707
        memset(mysql_rec, 0xff, prebuilt->null_bitmap_len);
 
2708
        for (i = start_field_no; i < end_field_no /* prebuilt->n_template */; i++) {
2700
2709
 
2701
2710
                templ = prebuilt->mysql_template + i;
2702
2711
 
2782
2791
                        mysql_rec[templ->mysql_null_byte_offset]
2783
2792
                                |= (byte) templ->mysql_null_bit_mask;
2784
2793
                        memcpy(mysql_rec + templ->mysql_col_offset,
2785
 
                               (const byte*) prebuilt->default_rec
2786
 
                               + templ->mysql_col_offset,
 
2794
                               prebuilt->default_rec + templ->mysql_col_offset,
2787
2795
                               templ->mysql_col_len);
2788
2796
                }
2789
2797
        }
2791
2799
        return(TRUE);
2792
2800
}
2793
2801
 
2794
 
/*********************************************************************//**
2795
 
Builds a previous version of a clustered index record for a consistent read
2796
 
@return DB_SUCCESS or error code */
 
2802
/*************************************************************************
 
2803
Builds a previous version of a clustered index record for a consistent read */
2797
2804
static
2798
2805
ulint
2799
2806
row_sel_build_prev_vers_for_mysql(
2800
2807
/*==============================*/
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
 
2808
                                        /* out: DB_SUCCESS or error code */
 
2809
        read_view_t*    read_view,      /* in: read view */
 
2810
        dict_index_t*   clust_index,    /* in: clustered index */
 
2811
        row_prebuilt_t* prebuilt,       /* in: prebuilt struct */
 
2812
        const rec_t*    rec,            /* in: record in a clustered index */
 
2813
        ulint**         offsets,        /* in/out: offsets returned by
2806
2814
                                        rec_get_offsets(rec, clust_index) */
2807
 
        mem_heap_t**    offset_heap,    /*!< in/out: memory heap from which
 
2815
        mem_heap_t**    offset_heap,    /* in/out: memory heap from which
2808
2816
                                        the offsets are allocated */
2809
 
        rec_t**         old_vers,       /*!< out: old version, or NULL if the
 
2817
        rec_t**         old_vers,       /* out: old version, or NULL if the
2810
2818
                                        record does not exist in the view:
2811
2819
                                        i.e., it was freshly inserted
2812
2820
                                        afterwards */
2813
 
        mtr_t*          mtr)            /*!< in: mtr */
 
2821
        mtr_t*          mtr)            /* in: mtr */
2814
2822
{
2815
2823
        ulint   err;
2816
2824
 
2826
2834
        return(err);
2827
2835
}
2828
2836
 
2829
 
/*********************************************************************//**
 
2837
/*************************************************************************
2830
2838
Retrieves the clustered index record corresponding to a record in a
2831
2839
non-clustered index. Does the necessary locking. Used in the MySQL
2832
 
interface.
2833
 
@return DB_SUCCESS or error code */
 
2840
interface. */
2834
2841
static
2835
2842
ulint
2836
2843
row_sel_get_clust_rec_for_mysql(
2837
2844
/*============================*/
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
 
2845
                                /* out: DB_SUCCESS or error code */
 
2846
        row_prebuilt_t* prebuilt,/* in: prebuilt struct in the handle */
 
2847
        dict_index_t*   sec_index,/* in: secondary index where rec resides */
 
2848
        const rec_t*    rec,    /* in: record in a non-clustered index; if
2841
2849
                                this is a locking read, then rec is not
2842
2850
                                allowed to be delete-marked, and that would
2843
2851
                                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
 
2852
        que_thr_t*      thr,    /* in: query thread */
 
2853
        const rec_t**   out_rec,/* out: clustered record or an old version of
2846
2854
                                it, NULL if the old version did not exist
2847
2855
                                in the read view, i.e., it was a fresh
2848
2856
                                inserted version */
2849
 
        ulint**         offsets,/*!< in: offsets returned by
 
2857
        ulint**         offsets,/* in: offsets returned by
2850
2858
                                rec_get_offsets(rec, sec_index);
2851
2859
                                out: offsets returned by
2852
2860
                                rec_get_offsets(out_rec, clust_index) */
2853
 
        mem_heap_t**    offset_heap,/*!< in/out: memory heap from which
 
2861
        mem_heap_t**    offset_heap,/* in/out: memory heap from which
2854
2862
                                the offsets are allocated */
2855
 
        mtr_t*          mtr)    /*!< in: mtr used to get access to the
 
2863
        mtr_t*          mtr)    /* in: mtr used to get access to the
2856
2864
                                non-clustered record; the same mtr is used to
2857
2865
                                access the clustered index */
2858
2866
{
2998
3006
func_exit:
2999
3007
        *out_rec = clust_rec;
3000
3008
 
3001
 
        if (prebuilt->select_lock_type != LOCK_NONE) {
3002
 
                /* We may use the cursor in update or in unlock_row():
3003
 
                store its position */
 
3009
        if (prebuilt->select_lock_type == LOCK_X) {
 
3010
                /* We may use the cursor in update: store its position */
3004
3011
 
3005
3012
                btr_pcur_store_position(prebuilt->clust_pcur, mtr);
3006
3013
        }
3010
3017
        return(err);
3011
3018
}
3012
3019
 
3013
 
/********************************************************************//**
 
3020
/************************************************************************
3014
3021
Restores cursor position after it has been stored. We have to take into
3015
3022
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) */
 
3023
Then we may have to move the cursor one step up or down. */
3019
3024
static
3020
3025
ibool
3021
3026
sel_restore_position_for_mysql(
3022
3027
/*===========================*/
3023
 
        ibool*          same_user_rec,  /*!< out: TRUE if we were able to restore
 
3028
                                        /* out: TRUE if we may need to
 
3029
                                        process the record the cursor is
 
3030
                                        now positioned on (i.e. we should
 
3031
                                        not go to the next record yet) */
 
3032
        ibool*          same_user_rec,  /* out: TRUE if we were able to restore
3024
3033
                                        the cursor on a user record with the
3025
3034
                                        same ordering prefix in in the
3026
3035
                                        B-tree index */
3027
 
        ulint           latch_mode,     /*!< in: latch mode wished in
 
3036
        ulint           latch_mode,     /* in: latch mode wished in
3028
3037
                                        restoration */
3029
 
        btr_pcur_t*     pcur,           /*!< in: cursor whose position
 
3038
        btr_pcur_t*     pcur,           /* in: cursor whose position
3030
3039
                                        has been stored */
3031
 
        ibool           moves_up,       /*!< in: TRUE if the cursor moves up
 
3040
        ibool           moves_up,       /* in: TRUE if the cursor moves up
3032
3041
                                        in the index */
3033
 
        mtr_t*          mtr)            /*!< in: mtr; CAUTION: may commit
 
3042
        mtr_t*          mtr)            /* in: mtr; CAUTION: may commit
3034
3043
                                        mtr temporarily! */
3035
3044
{
3036
3045
        ibool   success;
3078
3087
        return(TRUE);
3079
3088
}
3080
3089
 
3081
 
/********************************************************************//**
 
3090
/************************************************************************
3082
3091
Pops a cached row for MySQL from the fetch cache. */
3083
3092
UNIV_INLINE
3084
3093
void
3085
3094
row_sel_pop_cached_row_for_mysql(
3086
3095
/*=============================*/
3087
 
        byte*           buf,            /*!< in/out: buffer where to copy the
 
3096
        byte*           buf,            /* in/out: buffer where to copy the
3088
3097
                                        row */
3089
 
        row_prebuilt_t* prebuilt)       /*!< in: prebuilt struct */
 
3098
        row_prebuilt_t* prebuilt)       /* in: prebuilt struct */
3090
3099
{
3091
3100
        ulint                   i;
3092
3101
        mysql_row_templ_t*      templ;
3128
3137
        }
3129
3138
}
3130
3139
 
3131
 
/********************************************************************//**
 
3140
/************************************************************************
3132
3141
Pushes a row for MySQL to the fetch cache. */
3133
3142
UNIV_INLINE
3134
3143
void
3135
3144
row_sel_push_cache_row_for_mysql(
3136
3145
/*=============================*/
3137
 
        row_prebuilt_t* prebuilt,       /*!< in: prebuilt struct */
3138
 
        const rec_t*    rec,            /*!< in: record to push; must
 
3146
        row_prebuilt_t* prebuilt,       /* in: prebuilt struct */
 
3147
        const rec_t*    rec,            /* in: record to push; must
3139
3148
                                        be protected by a page latch */
3140
 
        const ulint*    offsets)        /*!<in: rec_get_offsets() */
 
3149
        const ulint*    offsets,        /* in: rec_get_offsets() */
 
3150
        ulint           start_field_no, /* psergy: start from this field */
 
3151
        byte*           remainder_buf)  /* if above !=0 -> where to take
 
3152
                                           prev fields */
3141
3153
{
3142
3154
        byte*   buf;
3143
3155
        ulint   i;
3170
3182
        if (UNIV_UNLIKELY(!row_sel_store_mysql_rec(
3171
3183
                                  prebuilt->fetch_cache[
3172
3184
                                          prebuilt->n_fetch_cached],
3173
 
                                  prebuilt, rec, offsets))) {
 
3185
                                  prebuilt, rec, offsets, start_field_no,
 
3186
                                  prebuilt->n_template))) {
3174
3187
                ut_error;
3175
3188
        }
3176
3189
 
 
3190
        if (start_field_no) {
 
3191
          for (i=0; i < start_field_no; i++) {
 
3192
            register ulint offs;
 
3193
            mysql_row_templ_t* templ;
 
3194
            templ = prebuilt->mysql_template + i;
 
3195
 
 
3196
            if (templ->mysql_null_bit_mask) {
 
3197
              offs= templ->mysql_null_byte_offset;
 
3198
              if (*(remainder_buf + offs) & templ->mysql_null_bit_mask)
 
3199
                 *(prebuilt->fetch_cache[prebuilt->n_fetch_cached] + offs) |= 
 
3200
                /*  (*(remainder_buf + offs) &*/( templ->mysql_null_bit_mask);
 
3201
              else
 
3202
                *(prebuilt->fetch_cache[prebuilt->n_fetch_cached] + offs) &= 
 
3203
                  ~templ->mysql_null_bit_mask;
 
3204
 
 
3205
            }
 
3206
            offs= templ->mysql_col_offset;
 
3207
            memcpy(prebuilt->fetch_cache[prebuilt->n_fetch_cached] + offs,
 
3208
                   remainder_buf + offs,
 
3209
                   templ->mysql_col_len);
 
3210
          }
 
3211
        }
 
3212
 
 
3213
 
3177
3214
        prebuilt->n_fetch_cached++;
3178
3215
}
3179
3216
 
3180
 
/*********************************************************************//**
 
3217
/*************************************************************************
3181
3218
Tries to do a shortcut to fetch a clustered index record with a unique key,
3182
3219
using the hash index if possible (not always). We assume that the search
3183
3220
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 */
 
3221
btr search latch has been locked in S-mode. */
3186
3222
static
3187
3223
ulint
3188
3224
row_sel_try_search_shortcut_for_mysql(
3189
3225
/*==================================*/
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 */
 
3226
                                /* out: SEL_FOUND, SEL_EXHAUSTED, SEL_RETRY */
 
3227
        const rec_t**   out_rec,/* out: record if found */
 
3228
        row_prebuilt_t* prebuilt,/* in: prebuilt struct */
 
3229
        ulint**         offsets,/* in/out: for rec_get_offsets(*out_rec) */
 
3230
        mem_heap_t**    heap,   /* in/out: heap for rec_get_offsets() */
 
3231
        mtr_t*          mtr)    /* in: started mtr */
3195
3232
{
3196
3233
        dict_index_t*   index           = prebuilt->index;
3197
3234
        const dtuple_t* search_tuple    = prebuilt->search_tuple;
3248
3285
        return(SEL_FOUND);
3249
3286
}
3250
3287
 
3251
 
/********************************************************************//**
 
3288
/************************************************************************
3252
3289
Searches for rows in the database. This is used in the interface to
3253
3290
MySQL. This function opens a cursor, and also implements fetch next
3254
3291
and fetch prev. NOTE that if we do a search with a full key value
3255
3292
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 */
 
3293
position and fetch next or fetch prev must not be tried to the cursor! */
3259
3294
UNIV_INTERN
3260
3295
ulint
3261
3296
row_search_for_mysql(
3262
3297
/*=================*/
3263
 
        byte*           buf,            /*!< in/out: buffer for the fetched
 
3298
                                        /* out: DB_SUCCESS,
 
3299
                                        DB_RECORD_NOT_FOUND,
 
3300
                                        DB_END_OF_INDEX, DB_DEADLOCK,
 
3301
                                        DB_LOCK_TABLE_FULL, DB_CORRUPTION,
 
3302
                                        or DB_TOO_BIG_RECORD */
 
3303
        byte*           buf,            /* in/out: buffer for the fetched
3264
3304
                                        row in the MySQL format */
3265
 
        ulint           mode,           /*!< in: search mode PAGE_CUR_L, ... */
3266
 
        row_prebuilt_t* prebuilt,       /*!< in: prebuilt struct for the
 
3305
        ulint           mode,           /* in: search mode PAGE_CUR_L, ... */
 
3306
        row_prebuilt_t* prebuilt,       /* in: prebuilt struct for the
3267
3307
                                        table handle; this contains the info
3268
3308
                                        of search_tuple, index; if search
3269
3309
                                        tuple contains 0 fields then we
3270
3310
                                        position the cursor at the start or
3271
3311
                                        the end of the index, depending on
3272
3312
                                        'mode' */
3273
 
        ulint           match_mode,     /*!< in: 0 or ROW_SEL_EXACT or
 
3313
        ulint           match_mode,     /* in: 0 or ROW_SEL_EXACT or
3274
3314
                                        ROW_SEL_EXACT_PREFIX */
3275
 
        ulint           direction)      /*!< in: 0 or ROW_SEL_NEXT or
 
3315
        ulint           direction)      /* in: 0 or ROW_SEL_NEXT or
3276
3316
                                        ROW_SEL_PREV; NOTE: if this is != 0,
3277
3317
                                        then prebuilt must have a pcur
3278
3318
                                        with stored position! In opening of a
3309
3349
        mem_heap_t*     heap                            = NULL;
3310
3350
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
3311
3351
        ulint*          offsets                         = offsets_;
 
3352
        ibool           some_fields_in_buffer;
 
3353
        ibool           get_clust_rec= 0;
3312
3354
 
3313
3355
        rec_offs_init(offsets_);
3314
3356
 
3326
3368
                        "InnoDB: the MySQL datadir, or have you used"
3327
3369
                        " DISCARD TABLESPACE?\n"
3328
3370
                        "InnoDB: Look from\n"
3329
 
                        "InnoDB: " REFMAN "innodb-troubleshooting.html\n"
 
3371
                        "InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
 
3372
                        "innodb-troubleshooting.html\n"
3330
3373
                        "InnoDB: how you can resolve the problem.\n",
3331
3374
                        prebuilt->table->name);
3332
3375
 
3333
3376
                return(DB_ERROR);
3334
3377
        }
3335
3378
 
3336
 
        if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
3337
 
 
3338
 
                return(DB_MISSING_HISTORY);
3339
 
        }
3340
 
 
3341
3379
        if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) {
3342
3380
                fprintf(stderr,
3343
3381
                        "InnoDB: Error: trying to free a corrupt\n"
3352
3390
        }
3353
3391
 
3354
3392
#if 0
 
3393
        /* August 19, 2005 by Heikki: temporarily disable this error
 
3394
        print until the cursor lock count is done correctly.
 
3395
        See bugs #12263 and #12456!*/
 
3396
 
 
3397
        if (trx->n_mysql_tables_in_use == 0
 
3398
            && UNIV_UNLIKELY(prebuilt->select_lock_type == LOCK_NONE)) {
 
3399
                /* Note that if MySQL uses an InnoDB temp table that it
 
3400
                created inside LOCK TABLES, then n_mysql_tables_in_use can
 
3401
                be zero; in that case select_lock_type is set to LOCK_X in
 
3402
                ::start_stmt. */
 
3403
 
 
3404
                fputs("InnoDB: Error: MySQL is trying to perform a SELECT\n"
 
3405
                      "InnoDB: but it has not locked"
 
3406
                      " any tables in ::external_lock()!\n",
 
3407
                      stderr);
 
3408
                trx_print(stderr, trx, 600);
 
3409
                fputc('\n', stderr);
 
3410
        }
 
3411
#endif
 
3412
 
 
3413
#if 0
3355
3414
        fprintf(stderr, "Match mode %lu\n search tuple ",
3356
3415
                (ulong) match_mode);
3357
3416
        dtuple_print(search_tuple);
3380
3439
        is set or session is using a READ COMMITED isolation level. Then
3381
3440
        we are able to remove the record locks set here on an individual
3382
3441
        row. */
3383
 
        prebuilt->new_rec_locks = 0;
 
3442
 
 
3443
        if ((srv_locks_unsafe_for_binlog
 
3444
             || trx->isolation_level == TRX_ISO_READ_COMMITTED)
 
3445
            && prebuilt->select_lock_type != LOCK_NONE) {
 
3446
 
 
3447
                trx_reset_new_rec_lock_info(trx);
 
3448
        }
3384
3449
 
3385
3450
        /*-------------------------------------------------------------*/
3386
3451
        /* PHASE 1: Try to pop the row from the prefetch cache */
3473
3538
 
3474
3539
                /* Even if the condition is unique, MySQL seems to try to
3475
3540
                retrieve also a second row if a primary key contains more than
3476
 
                1 column.*/
 
3541
                1 column. Return immediately if this is not a HANDLER
 
3542
                command. */
3477
3543
 
3478
 
                if (UNIV_UNLIKELY(direction != 0)) {
 
3544
                if (UNIV_UNLIKELY(direction != 0
 
3545
                                  && !prebuilt->used_in_HANDLER)) {
3479
3546
 
3480
3547
                        err = DB_RECORD_NOT_FOUND;
3481
3548
                        goto func_exit;
3497
3564
            && unique_search
3498
3565
            && dict_index_is_clust(index)
3499
3566
            && !prebuilt->templ_contains_blob
 
3567
            && !prebuilt->used_in_HANDLER
3500
3568
            && (prebuilt->mysql_row_len < UNIV_PAGE_SIZE / 8)) {
3501
3569
 
3502
3570
                mode = PAGE_CUR_GE;
3541
3609
                                mtr_commit(&mtr). */
3542
3610
 
3543
3611
                                if (!row_sel_store_mysql_rec(buf, prebuilt,
3544
 
                                                             rec, offsets)) {
 
3612
                                                             rec, offsets, 0,
 
3613
                                                             prebuilt->n_template)) {
3545
3614
                                        err = DB_TOO_BIG_RECORD;
3546
3615
 
3547
3616
                                        /* We let the main loop to do the
4022
4091
                switch (err) {
4023
4092
                        const rec_t*    old_vers;
4024
4093
                case DB_SUCCESS:
4025
 
                        if (srv_locks_unsafe_for_binlog
4026
 
                            || trx->isolation_level == TRX_ISO_READ_COMMITTED) {
4027
 
                                /* Note that a record of
4028
 
                                prebuilt->index was locked. */
4029
 
                                prebuilt->new_rec_locks = 1;
4030
 
                        }
4031
4094
                        break;
4032
4095
                case DB_LOCK_WAIT:
4033
4096
                        if (UNIV_LIKELY(prebuilt->row_read_type
4058
4121
                        if (UNIV_LIKELY(trx->wait_lock != NULL)) {
4059
4122
                                lock_cancel_waiting_and_release(
4060
4123
                                        trx->wait_lock);
4061
 
                                prebuilt->new_rec_locks = 0;
 
4124
                                trx_reset_new_rec_lock_info(trx);
4062
4125
                        } else {
4063
4126
                                mutex_exit(&kernel_mutex);
4064
4127
 
4070
4133
                                                          ULINT_UNDEFINED,
4071
4134
                                                          &heap);
4072
4135
                                err = DB_SUCCESS;
4073
 
                                /* Note that a record of
4074
 
                                prebuilt->index was locked. */
4075
 
                                prebuilt->new_rec_locks = 1;
4076
4136
                                break;
4077
4137
                        }
4078
4138
                        mutex_exit(&kernel_mutex);
4140
4200
                        information via the clustered index record. */
4141
4201
 
4142
4202
                        ut_ad(index != clust_index);
4143
 
                        goto requires_clust_rec;
 
4203
                        get_clust_rec= TRUE;
 
4204
                        goto idx_cond_check;
4144
4205
                }
4145
4206
        }
4146
4207
 
4184
4245
                goto next_rec;
4185
4246
        }
4186
4247
 
 
4248
idx_cond_check:
 
4249
        if (prebuilt->idx_cond_func)
 
4250
        {
 
4251
          int res;
 
4252
          ut_ad(prebuilt->template_type != ROW_DRIZZLE_DUMMY_TEMPLATE);
 
4253
          offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
 
4254
          row_sel_store_mysql_rec(buf, prebuilt, rec,
 
4255
                                  offsets, 0, prebuilt->n_index_fields);
 
4256
          res= prebuilt->idx_cond_func(prebuilt->idx_cond_func_arg);
 
4257
          if (res == 0)
 
4258
            goto next_rec;
 
4259
          if (res == 2)
 
4260
          {
 
4261
            err = DB_RECORD_NOT_FOUND;
 
4262
            goto idx_cond_failed;
 
4263
          }
 
4264
        }
 
4265
 
4187
4266
        /* Get the clustered index record if needed, if we did not do the
4188
4267
        search using the clustered index. */
4189
4268
 
4190
 
        if (index != clust_index && prebuilt->need_to_access_clustered) {
 
4269
        if (get_clust_rec || (index != clust_index &&
 
4270
            prebuilt->need_to_access_clustered)) {
4191
4271
 
4192
 
requires_clust_rec:
4193
4272
                /* We use a 'goto' to the preceding label if a consistent
4194
4273
                read of a secondary index record requires us to look up old
4195
4274
                versions of the associated clustered index record. */
4220
4299
                        goto next_rec;
4221
4300
                }
4222
4301
 
4223
 
                if ((srv_locks_unsafe_for_binlog
4224
 
                     || trx->isolation_level == TRX_ISO_READ_COMMITTED)
4225
 
                    && prebuilt->select_lock_type != LOCK_NONE) {
4226
 
                        /* Note that both the secondary index record
4227
 
                        and the clustered index record were locked. */
4228
 
                        ut_ad(prebuilt->new_rec_locks == 1);
4229
 
                        prebuilt->new_rec_locks = 2;
4230
 
                }
4231
 
 
4232
4302
                if (UNIV_UNLIKELY(rec_get_deleted_flag(clust_rec, comp))) {
4233
4303
 
4234
4304
                        /* The record is delete marked: we can skip it */
4280
4350
            && prebuilt->select_lock_type == LOCK_NONE
4281
4351
            && !prebuilt->templ_contains_blob
4282
4352
            && !prebuilt->clust_index_was_generated
 
4353
            && !prebuilt->used_in_HANDLER
4283
4354
            && prebuilt->template_type
4284
4355
            != ROW_MYSQL_DUMMY_TEMPLATE) {
4285
4356
 
4291
4362
                are BLOBs in the fields to be fetched. In HANDLER we do
4292
4363
                not cache rows because there the cursor is a scrollable
4293
4364
                cursor. */
 
4365
                some_fields_in_buffer= (index != clust_index &&
 
4366
                                        prebuilt->idx_cond_func);
4294
4367
 
4295
4368
                row_sel_push_cache_row_for_mysql(prebuilt, result_rec,
4296
 
                                                 offsets);
 
4369
                                                 offsets,
 
4370
                                                 some_fields_in_buffer?
 
4371
                                                 prebuilt->n_index_fields: 0,
 
4372
                                                 buf);
4297
4373
                if (prebuilt->n_fetch_cached == MYSQL_FETCH_CACHE_SIZE) {
4298
4374
 
4299
4375
                        goto got_row;
4309
4385
                                        rec_offs_extra_size(offsets) + 4);
4310
4386
                } else {
4311
4387
                        if (!row_sel_store_mysql_rec(buf, prebuilt,
4312
 
                                                     result_rec, offsets)) {
 
4388
                                                     result_rec, offsets,
 
4389
                                                     prebuilt->idx_cond_func?
 
4390
                                                     prebuilt->n_index_fields: 0,
 
4391
                                                     prebuilt->n_template)) {
4313
4392
                                err = DB_TOO_BIG_RECORD;
4314
4393
 
4315
4394
                                goto lock_wait_or_error;
4337
4416
        HANDLER command where the user can move the cursor with PREV or NEXT
4338
4417
        even after a unique search. */
4339
4418
 
 
4419
idx_cond_failed:
4340
4420
        if (!unique_search_from_clust_index
4341
 
            || prebuilt->select_lock_type != LOCK_NONE) {
 
4421
            || prebuilt->select_lock_type != LOCK_NONE
 
4422
            || prebuilt->used_in_HANDLER) {
4342
4423
 
4343
4424
                /* Inside an update always store the cursor position */
4344
4425
 
4356
4437
                prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
4357
4438
        }
4358
4439
        did_semi_consistent_read = FALSE;
4359
 
        prebuilt->new_rec_locks = 0;
 
4440
 
 
4441
        if (UNIV_UNLIKELY(srv_locks_unsafe_for_binlog
 
4442
                          || trx->isolation_level == TRX_ISO_READ_COMMITTED)
 
4443
            && prebuilt->select_lock_type != LOCK_NONE) {
 
4444
 
 
4445
                trx_reset_new_rec_lock_info(trx);
 
4446
        }
4360
4447
 
4361
4448
        /*-------------------------------------------------------------*/
4362
4449
        /* PHASE 5: Move the cursor to the next index record */
4462
4549
                        rec_loop we will again try to set a lock, and
4463
4550
                        new_rec_lock_info in trx will be right at the end. */
4464
4551
 
4465
 
                        prebuilt->new_rec_locks = 0;
 
4552
                        trx_reset_new_rec_lock_info(trx);
4466
4553
                }
4467
4554
 
4468
4555
                mode = pcur->search_mode;
4522
4609
        return(err);
4523
4610
}
4524
4611
 
4525
 
/*******************************************************************//**
 
4612
/***********************************************************************
4526
4613
Checks if MySQL at the moment is allowed for this table to retrieve a
4527
 
consistent read result, or store it to the query cache.
4528
 
@return TRUE if storing or retrieving from the query cache is permitted */
 
4614
consistent read result, or store it to the query cache. */
4529
4615
UNIV_INTERN
4530
4616
ibool
4531
4617
row_search_check_if_query_cache_permitted(
4532
4618
/*======================================*/
4533
 
        trx_t*          trx,            /*!< in: transaction object */
4534
 
        const char*     norm_name)      /*!< in: concatenation of database name,
 
4619
                                        /* out: TRUE if storing or retrieving
 
4620
                                        from the query cache is permitted */
 
4621
        trx_t*          trx,            /* in: transaction object */
 
4622
        const char*     norm_name)      /* in: concatenation of database name,
4535
4623
                                        '/' char, table name */
4536
4624
{
4537
4625
        dict_table_t*   table;
4578
4666
        return(ret);
4579
4667
}
4580
4668
 
4581
 
/*******************************************************************//**
 
4669
/***********************************************************************
4582
4670
Read the AUTOINC column from the current row. If the value is less than
4583
 
0 and the type is not unsigned then we reset the value to 0.
4584
 
@return value read from the column */
 
4671
0 and the type is not unsigned then we reset the value to 0. */
4585
4672
static
4586
4673
ib_uint64_t
4587
4674
row_search_autoinc_read_column(
4588
4675
/*===========================*/
4589
 
        dict_index_t*   index,          /*!< in: index to read from */
4590
 
        const rec_t*    rec,            /*!< in: current rec */
4591
 
        ulint           col_no,         /*!< in: column number */
4592
 
        ibool           unsigned_type)  /*!< in: signed or unsigned flag */
 
4676
                                        /* out: value read from the column */
 
4677
        dict_index_t*   index,          /* in: index to read from */
 
4678
        const rec_t*    rec,            /* in: current rec */
 
4679
        ulint           col_no,         /* in: column number */
 
4680
        ibool           unsigned_type)  /* in: signed or unsigned flag */
4593
4681
{
4594
4682
        ulint           len;
4595
4683
        const byte*     data;
4621
4709
        return(value);
4622
4710
}
4623
4711
 
4624
 
/*******************************************************************//**
4625
 
Get the last row.
4626
 
@return current rec or NULL */
 
4712
/***********************************************************************
 
4713
Get the last row. */
4627
4714
static
4628
4715
const rec_t*
4629
4716
row_search_autoinc_get_rec(
4630
4717
/*=======================*/
4631
 
        btr_pcur_t*     pcur,           /*!< in: the current cursor */
4632
 
        mtr_t*          mtr)            /*!< in: mini transaction */
 
4718
                                        /* out: current rec or NULL */
 
4719
        btr_pcur_t*     pcur,           /* in: the current cursor */
 
4720
        mtr_t*          mtr)            /* in: mini transaction */
4633
4721
{
4634
4722
        do {
4635
4723
                const rec_t* rec = btr_pcur_get_rec(pcur);
4642
4730
        return(NULL);
4643
4731
}
4644
4732
 
4645
 
/*******************************************************************//**
4646
 
Read the max AUTOINC value from an index.
4647
 
@return DB_SUCCESS if all OK else error code, DB_RECORD_NOT_FOUND if
4648
 
column name can't be found in index */
 
4733
/***********************************************************************
 
4734
Read the max AUTOINC value from an index. */
4649
4735
UNIV_INTERN
4650
4736
ulint
4651
4737
row_search_max_autoinc(
4652
4738
/*===================*/
4653
 
        dict_index_t*   index,          /*!< in: index to search */
4654
 
        const char*     col_name,       /*!< in: name of autoinc column */
4655
 
        ib_uint64_t*    value)          /*!< out: AUTOINC value read */
 
4739
                                        /* out: DB_SUCCESS if all OK else
 
4740
                                        error code, DB_RECORD_NOT_FOUND if
 
4741
                                        column name can't be found in index */
 
4742
        dict_index_t*   index,          /* in: index to search */
 
4743
        const char*     col_name,       /* in: name of autoinc column */
 
4744
        ib_uint64_t*    value)          /* out: AUTOINC value read */
4656
4745
{
4657
4746
        ulint           i;
4658
4747
        ulint           n_cols;