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 /**************************************************//**
23 Created 4/20/1996 Heikki Tuuri
24 *******************************************************/
32 #include "data0type.h"
33 #include "dict0dict.h"
35 #include "ha_prototypes.h"
36 #include "mach0data.h"
41 #include "trx0purge.h"
47 #include "read0read.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 */
58 row_build_index_entry(
59 /*==================*/
60 const dtuple_t
* row
, /*!< in: row which should be
62 row_ext_t
* ext
, /*!< in: externally stored column prefixes,
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 */
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. */
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
);
94 = dict_col_get_no(col
);
96 = dtuple_get_nth_field(entry
, i
);
97 const dfield_t
* dfield2
98 = dtuple_get_nth_field(row
, col_no
);
100 = dfield_get_len(dfield2
);
102 dfield_copy(dfield
, dfield2
);
104 if (dfield_is_null(dfield
)) {
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. */
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
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
,
131 if (UNIV_LIKELY_NULL(buf
)) {
132 if (UNIV_UNLIKELY(buf
== field_ref_zero
)) {
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. */
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
));
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! */
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
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
214 row_ext_t
** ext
, /*!< out, own: cache of
215 externally stored column
217 mem_heap_t
* heap
) /*!< in: memory heap from which
218 the memory needed is allocated */
221 const dict_table_t
* table
;
224 ulint
* ext_cols
= NULL
; /* remove warning */
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
));
239 offsets
= rec_get_offsets(rec
, index
, offsets_
,
240 ULINT_UNDEFINED
, &tmp_heap
);
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
);
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
);
288 = dict_col_get_no(col
);
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
)) {
305 < dict_table_get_n_cols(col_table
));
306 col
= dict_table_get_nth_col(
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
));
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
);
328 *ext
= row_ext_create(j
, ext_cols
, row
,
329 dict_table_zip_size(index
->table
),
336 mem_heap_free(tmp_heap
);
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 */
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
355 mem_heap_t
* heap
) /*!< in: memory heap from which
356 the memory needed is allocated */
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. */
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
);
395 ut_ad(dtuple_check_typed(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! */
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
414 const rec_t
* rec
, /*!< in: record in the index;
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
427 mem_heap_t
* heap
) /*!< in: memory heap from which
428 the memory needed is allocated */
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
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
)));
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! */
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 */
480 dict_index_t
* clust_index
;
488 ulint clust_col_prefix_len
;
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
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
) {
546 = dfield_get_type(dfield
);
548 dfield_set_len(dfield
,
549 dtype_get_at_most_n_mbchars(
553 clust_col_prefix_len
,
554 len
, (char*) field
));
559 ut_ad(dtuple_check_typed(ref
));
561 mem_heap_free(tmp_heap
);
567 /*******************************************************************//**
568 Builds from a secondary index record a row reference with which we can
569 search the clustered index record. */
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)
587 trx_t
* trx
) /*!< in: transaction */
589 const dict_index_t
* clust_index
;
595 ulint clust_col_prefix_len
;
597 mem_heap_t
* heap
= NULL
;
598 ulint offsets_
[REC_OFFS_NORMAL_SIZE
];
599 rec_offs_init(offsets_
);
604 ut_ad(!dict_index_is_clust(index
));
606 if (UNIV_UNLIKELY(!index
->table
)) {
607 fputs("InnoDB: table ", stderr
);
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
);
616 clust_index
= dict_table_get_first_index(index
->table
);
618 if (UNIV_UNLIKELY(!clust_index
)) {
619 fputs("InnoDB: clust index for table ", stderr
);
624 offsets
= rec_get_offsets(rec
, index
, offsets_
,
625 ULINT_UNDEFINED
, &heap
);
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
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
) {
661 = dfield_get_type(dfield
);
663 dfield_set_len(dfield
,
664 dtype_get_at_most_n_mbchars(
668 clust_col_prefix_len
,
669 len
, (char*) field
));
674 ut_ad(dtuple_check_typed(ref
));
675 if (UNIV_LIKELY_NULL(heap
)) {
680 /***************************************************************//**
681 Searches the clustered index record for a row, if we have the row reference.
682 @return TRUE if found */
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 */
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
)) {
715 if (low_match
!= dtuple_get_n_fields(ref
)) {
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 */
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 */
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
;
758 btr_pcur_close(&pcur
);
760 *clust_index
= dict_table_get_first_index(table
);
765 /***************************************************************//**
766 Searches an index record.
767 @return TRUE if found */
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 */
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
);
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
807 @return number of bytes that were written */
812 const char* data
, /*!< in: raw data */
813 ulint data_len
, /*!< in: raw data length
815 ulint prtype
, /*!< in: precise type */
816 char* buf
, /*!< out: output buffer */
817 ulint buf_size
, /*!< in: output buffer size
819 ibool
* format_in_hex
) /*!< out: should the data be
824 if (data_len
<= sizeof(ullint
)) {
827 ibool unsigned_type
= prtype
& DATA_UNSIGNED
;
829 value
= mach_read_int_type((const byte
*) data
,
830 data_len
, unsigned_type
);
834 ret
= ut_snprintf(buf
, buf_size
, "%llu",
838 ret
= ut_snprintf(buf
, buf_size
, "%lld",
839 (long long) value
) + 1;
844 *format_in_hex
= TRUE
;
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
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
862 @return number of bytes that were written */
867 const char* data
, /*!< in: raw data */
868 ulint data_len
, /*!< in: raw data length
870 ulint prtype
, /*!< in: precise type */
871 char* buf
, /*!< out: output buffer */
872 ulint buf_size
, /*!< in: output buffer size
874 ibool
* format_in_hex
) /*!< out: should the data be
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
));
894 if (charset_coll
== DATA_MYSQL_BINARY_CHARSET_COLL
) {
896 *format_in_hex
= TRUE
;
901 return(innobase_raw_format(data
, data_len
, charset_coll
,
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
912 @return number of bytes that were written */
917 const char* data
, /*!< in: raw data */
918 ulint data_len
, /*!< in: raw data length
920 const dict_field_t
* dict_field
, /*!< in: index field */
921 char* buf
, /*!< out: output buffer */
922 ulint buf_size
) /*!< in: output buffer size
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
;
950 ret
= row_raw_format_int(data
, data_len
, prtype
,
951 buf
, buf_size
, &format_in_hex
);
962 ret
= row_raw_format_str(data
, data_len
, prtype
,
963 buf
, buf_size
, &format_in_hex
);
970 /* XXX support more data types */
974 if (UNIV_LIKELY(buf_size
> 2)) {
976 memcpy(buf
, "0x", 2);
979 ret
= 2 + ut_raw_to_hex(data
, data_len
,
991 #ifdef UNIV_COMPILE_TEST_FUNCS
996 test_row_raw_format_int()
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)\
1007 memset(buf, 'x', 10);\
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,\
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);\
1024 if (strcmp((char*) buf, buf_expected) != 0) {\
1025 fprintf(stderr, "expected buf \"%s\", got \"%s\"\n",\
1026 buf_expected, buf);\
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);\
1036 fprintf(stderr, "OK: %lu, \"%s\" %d\n\n",\
1037 (ulint) ret, buf, (int) format_in_hex);\
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);
1186 speedo_reset(&speedo
);
1188 for (i
= 0; i
< 1000000; i
++) {
1189 row_raw_format_int("\x23", 1,
1190 0, buf
, sizeof(buf
),
1192 row_raw_format_int("\x23", 1,
1193 DATA_UNSIGNED
, buf
, sizeof(buf
),
1196 row_raw_format_int("\x00\x00\x00\x00\x00\x01\x64\x62", 8,
1197 0, buf
, sizeof(buf
),
1199 row_raw_format_int("\x00\x00\x00\x00\x00\x01\x64\x62", 8,
1200 DATA_UNSIGNED
, buf
, sizeof(buf
),
1204 speedo_show(&speedo
);
1207 #endif /* UNIV_COMPILE_TEST_FUNCS */