1
/******************************************************
6
Created 4/20/1996 Heikki Tuuri
7
*******************************************************/
15
#include "dict0dict.h"
17
#include "mach0data.h"
22
#include "trx0purge.h"
28
#include "read0read.h"
30
/*************************************************************************
31
Reads the trx id or roll ptr field from a clustered index record: this function
32
is slower than the specialized inline functions. */
35
row_get_rec_sys_field(
36
/*==================*/
37
/* out: value of the field */
38
ulint type, /* in: DATA_TRX_ID or DATA_ROLL_PTR */
39
rec_t* rec, /* in: record */
40
dict_index_t* index, /* in: clustered index */
41
const ulint* offsets)/* in: rec_get_offsets(rec, index) */
47
ut_ad(index->type & DICT_CLUSTERED);
49
pos = dict_index_get_sys_col_pos(index, type);
51
field = rec_get_nth_field(rec, offsets, pos, &len);
53
if (type == DATA_TRX_ID) {
55
return(trx_read_trx_id(field));
57
ut_ad(type == DATA_ROLL_PTR);
59
return(trx_read_roll_ptr(field));
63
/*************************************************************************
64
Sets the trx id or roll ptr field in a clustered index record: this function
65
is slower than the specialized inline functions. */
68
row_set_rec_sys_field(
69
/*==================*/
70
/* out: value of the field */
71
ulint type, /* in: DATA_TRX_ID or DATA_ROLL_PTR */
72
rec_t* rec, /* in: record */
73
dict_index_t* index, /* in: clustered index */
74
const ulint* offsets,/* in: rec_get_offsets(rec, index) */
75
dulint val) /* in: value to set */
81
ut_ad(index->type & DICT_CLUSTERED);
82
ut_ad(rec_offs_validate(rec, index, offsets));
84
pos = dict_index_get_sys_col_pos(index, type);
86
field = rec_get_nth_field(rec, offsets, pos, &len);
88
if (type == DATA_TRX_ID) {
90
trx_write_trx_id(field, val);
92
ut_ad(type == DATA_ROLL_PTR);
94
trx_write_roll_ptr(field, val);
98
/*********************************************************************
99
When an insert to a table is performed, this function builds the entry which
100
has to be inserted to an index on the table. */
103
row_build_index_entry(
104
/*==================*/
105
/* out: index entry which should be inserted */
106
dtuple_t* row, /* in: row which should be inserted to the
108
dict_index_t* index, /* in: index on the table */
109
mem_heap_t* heap) /* in: memory heap from which the memory for
110
the index entry is allocated */
114
dict_field_t* ind_field;
120
ut_ad(row && index && heap);
121
ut_ad(dtuple_check_typed(row));
123
entry_len = dict_index_get_n_fields(index);
124
entry = dtuple_create(heap, entry_len);
126
if (index->type & DICT_UNIVERSAL) {
127
dtuple_set_n_fields_cmp(entry, entry_len);
129
dtuple_set_n_fields_cmp(
130
entry, dict_index_get_n_unique_in_tree(index));
133
for (i = 0; i < entry_len; i++) {
134
const dict_col_t* col;
135
ind_field = dict_index_get_nth_field(index, i);
136
col = ind_field->col;
138
dfield = dtuple_get_nth_field(entry, i);
140
dfield2 = dtuple_get_nth_field(row, dict_col_get_no(col));
142
dfield_copy(dfield, dfield2);
144
/* If a column prefix index, take only the prefix */
145
if (ind_field->prefix_len > 0
146
&& dfield_get_len(dfield2) != UNIV_SQL_NULL) {
148
storage_len = dtype_get_at_most_n_mbchars(
149
col->prtype, col->mbminlen, col->mbmaxlen,
150
ind_field->prefix_len,
151
dfield_get_len(dfield2), dfield2->data);
153
dfield_set_len(dfield, storage_len);
157
ut_ad(dtuple_check_typed(entry));
162
/***********************************************************************
163
An inverse function to dict_row_build_index_entry. Builds a row from a
164
record in a clustered index. */
169
/* out, own: row built; see the NOTE below! */
170
ulint type, /* in: ROW_COPY_POINTERS or ROW_COPY_DATA;
171
the latter copies also the data fields to
172
heap while the first only places pointers to
173
data fields on the index page, and thus is
175
dict_index_t* index, /* in: clustered index */
176
rec_t* rec, /* in: record in the clustered index;
177
NOTE: in the case ROW_COPY_POINTERS
178
the data fields in the row will point
179
directly into this record, therefore,
180
the buffer page of this record must be
181
at least s-latched and the latch held
182
as long as the row dtuple is used! */
183
const ulint* offsets,/* in: rec_get_offsets(rec, index)
184
or NULL, in which case this function
185
will invoke rec_get_offsets() */
186
mem_heap_t* heap) /* in: memory heap from which the memory
187
needed is allocated */
191
dict_field_t* ind_field;
199
mem_heap_t* tmp_heap = NULL;
200
ulint offsets_[REC_OFFS_NORMAL_SIZE];
201
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
203
ut_ad(index && rec && heap);
204
ut_ad(index->type & DICT_CLUSTERED);
207
offsets = rec_get_offsets(rec, index, offsets_,
208
ULINT_UNDEFINED, &tmp_heap);
210
ut_ad(rec_offs_validate(rec, index, offsets));
213
if (type != ROW_COPY_POINTERS) {
214
/* Take a copy of rec to heap */
215
buf = mem_heap_alloc(heap, rec_offs_size(offsets));
216
rec = rec_copy(buf, rec, offsets);
217
/* Avoid a debug assertion in rec_offs_validate(). */
218
rec_offs_make_valid(rec, index, (ulint*) offsets);
221
table = index->table;
222
row_len = dict_table_get_n_cols(table);
224
row = dtuple_create(heap, row_len);
226
dtuple_set_info_bits(row, rec_get_info_bits(
227
rec, dict_table_is_comp(table)));
229
n_fields = rec_offs_n_fields(offsets);
231
dict_table_copy_types(row, table);
233
for (i = 0; i < n_fields; i++) {
234
ind_field = dict_index_get_nth_field(index, i);
236
if (ind_field->prefix_len == 0) {
238
const dict_col_t* col
239
= dict_field_get_col(ind_field);
241
dfield = dtuple_get_nth_field(row,
242
dict_col_get_no(col));
243
field = rec_get_nth_field(rec, offsets, i, &len);
245
dfield_set_data(dfield, field, len);
249
ut_ad(dtuple_check_typed(row));
252
mem_heap_free(tmp_heap);
258
/***********************************************************************
259
Converts an index record to a typed data tuple. NOTE that externally
260
stored (often big) fields are NOT copied to heap. */
263
row_rec_to_index_entry(
264
/*===================*/
265
/* out, own: index entry built; see the
267
ulint type, /* in: ROW_COPY_DATA, or ROW_COPY_POINTERS:
268
the former copies also the data fields to
269
heap as the latter only places pointers to
270
data fields on the index page */
271
dict_index_t* index, /* in: index */
272
rec_t* rec, /* in: record in the index;
273
NOTE: in the case ROW_COPY_POINTERS
274
the data fields in the row will point
275
directly into this record, therefore,
276
the buffer page of this record must be
277
at least s-latched and the latch held
278
as long as the dtuple is used! */
279
mem_heap_t* heap) /* in: memory heap from which the memory
280
needed is allocated */
289
mem_heap_t* tmp_heap = NULL;
290
ulint offsets_[REC_OFFS_NORMAL_SIZE];
291
ulint* offsets = offsets_;
292
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
294
ut_ad(rec && heap && index);
296
offsets = rec_get_offsets(rec, index, offsets,
297
ULINT_UNDEFINED, &tmp_heap);
299
if (type == ROW_COPY_DATA) {
300
/* Take a copy of rec to heap */
301
buf = mem_heap_alloc(heap, rec_offs_size(offsets));
302
rec = rec_copy(buf, rec, offsets);
303
/* Avoid a debug assertion in rec_offs_validate(). */
304
rec_offs_make_valid(rec, index, offsets);
307
rec_len = rec_offs_n_fields(offsets);
309
entry = dtuple_create(heap, rec_len);
311
dtuple_set_n_fields_cmp(entry,
312
dict_index_get_n_unique_in_tree(index));
313
ut_ad(rec_len == dict_index_get_n_fields(index));
315
dict_index_copy_types(entry, index, rec_len);
317
dtuple_set_info_bits(entry,
318
rec_get_info_bits(rec, rec_offs_comp(offsets)));
320
for (i = 0; i < rec_len; i++) {
322
dfield = dtuple_get_nth_field(entry, i);
323
field = rec_get_nth_field(rec, offsets, i, &len);
325
dfield_set_data(dfield, field, len);
328
ut_ad(dtuple_check_typed(entry));
330
mem_heap_free(tmp_heap);
336
/***********************************************************************
337
Builds from a secondary index record a row reference with which we can
338
search the clustered index record. */
343
/* out, own: row reference built; see the
345
ulint type, /* in: ROW_COPY_DATA, or ROW_COPY_POINTERS:
346
the former copies also the data fields to
347
heap, whereas the latter only places pointers
348
to data fields on the index page */
349
dict_index_t* index, /* in: index */
350
rec_t* rec, /* in: record in the index;
351
NOTE: in the case ROW_COPY_POINTERS
352
the data fields in the row will point
353
directly into this record, therefore,
354
the buffer page of this record must be
355
at least s-latched and the latch held
356
as long as the row reference is used! */
357
mem_heap_t* heap) /* in: memory heap from which the memory
358
needed is allocated */
361
dict_index_t* clust_index;
369
ulint clust_col_prefix_len;
371
mem_heap_t* tmp_heap = NULL;
372
ulint offsets_[REC_OFFS_NORMAL_SIZE];
373
ulint* offsets = offsets_;
374
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
376
ut_ad(index && rec && heap);
378
offsets = rec_get_offsets(rec, index, offsets,
379
ULINT_UNDEFINED, &tmp_heap);
381
if (type == ROW_COPY_DATA) {
382
/* Take a copy of rec to heap */
384
buf = mem_heap_alloc(heap, rec_offs_size(offsets));
386
rec = rec_copy(buf, rec, offsets);
387
/* Avoid a debug assertion in rec_offs_validate(). */
388
rec_offs_make_valid(rec, index, offsets);
391
table = index->table;
393
clust_index = dict_table_get_first_index(table);
395
ref_len = dict_index_get_n_unique(clust_index);
397
ref = dtuple_create(heap, ref_len);
399
dict_index_copy_types(ref, clust_index, ref_len);
401
for (i = 0; i < ref_len; i++) {
402
dfield = dtuple_get_nth_field(ref, i);
404
pos = dict_index_get_nth_field_pos(index, clust_index, i);
406
ut_a(pos != ULINT_UNDEFINED);
408
field = rec_get_nth_field(rec, offsets, pos, &len);
410
dfield_set_data(dfield, field, len);
412
/* If the primary key contains a column prefix, then the
413
secondary index may contain a longer prefix of the same
414
column, or the full column, and we must adjust the length
417
clust_col_prefix_len = dict_index_get_nth_field(
418
clust_index, i)->prefix_len;
420
if (clust_col_prefix_len > 0) {
421
if (len != UNIV_SQL_NULL) {
424
= dfield_get_type(dfield);
426
dfield_set_len(dfield,
427
dtype_get_at_most_n_mbchars(
431
clust_col_prefix_len,
432
len, (char*) field));
437
ut_ad(dtuple_check_typed(ref));
439
mem_heap_free(tmp_heap);
445
/***********************************************************************
446
Builds from a secondary index record a row reference with which we can
447
search the clustered index record. */
450
row_build_row_ref_in_tuple(
451
/*=======================*/
452
dtuple_t* ref, /* in/out: row reference built; see the
454
dict_index_t* index, /* in: index */
455
rec_t* rec, /* in: record in the index;
456
NOTE: the data fields in ref will point
457
directly into this record, therefore,
458
the buffer page of this record must be
459
at least s-latched and the latch held
460
as long as the row reference is used! */
461
trx_t* trx) /* in: transaction */
463
dict_index_t* clust_index;
469
ulint clust_col_prefix_len;
471
mem_heap_t* heap = NULL;
472
ulint offsets_[REC_OFFS_NORMAL_SIZE];
473
ulint* offsets = offsets_;
474
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
480
if (UNIV_UNLIKELY(!index->table)) {
481
fputs("InnoDB: table ", stderr);
483
ut_print_name(stderr, trx, TRUE, index->table_name);
484
fputs(" for index ", stderr);
485
ut_print_name(stderr, trx, FALSE, index->name);
486
fputs(" not found\n", stderr);
490
clust_index = dict_table_get_first_index(index->table);
493
fputs("InnoDB: clust index for table ", stderr);
497
offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
499
ref_len = dict_index_get_n_unique(clust_index);
501
ut_ad(ref_len == dtuple_get_n_fields(ref));
503
dict_index_copy_types(ref, clust_index, ref_len);
505
for (i = 0; i < ref_len; i++) {
506
dfield = dtuple_get_nth_field(ref, i);
508
pos = dict_index_get_nth_field_pos(index, clust_index, i);
510
ut_a(pos != ULINT_UNDEFINED);
512
field = rec_get_nth_field(rec, offsets, pos, &len);
514
dfield_set_data(dfield, field, len);
516
/* If the primary key contains a column prefix, then the
517
secondary index may contain a longer prefix of the same
518
column, or the full column, and we must adjust the length
521
clust_col_prefix_len = dict_index_get_nth_field(
522
clust_index, i)->prefix_len;
524
if (clust_col_prefix_len > 0) {
525
if (len != UNIV_SQL_NULL) {
528
= dfield_get_type(dfield);
530
dfield_set_len(dfield,
531
dtype_get_at_most_n_mbchars(
535
clust_col_prefix_len,
536
len, (char*) field));
541
ut_ad(dtuple_check_typed(ref));
542
if (UNIV_LIKELY_NULL(heap)) {
547
/***********************************************************************
548
From a row build a row reference with which we can search the clustered
552
row_build_row_ref_from_row(
553
/*=======================*/
554
dtuple_t* ref, /* in/out: row reference built; see the
555
NOTE below! ref must have the right number
557
dict_table_t* table, /* in: table */
558
dtuple_t* row) /* in: row
559
NOTE: the data fields in ref will point
560
directly into data of this row */
562
dict_index_t* clust_index;
566
ut_ad(ref && table && row);
568
clust_index = dict_table_get_first_index(table);
570
ref_len = dict_index_get_n_unique(clust_index);
572
ut_ad(ref_len == dtuple_get_n_fields(ref));
574
for (i = 0; i < ref_len; i++) {
575
const dict_col_t* col;
580
dfield = dtuple_get_nth_field(ref, i);
582
field = dict_index_get_nth_field(clust_index, i);
584
col = dict_field_get_col(field);
586
dfield2 = dtuple_get_nth_field(row, dict_col_get_no(col));
588
dfield_copy(dfield, dfield2);
590
if (field->prefix_len > 0
591
&& dfield->len != UNIV_SQL_NULL) {
593
dfield->len = dtype_get_at_most_n_mbchars(
594
col->prtype, col->mbminlen, col->mbmaxlen,
595
field->prefix_len, dfield->len, dfield->data);
599
ut_ad(dtuple_check_typed(ref));
602
/*******************************************************************
603
Searches the clustered index record for a row, if we have the row reference. */
606
row_search_on_row_ref(
607
/*==================*/
608
/* out: TRUE if found */
609
btr_pcur_t* pcur, /* in/out: persistent cursor, which must
610
be closed by the caller */
611
ulint mode, /* in: BTR_MODIFY_LEAF, ... */
612
dict_table_t* table, /* in: table */
613
dtuple_t* ref, /* in: row reference */
614
mtr_t* mtr) /* in: mtr */
620
ut_ad(dtuple_check_typed(ref));
622
index = dict_table_get_first_index(table);
624
ut_a(dtuple_get_n_fields(ref) == dict_index_get_n_unique(index));
626
btr_pcur_open(index, ref, PAGE_CUR_LE, mode, pcur, mtr);
628
low_match = btr_pcur_get_low_match(pcur);
630
rec = btr_pcur_get_rec(pcur);
632
if (page_rec_is_infimum(rec)) {
637
if (low_match != dtuple_get_n_fields(ref)) {
645
/*************************************************************************
646
Fetches the clustered index record for a secondary index record. The latches
647
on the secondary index record are preserved. */
652
/* out: record or NULL, if no record found */
653
ulint mode, /* in: BTR_MODIFY_LEAF, ... */
654
rec_t* rec, /* in: record in a secondary index */
655
dict_index_t* index, /* in: secondary index */
656
dict_index_t** clust_index,/* out: clustered index */
657
mtr_t* mtr) /* in: mtr */
666
ut_ad((index->type & DICT_CLUSTERED) == 0);
668
table = index->table;
670
heap = mem_heap_create(256);
672
ref = row_build_row_ref(ROW_COPY_POINTERS, index, rec, heap);
674
found = row_search_on_row_ref(&pcur, mode, table, ref, mtr);
676
clust_rec = found ? btr_pcur_get_rec(&pcur) : NULL;
680
btr_pcur_close(&pcur);
682
*clust_index = dict_table_get_first_index(table);
687
/*******************************************************************
688
Searches an index record. */
691
row_search_index_entry(
692
/*===================*/
693
/* out: TRUE if found */
694
dict_index_t* index, /* in: index */
695
dtuple_t* entry, /* in: index entry */
696
ulint mode, /* in: BTR_MODIFY_LEAF, ... */
697
btr_pcur_t* pcur, /* in/out: persistent cursor, which must
698
be closed by the caller */
699
mtr_t* mtr) /* in: mtr */
705
ut_ad(dtuple_check_typed(entry));
707
btr_pcur_open(index, entry, PAGE_CUR_LE, mode, pcur, mtr);
708
low_match = btr_pcur_get_low_match(pcur);
710
rec = btr_pcur_get_rec(pcur);
712
n_fields = dtuple_get_n_fields(entry);
714
if (page_rec_is_infimum(rec)) {
719
if (low_match != n_fields) {