mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / storage / innodb_plugin / row / row0row.c
blobc1f39fb68cbca4f1fa79f5d2623eda7cc2cc9a3f
1 /*****************************************************************************
3 Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free Software
7 Foundation; version 2 of the License.
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License along with
14 this program; if not, write to the Free Software Foundation, Inc.,
15 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
17 *****************************************************************************/
19 /**************************************************//**
20 @file row/row0row.c
21 General row routines
23 Created 4/20/1996 Heikki Tuuri
24 *******************************************************/
26 #include "row0row.h"
28 #ifdef UNIV_NONINL
29 #include "row0row.ic"
30 #endif
32 #include "data0type.h"
33 #include "dict0dict.h"
34 #include "btr0btr.h"
35 #include "ha_prototypes.h"
36 #include "mach0data.h"
37 #include "trx0rseg.h"
38 #include "trx0trx.h"
39 #include "trx0roll.h"
40 #include "trx0undo.h"
41 #include "trx0purge.h"
42 #include "trx0rec.h"
43 #include "que0que.h"
44 #include "row0ext.h"
45 #include "row0upd.h"
46 #include "rem0cmp.h"
47 #include "read0read.h"
48 #include "ut0mem.h"
50 /*****************************************************************//**
51 When an insert or purge to a table is performed, this function builds
52 the entry to be inserted into or purged from an index on the table.
53 @return index entry which should be inserted or purged, or NULL if the
54 externally stored columns in the clustered index record are
55 unavailable and ext != NULL */
56 UNIV_INTERN
57 dtuple_t*
58 row_build_index_entry(
59 /*==================*/
60 const dtuple_t* row, /*!< in: row which should be
61 inserted or purged */
62 row_ext_t* ext, /*!< in: externally stored column prefixes,
63 or NULL */
64 dict_index_t* index, /*!< in: index on the table */
65 mem_heap_t* heap) /*!< in: memory heap from which the memory for
66 the index entry is allocated */
68 dtuple_t* entry;
69 ulint entry_len;
70 ulint i;
72 ut_ad(row && index && heap);
73 ut_ad(dtuple_check_typed(row));
75 entry_len = dict_index_get_n_fields(index);
76 entry = dtuple_create(heap, entry_len);
78 if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
79 dtuple_set_n_fields_cmp(entry, entry_len);
80 /* There may only be externally stored columns
81 in a clustered index B-tree of a user table. */
82 ut_a(!ext);
83 } else {
84 dtuple_set_n_fields_cmp(
85 entry, dict_index_get_n_unique_in_tree(index));
88 for (i = 0; i < entry_len; i++) {
89 const dict_field_t* ind_field
90 = dict_index_get_nth_field(index, i);
91 const dict_col_t* col
92 = ind_field->col;
93 ulint col_no
94 = dict_col_get_no(col);
95 dfield_t* dfield
96 = dtuple_get_nth_field(entry, i);
97 const dfield_t* dfield2
98 = dtuple_get_nth_field(row, col_no);
99 ulint len
100 = dfield_get_len(dfield2);
102 dfield_copy(dfield, dfield2);
104 if (dfield_is_null(dfield)) {
105 continue;
108 if (ind_field->prefix_len == 0
109 && (!dfield_is_ext(dfield)
110 || dict_index_is_clust(index))) {
111 /* The dfield_copy() above suffices for
112 columns that are stored in-page, or for
113 clustered index record columns that are not
114 part of a column prefix in the PRIMARY KEY. */
115 continue;
118 /* If the column is stored externally (off-page) in
119 the clustered index, it must be an ordering field in
120 the secondary index. In the Antelope format, only
121 prefix-indexed columns may be stored off-page in the
122 clustered index record. In the Barracuda format, also
123 fully indexed long CHAR or VARCHAR columns may be
124 stored off-page. */
125 ut_ad(col->ord_part);
127 if (UNIV_LIKELY_NULL(ext)) {
128 /* See if the column is stored externally. */
129 const byte* buf = row_ext_lookup(ext, col_no,
130 &len);
131 if (UNIV_LIKELY_NULL(buf)) {
132 if (UNIV_UNLIKELY(buf == field_ref_zero)) {
133 return(NULL);
135 dfield_set_data(dfield, buf, len);
138 if (ind_field->prefix_len == 0) {
139 /* In the Barracuda format
140 (ROW_FORMAT=DYNAMIC or
141 ROW_FORMAT=COMPRESSED), we can have a
142 secondary index on an entire column
143 that is stored off-page in the
144 clustered index. As this is not a
145 prefix index (prefix_len == 0),
146 include the entire off-page column in
147 the secondary index record. */
148 continue;
150 } else if (dfield_is_ext(dfield)) {
151 /* This table is either in Antelope format
152 (ROW_FORMAT=REDUNDANT or ROW_FORMAT=COMPACT)
153 or a purge record where the ordered part of
154 the field is not external.
155 In Antelope, the maximum column prefix
156 index length is 767 bytes, and the clustered
157 index record contains a 768-byte prefix of
158 each off-page column. */
159 ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE);
160 len -= BTR_EXTERN_FIELD_REF_SIZE;
161 dfield_set_len(dfield, len);
164 /* If a column prefix index, take only the prefix. */
165 if (ind_field->prefix_len) {
166 len = dtype_get_at_most_n_mbchars(
167 col->prtype, col->mbminlen, col->mbmaxlen,
168 ind_field->prefix_len, len,
169 dfield_get_data(dfield));
170 dfield_set_len(dfield, len);
174 ut_ad(dtuple_check_typed(entry));
176 return(entry);
179 /*******************************************************************//**
180 An inverse function to row_build_index_entry. Builds a row from a
181 record in a clustered index.
182 @return own: row built; see the NOTE below! */
183 UNIV_INTERN
184 dtuple_t*
185 row_build(
186 /*======*/
187 ulint type, /*!< in: ROW_COPY_POINTERS or
188 ROW_COPY_DATA; the latter
189 copies also the data fields to
190 heap while the first only
191 places pointers to data fields
192 on the index page, and thus is
193 more efficient */
194 const dict_index_t* index, /*!< in: clustered index */
195 const rec_t* rec, /*!< in: record in the clustered
196 index; NOTE: in the case
197 ROW_COPY_POINTERS the data
198 fields in the row will point
199 directly into this record,
200 therefore, the buffer page of
201 this record must be at least
202 s-latched and the latch held
203 as long as the row dtuple is used! */
204 const ulint* offsets,/*!< in: rec_get_offsets(rec,index)
205 or NULL, in which case this function
206 will invoke rec_get_offsets() */
207 const dict_table_t* col_table,
208 /*!< in: table, to check which
209 externally stored columns
210 occur in the ordering columns
211 of an index, or NULL if
212 index->table should be
213 consulted instead */
214 row_ext_t** ext, /*!< out, own: cache of
215 externally stored column
216 prefixes, or NULL */
217 mem_heap_t* heap) /*!< in: memory heap from which
218 the memory needed is allocated */
220 dtuple_t* row;
221 const dict_table_t* table;
222 ulint n_fields;
223 ulint n_ext_cols;
224 ulint* ext_cols = NULL; /* remove warning */
225 ulint len;
226 ulint row_len;
227 byte* buf;
228 ulint i;
229 ulint j;
230 mem_heap_t* tmp_heap = NULL;
231 ulint offsets_[REC_OFFS_NORMAL_SIZE];
232 rec_offs_init(offsets_);
234 ut_ad(index && rec && heap);
235 ut_ad(dict_index_is_clust(index));
236 ut_ad(!mutex_own(&kernel_mutex));
238 if (!offsets) {
239 offsets = rec_get_offsets(rec, index, offsets_,
240 ULINT_UNDEFINED, &tmp_heap);
241 } else {
242 ut_ad(rec_offs_validate(rec, index, offsets));
245 #if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
246 if (rec_offs_any_null_extern(rec, offsets)) {
247 /* This condition can occur during crash recovery
248 before trx_rollback_active() has completed execution,
249 or when a concurrently executing
250 row_ins_index_entry_low() has committed the B-tree
251 mini-transaction but has not yet managed to restore
252 the cursor position for writing the big_rec. */
253 ut_a(trx_undo_roll_ptr_is_insert(
254 row_get_rec_roll_ptr(rec, index, offsets)));
256 #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
258 if (type != ROW_COPY_POINTERS) {
259 /* Take a copy of rec to heap */
260 buf = mem_heap_alloc(heap, rec_offs_size(offsets));
261 rec = rec_copy(buf, rec, offsets);
262 /* Avoid a debug assertion in rec_offs_validate(). */
263 rec_offs_make_valid(rec, index, (ulint*) offsets);
266 table = index->table;
267 row_len = dict_table_get_n_cols(table);
269 row = dtuple_create(heap, row_len);
271 dict_table_copy_types(row, table);
273 dtuple_set_info_bits(row, rec_get_info_bits(
274 rec, dict_table_is_comp(table)));
276 n_fields = rec_offs_n_fields(offsets);
277 n_ext_cols = rec_offs_n_extern(offsets);
278 if (n_ext_cols) {
279 ext_cols = mem_heap_alloc(heap, n_ext_cols * sizeof *ext_cols);
282 for (i = j = 0; i < n_fields; i++) {
283 dict_field_t* ind_field
284 = dict_index_get_nth_field(index, i);
285 const dict_col_t* col
286 = dict_field_get_col(ind_field);
287 ulint col_no
288 = dict_col_get_no(col);
289 dfield_t* dfield
290 = dtuple_get_nth_field(row, col_no);
292 if (ind_field->prefix_len == 0) {
294 const byte* field = rec_get_nth_field(
295 rec, offsets, i, &len);
297 dfield_set_data(dfield, field, len);
300 if (rec_offs_nth_extern(offsets, i)) {
301 dfield_set_ext(dfield);
303 if (UNIV_LIKELY_NULL(col_table)) {
304 ut_a(col_no
305 < dict_table_get_n_cols(col_table));
306 col = dict_table_get_nth_col(
307 col_table, col_no);
310 if (col->ord_part) {
311 /* We will have to fetch prefixes of
312 externally stored columns that are
313 referenced by column prefixes. */
314 ext_cols[j++] = col_no;
319 ut_ad(dtuple_check_typed(row));
321 if (!ext) {
322 /* REDUNDANT and COMPACT formats store a local
323 768-byte prefix of each externally stored
324 column. No cache is needed. */
325 ut_ad(dict_table_get_format(index->table)
326 < DICT_TF_FORMAT_ZIP);
327 } else if (j) {
328 *ext = row_ext_create(j, ext_cols, row,
329 dict_table_zip_size(index->table),
330 heap);
331 } else {
332 *ext = NULL;
335 if (tmp_heap) {
336 mem_heap_free(tmp_heap);
339 return(row);
342 /*******************************************************************//**
343 Converts an index record to a typed data tuple.
344 @return index entry built; does not set info_bits, and the data fields
345 in the entry will point directly to rec */
346 UNIV_INTERN
347 dtuple_t*
348 row_rec_to_index_entry_low(
349 /*=======================*/
350 const rec_t* rec, /*!< in: record in the index */
351 const dict_index_t* index, /*!< in: index */
352 const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */
353 ulint* n_ext, /*!< out: number of externally
354 stored columns */
355 mem_heap_t* heap) /*!< in: memory heap from which
356 the memory needed is allocated */
358 dtuple_t* entry;
359 dfield_t* dfield;
360 ulint i;
361 const byte* field;
362 ulint len;
363 ulint rec_len;
365 ut_ad(rec && heap && index);
366 /* Because this function may be invoked by row0merge.c
367 on a record whose header is in different format, the check
368 rec_offs_validate(rec, index, offsets) must be avoided here. */
369 ut_ad(n_ext);
370 *n_ext = 0;
372 rec_len = rec_offs_n_fields(offsets);
374 entry = dtuple_create(heap, rec_len);
376 dtuple_set_n_fields_cmp(entry,
377 dict_index_get_n_unique_in_tree(index));
378 ut_ad(rec_len == dict_index_get_n_fields(index));
380 dict_index_copy_types(entry, index, rec_len);
382 for (i = 0; i < rec_len; i++) {
384 dfield = dtuple_get_nth_field(entry, i);
385 field = rec_get_nth_field(rec, offsets, i, &len);
387 dfield_set_data(dfield, field, len);
389 if (rec_offs_nth_extern(offsets, i)) {
390 dfield_set_ext(dfield);
391 (*n_ext)++;
395 ut_ad(dtuple_check_typed(entry));
397 return(entry);
400 /*******************************************************************//**
401 Converts an index record to a typed data tuple. NOTE that externally
402 stored (often big) fields are NOT copied to heap.
403 @return own: index entry built; see the NOTE below! */
404 UNIV_INTERN
405 dtuple_t*
406 row_rec_to_index_entry(
407 /*===================*/
408 ulint type, /*!< in: ROW_COPY_DATA, or
409 ROW_COPY_POINTERS: the former
410 copies also the data fields to
411 heap as the latter only places
412 pointers to data fields on the
413 index page */
414 const rec_t* rec, /*!< in: record in the index;
415 NOTE: in the case
416 ROW_COPY_POINTERS the data
417 fields in the row will point
418 directly into this record,
419 therefore, the buffer page of
420 this record must be at least
421 s-latched and the latch held
422 as long as the dtuple is used! */
423 const dict_index_t* index, /*!< in: index */
424 ulint* offsets,/*!< in/out: rec_get_offsets(rec) */
425 ulint* n_ext, /*!< out: number of externally
426 stored columns */
427 mem_heap_t* heap) /*!< in: memory heap from which
428 the memory needed is allocated */
430 dtuple_t* entry;
431 byte* buf;
433 ut_ad(rec && heap && index);
434 ut_ad(rec_offs_validate(rec, index, offsets));
436 if (type == ROW_COPY_DATA) {
437 /* Take a copy of rec to heap */
438 buf = mem_heap_alloc(heap, rec_offs_size(offsets));
439 rec = rec_copy(buf, rec, offsets);
440 /* Avoid a debug assertion in rec_offs_validate(). */
441 rec_offs_make_valid(rec, index, offsets);
442 #if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
443 } else {
444 ut_a(!rec_offs_any_null_extern(rec, offsets));
445 #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
448 entry = row_rec_to_index_entry_low(rec, index, offsets, n_ext, heap);
450 dtuple_set_info_bits(entry,
451 rec_get_info_bits(rec, rec_offs_comp(offsets)));
453 return(entry);
456 /*******************************************************************//**
457 Builds from a secondary index record a row reference with which we can
458 search the clustered index record.
459 @return own: row reference built; see the NOTE below! */
460 UNIV_INTERN
461 dtuple_t*
462 row_build_row_ref(
463 /*==============*/
464 ulint type, /*!< in: ROW_COPY_DATA, or ROW_COPY_POINTERS:
465 the former copies also the data fields to
466 heap, whereas the latter only places pointers
467 to data fields on the index page */
468 dict_index_t* index, /*!< in: secondary index */
469 const rec_t* rec, /*!< in: record in the index;
470 NOTE: in the case ROW_COPY_POINTERS
471 the data fields in the row will point
472 directly into this record, therefore,
473 the buffer page of this record must be
474 at least s-latched and the latch held
475 as long as the row reference is used! */
476 mem_heap_t* heap) /*!< in: memory heap from which the memory
477 needed is allocated */
479 dict_table_t* table;
480 dict_index_t* clust_index;
481 dfield_t* dfield;
482 dtuple_t* ref;
483 const byte* field;
484 ulint len;
485 ulint ref_len;
486 ulint pos;
487 byte* buf;
488 ulint clust_col_prefix_len;
489 ulint i;
490 mem_heap_t* tmp_heap = NULL;
491 ulint offsets_[REC_OFFS_NORMAL_SIZE];
492 ulint* offsets = offsets_;
493 rec_offs_init(offsets_);
495 ut_ad(index && rec && heap);
496 ut_ad(!dict_index_is_clust(index));
498 offsets = rec_get_offsets(rec, index, offsets,
499 ULINT_UNDEFINED, &tmp_heap);
500 /* Secondary indexes must not contain externally stored columns. */
501 ut_ad(!rec_offs_any_extern(offsets));
503 if (type == ROW_COPY_DATA) {
504 /* Take a copy of rec to heap */
506 buf = mem_heap_alloc(heap, rec_offs_size(offsets));
508 rec = rec_copy(buf, rec, offsets);
509 /* Avoid a debug assertion in rec_offs_validate(). */
510 rec_offs_make_valid(rec, index, offsets);
513 table = index->table;
515 clust_index = dict_table_get_first_index(table);
517 ref_len = dict_index_get_n_unique(clust_index);
519 ref = dtuple_create(heap, ref_len);
521 dict_index_copy_types(ref, clust_index, ref_len);
523 for (i = 0; i < ref_len; i++) {
524 dfield = dtuple_get_nth_field(ref, i);
526 pos = dict_index_get_nth_field_pos(index, clust_index, i);
528 ut_a(pos != ULINT_UNDEFINED);
530 field = rec_get_nth_field(rec, offsets, pos, &len);
532 dfield_set_data(dfield, field, len);
534 /* If the primary key contains a column prefix, then the
535 secondary index may contain a longer prefix of the same
536 column, or the full column, and we must adjust the length
537 accordingly. */
539 clust_col_prefix_len = dict_index_get_nth_field(
540 clust_index, i)->prefix_len;
542 if (clust_col_prefix_len > 0) {
543 if (len != UNIV_SQL_NULL) {
545 const dtype_t* dtype
546 = dfield_get_type(dfield);
548 dfield_set_len(dfield,
549 dtype_get_at_most_n_mbchars(
550 dtype->prtype,
551 dtype->mbminlen,
552 dtype->mbmaxlen,
553 clust_col_prefix_len,
554 len, (char*) field));
559 ut_ad(dtuple_check_typed(ref));
560 if (tmp_heap) {
561 mem_heap_free(tmp_heap);
564 return(ref);
567 /*******************************************************************//**
568 Builds from a secondary index record a row reference with which we can
569 search the clustered index record. */
570 UNIV_INTERN
571 void
572 row_build_row_ref_in_tuple(
573 /*=======================*/
574 dtuple_t* ref, /*!< in/out: row reference built;
575 see the NOTE below! */
576 const rec_t* rec, /*!< in: record in the index;
577 NOTE: the data fields in ref
578 will point directly into this
579 record, therefore, the buffer
580 page of this record must be at
581 least s-latched and the latch
582 held as long as the row
583 reference is used! */
584 const dict_index_t* index, /*!< in: secondary index */
585 ulint* offsets,/*!< in: rec_get_offsets(rec, index)
586 or NULL */
587 trx_t* trx) /*!< in: transaction */
589 const dict_index_t* clust_index;
590 dfield_t* dfield;
591 const byte* field;
592 ulint len;
593 ulint ref_len;
594 ulint pos;
595 ulint clust_col_prefix_len;
596 ulint i;
597 mem_heap_t* heap = NULL;
598 ulint offsets_[REC_OFFS_NORMAL_SIZE];
599 rec_offs_init(offsets_);
601 ut_a(ref);
602 ut_a(index);
603 ut_a(rec);
604 ut_ad(!dict_index_is_clust(index));
606 if (UNIV_UNLIKELY(!index->table)) {
607 fputs("InnoDB: table ", stderr);
608 notfound:
609 ut_print_name(stderr, trx, TRUE, index->table_name);
610 fputs(" for index ", stderr);
611 ut_print_name(stderr, trx, FALSE, index->name);
612 fputs(" not found\n", stderr);
613 ut_error;
616 clust_index = dict_table_get_first_index(index->table);
618 if (UNIV_UNLIKELY(!clust_index)) {
619 fputs("InnoDB: clust index for table ", stderr);
620 goto notfound;
623 if (!offsets) {
624 offsets = rec_get_offsets(rec, index, offsets_,
625 ULINT_UNDEFINED, &heap);
626 } else {
627 ut_ad(rec_offs_validate(rec, index, offsets));
630 /* Secondary indexes must not contain externally stored columns. */
631 ut_ad(!rec_offs_any_extern(offsets));
632 ref_len = dict_index_get_n_unique(clust_index);
634 ut_ad(ref_len == dtuple_get_n_fields(ref));
636 dict_index_copy_types(ref, clust_index, ref_len);
638 for (i = 0; i < ref_len; i++) {
639 dfield = dtuple_get_nth_field(ref, i);
641 pos = dict_index_get_nth_field_pos(index, clust_index, i);
643 ut_a(pos != ULINT_UNDEFINED);
645 field = rec_get_nth_field(rec, offsets, pos, &len);
647 dfield_set_data(dfield, field, len);
649 /* If the primary key contains a column prefix, then the
650 secondary index may contain a longer prefix of the same
651 column, or the full column, and we must adjust the length
652 accordingly. */
654 clust_col_prefix_len = dict_index_get_nth_field(
655 clust_index, i)->prefix_len;
657 if (clust_col_prefix_len > 0) {
658 if (len != UNIV_SQL_NULL) {
660 const dtype_t* dtype
661 = dfield_get_type(dfield);
663 dfield_set_len(dfield,
664 dtype_get_at_most_n_mbchars(
665 dtype->prtype,
666 dtype->mbminlen,
667 dtype->mbmaxlen,
668 clust_col_prefix_len,
669 len, (char*) field));
674 ut_ad(dtuple_check_typed(ref));
675 if (UNIV_LIKELY_NULL(heap)) {
676 mem_heap_free(heap);
680 /***************************************************************//**
681 Searches the clustered index record for a row, if we have the row reference.
682 @return TRUE if found */
683 UNIV_INTERN
684 ibool
685 row_search_on_row_ref(
686 /*==================*/
687 btr_pcur_t* pcur, /*!< out: persistent cursor, which must
688 be closed by the caller */
689 ulint mode, /*!< in: BTR_MODIFY_LEAF, ... */
690 const dict_table_t* table, /*!< in: table */
691 const dtuple_t* ref, /*!< in: row reference */
692 mtr_t* mtr) /*!< in/out: mtr */
694 ulint low_match;
695 rec_t* rec;
696 dict_index_t* index;
698 ut_ad(dtuple_check_typed(ref));
700 index = dict_table_get_first_index(table);
702 ut_a(dtuple_get_n_fields(ref) == dict_index_get_n_unique(index));
704 btr_pcur_open(index, ref, PAGE_CUR_LE, mode, pcur, mtr);
706 low_match = btr_pcur_get_low_match(pcur);
708 rec = btr_pcur_get_rec(pcur);
710 if (page_rec_is_infimum(rec)) {
712 return(FALSE);
715 if (low_match != dtuple_get_n_fields(ref)) {
717 return(FALSE);
720 return(TRUE);
723 /*********************************************************************//**
724 Fetches the clustered index record for a secondary index record. The latches
725 on the secondary index record are preserved.
726 @return record or NULL, if no record found */
727 UNIV_INTERN
728 rec_t*
729 row_get_clust_rec(
730 /*==============*/
731 ulint mode, /*!< in: BTR_MODIFY_LEAF, ... */
732 const rec_t* rec, /*!< in: record in a secondary index */
733 dict_index_t* index, /*!< in: secondary index */
734 dict_index_t** clust_index,/*!< out: clustered index */
735 mtr_t* mtr) /*!< in: mtr */
737 mem_heap_t* heap;
738 dtuple_t* ref;
739 dict_table_t* table;
740 btr_pcur_t pcur;
741 ibool found;
742 rec_t* clust_rec;
744 ut_ad(!dict_index_is_clust(index));
746 table = index->table;
748 heap = mem_heap_create(256);
750 ref = row_build_row_ref(ROW_COPY_POINTERS, index, rec, heap);
752 found = row_search_on_row_ref(&pcur, mode, table, ref, mtr);
754 clust_rec = found ? btr_pcur_get_rec(&pcur) : NULL;
756 mem_heap_free(heap);
758 btr_pcur_close(&pcur);
760 *clust_index = dict_table_get_first_index(table);
762 return(clust_rec);
765 /***************************************************************//**
766 Searches an index record.
767 @return TRUE if found */
768 UNIV_INTERN
769 ibool
770 row_search_index_entry(
771 /*===================*/
772 dict_index_t* index, /*!< in: index */
773 const dtuple_t* entry, /*!< in: index entry */
774 ulint mode, /*!< in: BTR_MODIFY_LEAF, ... */
775 btr_pcur_t* pcur, /*!< in/out: persistent cursor, which must
776 be closed by the caller */
777 mtr_t* mtr) /*!< in: mtr */
779 ulint n_fields;
780 ulint low_match;
781 rec_t* rec;
783 ut_ad(dtuple_check_typed(entry));
785 btr_pcur_open(index, entry, PAGE_CUR_LE, mode, pcur, mtr);
786 low_match = btr_pcur_get_low_match(pcur);
788 rec = btr_pcur_get_rec(pcur);
790 n_fields = dtuple_get_n_fields(entry);
792 return(!page_rec_is_infimum(rec) && low_match == n_fields);
795 #include <my_sys.h>
797 /*******************************************************************//**
798 Formats the raw data in "data" (in InnoDB on-disk format) that is of
799 type DATA_INT using "prtype" and writes the result to "buf".
800 If the data is in unknown format, then nothing is written to "buf",
801 0 is returned and "format_in_hex" is set to TRUE, otherwise
802 "format_in_hex" is left untouched.
803 Not more than "buf_size" bytes are written to "buf".
804 The result is always '\0'-terminated (provided buf_size > 0) and the
805 number of bytes that were written to "buf" is returned (including the
806 terminating '\0').
807 @return number of bytes that were written */
808 static
809 ulint
810 row_raw_format_int(
811 /*===============*/
812 const char* data, /*!< in: raw data */
813 ulint data_len, /*!< in: raw data length
814 in bytes */
815 ulint prtype, /*!< in: precise type */
816 char* buf, /*!< out: output buffer */
817 ulint buf_size, /*!< in: output buffer size
818 in bytes */
819 ibool* format_in_hex) /*!< out: should the data be
820 formated in hex */
822 ulint ret;
824 if (data_len <= sizeof(ullint)) {
826 ullint value;
827 ibool unsigned_type = prtype & DATA_UNSIGNED;
829 value = mach_read_int_type((const byte*) data,
830 data_len, unsigned_type);
832 if (unsigned_type) {
834 ret = ut_snprintf(buf, buf_size, "%llu",
835 value) + 1;
836 } else {
838 ret = ut_snprintf(buf, buf_size, "%lld",
839 (long long) value) + 1;
842 } else {
844 *format_in_hex = TRUE;
845 ret = 0;
848 return(ut_min(ret, buf_size));
851 /*******************************************************************//**
852 Formats the raw data in "data" (in InnoDB on-disk format) that is of
853 type DATA_(CHAR|VARCHAR|MYSQL|VARMYSQL) using "prtype" and writes the
854 result to "buf".
855 If the data is in binary format, then nothing is written to "buf",
856 0 is returned and "format_in_hex" is set to TRUE, otherwise
857 "format_in_hex" is left untouched.
858 Not more than "buf_size" bytes are written to "buf".
859 The result is always '\0'-terminated (provided buf_size > 0) and the
860 number of bytes that were written to "buf" is returned (including the
861 terminating '\0').
862 @return number of bytes that were written */
863 static
864 ulint
865 row_raw_format_str(
866 /*===============*/
867 const char* data, /*!< in: raw data */
868 ulint data_len, /*!< in: raw data length
869 in bytes */
870 ulint prtype, /*!< in: precise type */
871 char* buf, /*!< out: output buffer */
872 ulint buf_size, /*!< in: output buffer size
873 in bytes */
874 ibool* format_in_hex) /*!< out: should the data be
875 formated in hex */
877 ulint charset_coll;
879 if (buf_size == 0) {
881 return(0);
884 /* we assume system_charset_info is UTF-8 */
886 charset_coll = dtype_get_charset_coll(prtype);
888 if (UNIV_LIKELY(dtype_is_utf8(prtype))) {
890 return(ut_str_sql_format(data, data_len, buf, buf_size));
892 /* else */
894 if (charset_coll == DATA_MYSQL_BINARY_CHARSET_COLL) {
896 *format_in_hex = TRUE;
897 return(0);
899 /* else */
901 return(innobase_raw_format(data, data_len, charset_coll,
902 buf, buf_size));
905 /*******************************************************************//**
906 Formats the raw data in "data" (in InnoDB on-disk format) using
907 "dict_field" and writes the result to "buf".
908 Not more than "buf_size" bytes are written to "buf".
909 The result is always NUL-terminated (provided buf_size is positive) and the
910 number of bytes that were written to "buf" is returned (including the
911 terminating NUL).
912 @return number of bytes that were written */
913 UNIV_INTERN
914 ulint
915 row_raw_format(
916 /*===========*/
917 const char* data, /*!< in: raw data */
918 ulint data_len, /*!< in: raw data length
919 in bytes */
920 const dict_field_t* dict_field, /*!< in: index field */
921 char* buf, /*!< out: output buffer */
922 ulint buf_size) /*!< in: output buffer size
923 in bytes */
925 ulint mtype;
926 ulint prtype;
927 ulint ret;
928 ibool format_in_hex;
930 if (buf_size == 0) {
932 return(0);
935 if (data_len == UNIV_SQL_NULL) {
937 ret = ut_snprintf((char*) buf, buf_size, "NULL") + 1;
939 return(ut_min(ret, buf_size));
942 mtype = dict_field->col->mtype;
943 prtype = dict_field->col->prtype;
945 format_in_hex = FALSE;
947 switch (mtype) {
948 case DATA_INT:
950 ret = row_raw_format_int(data, data_len, prtype,
951 buf, buf_size, &format_in_hex);
952 if (format_in_hex) {
954 goto format_in_hex;
956 break;
957 case DATA_CHAR:
958 case DATA_VARCHAR:
959 case DATA_MYSQL:
960 case DATA_VARMYSQL:
962 ret = row_raw_format_str(data, data_len, prtype,
963 buf, buf_size, &format_in_hex);
964 if (format_in_hex) {
966 goto format_in_hex;
969 break;
970 /* XXX support more data types */
971 default:
972 format_in_hex:
974 if (UNIV_LIKELY(buf_size > 2)) {
976 memcpy(buf, "0x", 2);
977 buf += 2;
978 buf_size -= 2;
979 ret = 2 + ut_raw_to_hex(data, data_len,
980 buf, buf_size);
981 } else {
983 buf[0] = '\0';
984 ret = 1;
988 return(ret);
991 #ifdef UNIV_COMPILE_TEST_FUNCS
993 #include "ut0dbg.h"
995 void
996 test_row_raw_format_int()
998 ulint ret;
999 char buf[128];
1000 ibool format_in_hex;
1002 #define CALL_AND_TEST(data, data_len, prtype, buf, buf_size,\
1003 ret_expected, buf_expected, format_in_hex_expected)\
1004 do {\
1005 ibool ok = TRUE;\
1006 ulint i;\
1007 memset(buf, 'x', 10);\
1008 buf[10] = '\0';\
1009 format_in_hex = FALSE;\
1010 fprintf(stderr, "TESTING \"\\x");\
1011 for (i = 0; i < data_len; i++) {\
1012 fprintf(stderr, "%02hhX", data[i]);\
1014 fprintf(stderr, "\", %lu, %lu, %lu\n",\
1015 (ulint) data_len, (ulint) prtype,\
1016 (ulint) buf_size);\
1017 ret = row_raw_format_int(data, data_len, prtype,\
1018 buf, buf_size, &format_in_hex);\
1019 if (ret != ret_expected) {\
1020 fprintf(stderr, "expected ret %lu, got %lu\n",\
1021 (ulint) ret_expected, ret);\
1022 ok = FALSE;\
1024 if (strcmp((char*) buf, buf_expected) != 0) {\
1025 fprintf(stderr, "expected buf \"%s\", got \"%s\"\n",\
1026 buf_expected, buf);\
1027 ok = FALSE;\
1029 if (format_in_hex != format_in_hex_expected) {\
1030 fprintf(stderr, "expected format_in_hex %d, got %d\n",\
1031 (int) format_in_hex_expected,\
1032 (int) format_in_hex);\
1033 ok = FALSE;\
1035 if (ok) {\
1036 fprintf(stderr, "OK: %lu, \"%s\" %d\n\n",\
1037 (ulint) ret, buf, (int) format_in_hex);\
1038 } else {\
1039 return;\
1041 } while (0)
1043 #if 1
1044 /* min values for signed 1-8 byte integers */
1046 CALL_AND_TEST("\x00", 1, 0,
1047 buf, sizeof(buf), 5, "-128", 0);
1049 CALL_AND_TEST("\x00\x00", 2, 0,
1050 buf, sizeof(buf), 7, "-32768", 0);
1052 CALL_AND_TEST("\x00\x00\x00", 3, 0,
1053 buf, sizeof(buf), 9, "-8388608", 0);
1055 CALL_AND_TEST("\x00\x00\x00\x00", 4, 0,
1056 buf, sizeof(buf), 12, "-2147483648", 0);
1058 CALL_AND_TEST("\x00\x00\x00\x00\x00", 5, 0,
1059 buf, sizeof(buf), 14, "-549755813888", 0);
1061 CALL_AND_TEST("\x00\x00\x00\x00\x00\x00", 6, 0,
1062 buf, sizeof(buf), 17, "-140737488355328", 0);
1064 CALL_AND_TEST("\x00\x00\x00\x00\x00\x00\x00", 7, 0,
1065 buf, sizeof(buf), 19, "-36028797018963968", 0);
1067 CALL_AND_TEST("\x00\x00\x00\x00\x00\x00\x00\x00", 8, 0,
1068 buf, sizeof(buf), 21, "-9223372036854775808", 0);
1070 /* min values for unsigned 1-8 byte integers */
1072 CALL_AND_TEST("\x00", 1, DATA_UNSIGNED,
1073 buf, sizeof(buf), 2, "0", 0);
1075 CALL_AND_TEST("\x00\x00", 2, DATA_UNSIGNED,
1076 buf, sizeof(buf), 2, "0", 0);
1078 CALL_AND_TEST("\x00\x00\x00", 3, DATA_UNSIGNED,
1079 buf, sizeof(buf), 2, "0", 0);
1081 CALL_AND_TEST("\x00\x00\x00\x00", 4, DATA_UNSIGNED,
1082 buf, sizeof(buf), 2, "0", 0);
1084 CALL_AND_TEST("\x00\x00\x00\x00\x00", 5, DATA_UNSIGNED,
1085 buf, sizeof(buf), 2, "0", 0);
1087 CALL_AND_TEST("\x00\x00\x00\x00\x00\x00", 6, DATA_UNSIGNED,
1088 buf, sizeof(buf), 2, "0", 0);
1090 CALL_AND_TEST("\x00\x00\x00\x00\x00\x00\x00", 7, DATA_UNSIGNED,
1091 buf, sizeof(buf), 2, "0", 0);
1093 CALL_AND_TEST("\x00\x00\x00\x00\x00\x00\x00\x00", 8, DATA_UNSIGNED,
1094 buf, sizeof(buf), 2, "0", 0);
1096 /* max values for signed 1-8 byte integers */
1098 CALL_AND_TEST("\xFF", 1, 0,
1099 buf, sizeof(buf), 4, "127", 0);
1101 CALL_AND_TEST("\xFF\xFF", 2, 0,
1102 buf, sizeof(buf), 6, "32767", 0);
1104 CALL_AND_TEST("\xFF\xFF\xFF", 3, 0,
1105 buf, sizeof(buf), 8, "8388607", 0);
1107 CALL_AND_TEST("\xFF\xFF\xFF\xFF", 4, 0,
1108 buf, sizeof(buf), 11, "2147483647", 0);
1110 CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF", 5, 0,
1111 buf, sizeof(buf), 13, "549755813887", 0);
1113 CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF", 6, 0,
1114 buf, sizeof(buf), 16, "140737488355327", 0);
1116 CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 7, 0,
1117 buf, sizeof(buf), 18, "36028797018963967", 0);
1119 CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8, 0,
1120 buf, sizeof(buf), 20, "9223372036854775807", 0);
1122 /* max values for unsigned 1-8 byte integers */
1124 CALL_AND_TEST("\xFF", 1, DATA_UNSIGNED,
1125 buf, sizeof(buf), 4, "255", 0);
1127 CALL_AND_TEST("\xFF\xFF", 2, DATA_UNSIGNED,
1128 buf, sizeof(buf), 6, "65535", 0);
1130 CALL_AND_TEST("\xFF\xFF\xFF", 3, DATA_UNSIGNED,
1131 buf, sizeof(buf), 9, "16777215", 0);
1133 CALL_AND_TEST("\xFF\xFF\xFF\xFF", 4, DATA_UNSIGNED,
1134 buf, sizeof(buf), 11, "4294967295", 0);
1136 CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF", 5, DATA_UNSIGNED,
1137 buf, sizeof(buf), 14, "1099511627775", 0);
1139 CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF", 6, DATA_UNSIGNED,
1140 buf, sizeof(buf), 16, "281474976710655", 0);
1142 CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 7, DATA_UNSIGNED,
1143 buf, sizeof(buf), 18, "72057594037927935", 0);
1145 CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8, DATA_UNSIGNED,
1146 buf, sizeof(buf), 21, "18446744073709551615", 0);
1148 /* some random values */
1150 CALL_AND_TEST("\x52", 1, 0,
1151 buf, sizeof(buf), 4, "-46", 0);
1153 CALL_AND_TEST("\x0E", 1, DATA_UNSIGNED,
1154 buf, sizeof(buf), 3, "14", 0);
1156 CALL_AND_TEST("\x62\xCE", 2, 0,
1157 buf, sizeof(buf), 6, "-7474", 0);
1159 CALL_AND_TEST("\x29\xD6", 2, DATA_UNSIGNED,
1160 buf, sizeof(buf), 6, "10710", 0);
1162 CALL_AND_TEST("\x7F\xFF\x90", 3, 0,
1163 buf, sizeof(buf), 5, "-112", 0);
1165 CALL_AND_TEST("\x00\xA1\x16", 3, DATA_UNSIGNED,
1166 buf, sizeof(buf), 6, "41238", 0);
1168 CALL_AND_TEST("\x7F\xFF\xFF\xF7", 4, 0,
1169 buf, sizeof(buf), 3, "-9", 0);
1171 CALL_AND_TEST("\x00\x00\x00\x5C", 4, DATA_UNSIGNED,
1172 buf, sizeof(buf), 3, "92", 0);
1174 CALL_AND_TEST("\x7F\xFF\xFF\xFF\xFF\xFF\xDC\x63", 8, 0,
1175 buf, sizeof(buf), 6, "-9117", 0);
1177 CALL_AND_TEST("\x00\x00\x00\x00\x00\x01\x64\x62", 8, DATA_UNSIGNED,
1178 buf, sizeof(buf), 6, "91234", 0);
1179 #endif
1181 /* speed test */
1183 speedo_t speedo;
1184 ulint i;
1186 speedo_reset(&speedo);
1188 for (i = 0; i < 1000000; i++) {
1189 row_raw_format_int("\x23", 1,
1190 0, buf, sizeof(buf),
1191 &format_in_hex);
1192 row_raw_format_int("\x23", 1,
1193 DATA_UNSIGNED, buf, sizeof(buf),
1194 &format_in_hex);
1196 row_raw_format_int("\x00\x00\x00\x00\x00\x01\x64\x62", 8,
1197 0, buf, sizeof(buf),
1198 &format_in_hex);
1199 row_raw_format_int("\x00\x00\x00\x00\x00\x01\x64\x62", 8,
1200 DATA_UNSIGNED, buf, sizeof(buf),
1201 &format_in_hex);
1204 speedo_show(&speedo);
1207 #endif /* UNIV_COMPILE_TEST_FUNCS */