1
/*****************************************************************************
3
Copyright (c) 1996, 2010, Innobase Oy. 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., 51 Franklin
15
St, Fifth Floor, Boston, MA 02110-1301 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
Gets the offset of trx id field, in bytes relative to the origin of
52
a clustered index record.
53
@return offset of DATA_TRX_ID */
56
row_get_trx_id_offset(
57
/*==================*/
58
const rec_t* rec __attribute__((unused)),
60
dict_index_t* index, /*!< in: clustered index */
61
const ulint* offsets)/*!< in: rec_get_offsets(rec, index) */
67
ut_ad(dict_index_is_clust(index));
68
ut_ad(rec_offs_validate(rec, index, offsets));
70
pos = dict_index_get_sys_col_pos(index, DATA_TRX_ID);
72
offset = rec_get_nth_field_offs(offsets, pos, &len);
74
ut_ad(len == DATA_TRX_ID_LEN);
79
/*****************************************************************//**
80
When an insert or purge to a table is performed, this function builds
81
the entry to be inserted into or purged from an index on the table.
82
@return index entry which should be inserted or purged, or NULL if the
83
externally stored columns in the clustered index record are
84
unavailable and ext != NULL */
87
row_build_index_entry(
88
/*==================*/
89
const dtuple_t* row, /*!< in: row which should be
91
row_ext_t* ext, /*!< in: externally stored column prefixes,
93
dict_index_t* index, /*!< in: index on the table */
94
mem_heap_t* heap) /*!< in: memory heap from which the memory for
95
the index entry is allocated */
101
ut_ad(row && index && heap);
102
ut_ad(dtuple_check_typed(row));
104
entry_len = dict_index_get_n_fields(index);
105
entry = dtuple_create(heap, entry_len);
107
if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
108
dtuple_set_n_fields_cmp(entry, entry_len);
109
/* There may only be externally stored columns
110
in a clustered index B-tree of a user table. */
113
dtuple_set_n_fields_cmp(
114
entry, dict_index_get_n_unique_in_tree(index));
117
for (i = 0; i < entry_len; i++) {
118
const dict_field_t* ind_field
119
= dict_index_get_nth_field(index, i);
120
const dict_col_t* col
123
= dict_col_get_no(col);
125
= dtuple_get_nth_field(entry, i);
126
const dfield_t* dfield2
127
= dtuple_get_nth_field(row, col_no);
129
= dfield_get_len(dfield2);
131
dfield_copy(dfield, dfield2);
133
if (dfield_is_null(dfield) || ind_field->prefix_len == 0) {
137
/* If a column prefix index, take only the prefix.
138
Prefix-indexed columns may be externally stored. */
139
ut_ad(col->ord_part);
141
if (UNIV_LIKELY_NULL(ext)) {
142
/* See if the column is stored externally. */
143
const byte* buf = row_ext_lookup(ext, col_no,
145
if (UNIV_LIKELY_NULL(buf)) {
146
if (UNIV_UNLIKELY(buf == field_ref_zero)) {
149
dfield_set_data(dfield, buf, len);
151
} else if (dfield_is_ext(dfield)) {
152
ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE);
153
len -= BTR_EXTERN_FIELD_REF_SIZE;
154
ut_a(ind_field->prefix_len <= len
155
|| dict_index_is_clust(index));
158
len = dtype_get_at_most_n_mbchars(
159
col->prtype, col->mbminmaxlen,
160
ind_field->prefix_len, len, dfield_get_data(dfield));
161
dfield_set_len(dfield, len);
164
ut_ad(dtuple_check_typed(entry));
169
/*******************************************************************//**
170
An inverse function to row_build_index_entry. Builds a row from a
171
record in a clustered index.
172
@return own: row built; see the NOTE below! */
177
ulint type, /*!< in: ROW_COPY_POINTERS or
178
ROW_COPY_DATA; the latter
179
copies also the data fields to
180
heap while the first only
181
places pointers to data fields
182
on the index page, and thus is
184
const dict_index_t* index, /*!< in: clustered index */
185
const rec_t* rec, /*!< in: record in the clustered
186
index; NOTE: in the case
187
ROW_COPY_POINTERS the data
188
fields in the row will point
189
directly into this record,
190
therefore, the buffer page of
191
this record must be at least
192
s-latched and the latch held
193
as long as the row dtuple is used! */
194
const ulint* offsets,/*!< in: rec_get_offsets(rec,index)
195
or NULL, in which case this function
196
will invoke rec_get_offsets() */
197
const dict_table_t* col_table,
198
/*!< in: table, to check which
199
externally stored columns
200
occur in the ordering columns
201
of an index, or NULL if
202
index->table should be
204
row_ext_t** ext, /*!< out, own: cache of
205
externally stored column
207
mem_heap_t* heap) /*!< in: memory heap from which
208
the memory needed is allocated */
211
const dict_table_t* table;
214
ulint* ext_cols = NULL; /* remove warning */
220
mem_heap_t* tmp_heap = NULL;
221
ulint offsets_[REC_OFFS_NORMAL_SIZE];
222
rec_offs_init(offsets_);
224
ut_ad(index && rec && heap);
225
ut_ad(dict_index_is_clust(index));
228
offsets = rec_get_offsets(rec, index, offsets_,
229
ULINT_UNDEFINED, &tmp_heap);
231
ut_ad(rec_offs_validate(rec, index, offsets));
234
if (type != ROW_COPY_POINTERS) {
235
/* Take a copy of rec to heap */
236
buf = mem_heap_alloc(heap, rec_offs_size(offsets));
237
rec = rec_copy(buf, rec, offsets);
238
/* Avoid a debug assertion in rec_offs_validate(). */
239
rec_offs_make_valid(rec, index, (ulint*) offsets);
242
table = index->table;
243
row_len = dict_table_get_n_cols(table);
245
row = dtuple_create(heap, row_len);
247
dict_table_copy_types(row, table);
249
dtuple_set_info_bits(row, rec_get_info_bits(
250
rec, dict_table_is_comp(table)));
252
n_fields = rec_offs_n_fields(offsets);
253
n_ext_cols = rec_offs_n_extern(offsets);
255
ext_cols = mem_heap_alloc(heap, n_ext_cols * sizeof *ext_cols);
258
for (i = j = 0; i < n_fields; i++) {
259
dict_field_t* ind_field
260
= dict_index_get_nth_field(index, i);
261
const dict_col_t* col
262
= dict_field_get_col(ind_field);
264
= dict_col_get_no(col);
266
= dtuple_get_nth_field(row, col_no);
268
if (ind_field->prefix_len == 0) {
270
const byte* field = rec_get_nth_field(
271
rec, offsets, i, &len);
273
dfield_set_data(dfield, field, len);
276
if (rec_offs_nth_extern(offsets, i)) {
277
dfield_set_ext(dfield);
279
if (UNIV_LIKELY_NULL(col_table)) {
281
< dict_table_get_n_cols(col_table));
282
col = dict_table_get_nth_col(
287
/* We will have to fetch prefixes of
288
externally stored columns that are
289
referenced by column prefixes. */
290
ext_cols[j++] = col_no;
295
ut_ad(dtuple_check_typed(row));
298
/* REDUNDANT and COMPACT formats store a local
299
768-byte prefix of each externally stored
300
column. No cache is needed. */
301
ut_ad(dict_table_get_format(index->table)
302
< DICT_TF_FORMAT_ZIP);
304
*ext = row_ext_create(j, ext_cols, row,
305
dict_table_zip_size(index->table),
312
mem_heap_free(tmp_heap);
318
/*******************************************************************//**
319
Converts an index record to a typed data tuple.
320
@return index entry built; does not set info_bits, and the data fields
321
in the entry will point directly to rec */
324
row_rec_to_index_entry_low(
325
/*=======================*/
326
const rec_t* rec, /*!< in: record in the index */
327
const dict_index_t* index, /*!< in: index */
328
const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */
329
ulint* n_ext, /*!< out: number of externally
331
mem_heap_t* heap) /*!< in: memory heap from which
332
the memory needed is allocated */
341
ut_ad(rec && heap && index);
342
/* Because this function may be invoked by row0merge.c
343
on a record whose header is in different format, the check
344
rec_offs_validate(rec, index, offsets) must be avoided here. */
348
rec_len = rec_offs_n_fields(offsets);
350
entry = dtuple_create(heap, rec_len);
352
dtuple_set_n_fields_cmp(entry,
353
dict_index_get_n_unique_in_tree(index));
354
ut_ad(rec_len == dict_index_get_n_fields(index));
356
dict_index_copy_types(entry, index, rec_len);
358
for (i = 0; i < rec_len; i++) {
360
dfield = dtuple_get_nth_field(entry, i);
361
field = rec_get_nth_field(rec, offsets, i, &len);
363
dfield_set_data(dfield, field, len);
365
if (rec_offs_nth_extern(offsets, i)) {
366
dfield_set_ext(dfield);
371
ut_ad(dtuple_check_typed(entry));
376
/*******************************************************************//**
377
Converts an index record to a typed data tuple. NOTE that externally
378
stored (often big) fields are NOT copied to heap.
379
@return own: index entry built; see the NOTE below! */
382
row_rec_to_index_entry(
383
/*===================*/
384
ulint type, /*!< in: ROW_COPY_DATA, or
385
ROW_COPY_POINTERS: the former
386
copies also the data fields to
387
heap as the latter only places
388
pointers to data fields on the
390
const rec_t* rec, /*!< in: record in the index;
392
ROW_COPY_POINTERS the data
393
fields in the row will point
394
directly into this record,
395
therefore, the buffer page of
396
this record must be at least
397
s-latched and the latch held
398
as long as the dtuple is used! */
399
const dict_index_t* index, /*!< in: index */
400
ulint* offsets,/*!< in/out: rec_get_offsets(rec) */
401
ulint* n_ext, /*!< out: number of externally
403
mem_heap_t* heap) /*!< in: memory heap from which
404
the memory needed is allocated */
409
ut_ad(rec && heap && index);
410
ut_ad(rec_offs_validate(rec, index, offsets));
412
if (type == ROW_COPY_DATA) {
413
/* Take a copy of rec to heap */
414
buf = mem_heap_alloc(heap, rec_offs_size(offsets));
415
rec = rec_copy(buf, rec, offsets);
416
/* Avoid a debug assertion in rec_offs_validate(). */
417
rec_offs_make_valid(rec, index, offsets);
420
entry = row_rec_to_index_entry_low(rec, index, offsets, n_ext, heap);
422
dtuple_set_info_bits(entry,
423
rec_get_info_bits(rec, rec_offs_comp(offsets)));
428
/*******************************************************************//**
429
Builds from a secondary index record a row reference with which we can
430
search the clustered index record.
431
@return own: row reference built; see the NOTE below! */
436
ulint type, /*!< in: ROW_COPY_DATA, or ROW_COPY_POINTERS:
437
the former copies also the data fields to
438
heap, whereas the latter only places pointers
439
to data fields on the index page */
440
dict_index_t* index, /*!< in: secondary index */
441
const rec_t* rec, /*!< in: record in the index;
442
NOTE: in the case ROW_COPY_POINTERS
443
the data fields in the row will point
444
directly into this record, therefore,
445
the buffer page of this record must be
446
at least s-latched and the latch held
447
as long as the row reference is used! */
448
mem_heap_t* heap) /*!< in: memory heap from which the memory
449
needed is allocated */
452
dict_index_t* clust_index;
460
ulint clust_col_prefix_len;
462
mem_heap_t* tmp_heap = NULL;
463
ulint offsets_[REC_OFFS_NORMAL_SIZE];
464
ulint* offsets = offsets_;
465
rec_offs_init(offsets_);
467
ut_ad(index && rec && heap);
468
ut_ad(!dict_index_is_clust(index));
470
offsets = rec_get_offsets(rec, index, offsets,
471
ULINT_UNDEFINED, &tmp_heap);
472
/* Secondary indexes must not contain externally stored columns. */
473
ut_ad(!rec_offs_any_extern(offsets));
475
if (type == ROW_COPY_DATA) {
476
/* Take a copy of rec to heap */
478
buf = mem_heap_alloc(heap, rec_offs_size(offsets));
480
rec = rec_copy(buf, rec, offsets);
481
/* Avoid a debug assertion in rec_offs_validate(). */
482
rec_offs_make_valid(rec, index, offsets);
485
table = index->table;
487
clust_index = dict_table_get_first_index(table);
489
ref_len = dict_index_get_n_unique(clust_index);
491
ref = dtuple_create(heap, ref_len);
493
dict_index_copy_types(ref, clust_index, ref_len);
495
for (i = 0; i < ref_len; i++) {
496
dfield = dtuple_get_nth_field(ref, i);
498
pos = dict_index_get_nth_field_pos(index, clust_index, i);
500
ut_a(pos != ULINT_UNDEFINED);
502
field = rec_get_nth_field(rec, offsets, pos, &len);
504
dfield_set_data(dfield, field, len);
506
/* If the primary key contains a column prefix, then the
507
secondary index may contain a longer prefix of the same
508
column, or the full column, and we must adjust the length
511
clust_col_prefix_len = dict_index_get_nth_field(
512
clust_index, i)->prefix_len;
514
if (clust_col_prefix_len > 0) {
515
if (len != UNIV_SQL_NULL) {
518
= dfield_get_type(dfield);
520
dfield_set_len(dfield,
521
dtype_get_at_most_n_mbchars(
524
clust_col_prefix_len,
525
len, (char*) field));
530
ut_ad(dtuple_check_typed(ref));
532
mem_heap_free(tmp_heap);
538
/*******************************************************************//**
539
Builds from a secondary index record a row reference with which we can
540
search the clustered index record. */
543
row_build_row_ref_in_tuple(
544
/*=======================*/
545
dtuple_t* ref, /*!< in/out: row reference built;
546
see the NOTE below! */
547
const rec_t* rec, /*!< in: record in the index;
548
NOTE: the data fields in ref
549
will point directly into this
550
record, therefore, the buffer
551
page of this record must be at
552
least s-latched and the latch
553
held as long as the row
554
reference is used! */
555
const dict_index_t* index, /*!< in: secondary index */
556
ulint* offsets,/*!< in: rec_get_offsets(rec, index)
558
trx_t* trx) /*!< in: transaction */
560
const dict_index_t* clust_index;
566
ulint clust_col_prefix_len;
568
mem_heap_t* heap = NULL;
569
ulint offsets_[REC_OFFS_NORMAL_SIZE];
570
rec_offs_init(offsets_);
575
ut_ad(!dict_index_is_clust(index));
577
if (UNIV_UNLIKELY(!index->table)) {
578
fputs("InnoDB: table ", stderr);
580
ut_print_name(stderr, trx, TRUE, index->table_name);
581
fputs(" for index ", stderr);
582
ut_print_name(stderr, trx, FALSE, index->name);
583
fputs(" not found\n", stderr);
587
clust_index = dict_table_get_first_index(index->table);
589
if (UNIV_UNLIKELY(!clust_index)) {
590
fputs("InnoDB: clust index for table ", stderr);
595
offsets = rec_get_offsets(rec, index, offsets_,
596
ULINT_UNDEFINED, &heap);
598
ut_ad(rec_offs_validate(rec, index, offsets));
601
/* Secondary indexes must not contain externally stored columns. */
602
ut_ad(!rec_offs_any_extern(offsets));
603
ref_len = dict_index_get_n_unique(clust_index);
605
ut_ad(ref_len == dtuple_get_n_fields(ref));
607
dict_index_copy_types(ref, clust_index, ref_len);
609
for (i = 0; i < ref_len; i++) {
610
dfield = dtuple_get_nth_field(ref, i);
612
pos = dict_index_get_nth_field_pos(index, clust_index, i);
614
ut_a(pos != ULINT_UNDEFINED);
616
field = rec_get_nth_field(rec, offsets, pos, &len);
618
dfield_set_data(dfield, field, len);
620
/* If the primary key contains a column prefix, then the
621
secondary index may contain a longer prefix of the same
622
column, or the full column, and we must adjust the length
625
clust_col_prefix_len = dict_index_get_nth_field(
626
clust_index, i)->prefix_len;
628
if (clust_col_prefix_len > 0) {
629
if (len != UNIV_SQL_NULL) {
632
= dfield_get_type(dfield);
634
dfield_set_len(dfield,
635
dtype_get_at_most_n_mbchars(
638
clust_col_prefix_len,
639
len, (char*) field));
644
ut_ad(dtuple_check_typed(ref));
645
if (UNIV_LIKELY_NULL(heap)) {
650
/***************************************************************//**
651
Searches the clustered index record for a row, if we have the row reference.
652
@return TRUE if found */
655
row_search_on_row_ref(
656
/*==================*/
657
btr_pcur_t* pcur, /*!< out: persistent cursor, which must
658
be closed by the caller */
659
ulint mode, /*!< in: BTR_MODIFY_LEAF, ... */
660
const dict_table_t* table, /*!< in: table */
661
const dtuple_t* ref, /*!< in: row reference */
662
mtr_t* mtr) /*!< in/out: mtr */
668
ut_ad(dtuple_check_typed(ref));
670
index = dict_table_get_first_index(table);
672
ut_a(dtuple_get_n_fields(ref) == dict_index_get_n_unique(index));
674
btr_pcur_open(index, ref, PAGE_CUR_LE, mode, pcur, mtr);
676
low_match = btr_pcur_get_low_match(pcur);
678
rec = btr_pcur_get_rec(pcur);
680
if (page_rec_is_infimum(rec)) {
685
if (low_match != dtuple_get_n_fields(ref)) {
693
/*********************************************************************//**
694
Fetches the clustered index record for a secondary index record. The latches
695
on the secondary index record are preserved.
696
@return record or NULL, if no record found */
701
ulint mode, /*!< in: BTR_MODIFY_LEAF, ... */
702
const rec_t* rec, /*!< in: record in a secondary index */
703
dict_index_t* index, /*!< in: secondary index */
704
dict_index_t** clust_index,/*!< out: clustered index */
705
mtr_t* mtr) /*!< in: mtr */
714
ut_ad(!dict_index_is_clust(index));
716
table = index->table;
718
heap = mem_heap_create(256);
720
ref = row_build_row_ref(ROW_COPY_POINTERS, index, rec, heap);
722
found = row_search_on_row_ref(&pcur, mode, table, ref, mtr);
724
clust_rec = found ? btr_pcur_get_rec(&pcur) : NULL;
728
btr_pcur_close(&pcur);
730
*clust_index = dict_table_get_first_index(table);
735
/***************************************************************//**
736
Searches an index record.
737
@return whether the record was found or buffered */
739
enum row_search_result
740
row_search_index_entry(
741
/*===================*/
742
dict_index_t* index, /*!< in: index */
743
const dtuple_t* entry, /*!< in: index entry */
744
ulint mode, /*!< in: BTR_MODIFY_LEAF, ... */
745
btr_pcur_t* pcur, /*!< in/out: persistent cursor, which must
746
be closed by the caller */
747
mtr_t* mtr) /*!< in: mtr */
753
ut_ad(dtuple_check_typed(entry));
755
btr_pcur_open(index, entry, PAGE_CUR_LE, mode, pcur, mtr);
757
switch (btr_pcur_get_btr_cur(pcur)->flag) {
758
case BTR_CUR_DELETE_REF:
759
ut_a(mode & BTR_DELETE);
760
return(ROW_NOT_DELETED_REF);
762
case BTR_CUR_DEL_MARK_IBUF:
763
case BTR_CUR_DELETE_IBUF:
764
case BTR_CUR_INSERT_TO_IBUF:
765
return(ROW_BUFFERED);
768
case BTR_CUR_HASH_FAIL:
773
low_match = btr_pcur_get_low_match(pcur);
775
rec = btr_pcur_get_rec(pcur);
777
n_fields = dtuple_get_n_fields(entry);
779
if (page_rec_is_infimum(rec)) {
781
return(ROW_NOT_FOUND);
782
} else if (low_match != n_fields) {
784
return(ROW_NOT_FOUND);
790
#if !defined(BUILD_DRIZZLE)
795
/*******************************************************************//**
796
Formats the raw data in "data" (in InnoDB on-disk format) that is of
797
type DATA_INT using "prtype" and writes the result to "buf".
798
If the data is in unknown format, then nothing is written to "buf",
799
0 is returned and "format_in_hex" is set to TRUE, otherwise
800
"format_in_hex" is left untouched.
801
Not more than "buf_size" bytes are written to "buf".
802
The result is always '\0'-terminated (provided buf_size > 0) and the
803
number of bytes that were written to "buf" is returned (including the
805
@return number of bytes that were written */
810
const char* data, /*!< in: raw data */
811
ulint data_len, /*!< in: raw data length
813
ulint prtype, /*!< in: precise type */
814
char* buf, /*!< out: output buffer */
815
ulint buf_size, /*!< in: output buffer size
817
ibool* format_in_hex) /*!< out: should the data be
822
if (data_len <= sizeof(ullint)) {
825
ibool unsigned_type = prtype & DATA_UNSIGNED;
827
value = mach_read_int_type((const byte*) data,
828
data_len, unsigned_type);
832
ret = ut_snprintf(buf, buf_size, "%llu",
836
ret = ut_snprintf(buf, buf_size, "%lld",
837
(long long) value) + 1;
842
*format_in_hex = TRUE;
846
return(ut_min(ret, buf_size));
849
/*******************************************************************//**
850
Formats the raw data in "data" (in InnoDB on-disk format) that is of
851
type DATA_(CHAR|VARCHAR|MYSQL|VARMYSQL) using "prtype" and writes the
853
If the data is in binary format, then nothing is written to "buf",
854
0 is returned and "format_in_hex" is set to TRUE, otherwise
855
"format_in_hex" is left untouched.
856
Not more than "buf_size" bytes are written to "buf".
857
The result is always '\0'-terminated (provided buf_size > 0) and the
858
number of bytes that were written to "buf" is returned (including the
860
@return number of bytes that were written */
865
const char* data, /*!< in: raw data */
866
ulint data_len, /*!< in: raw data length
868
ulint prtype, /*!< in: precise type */
869
char* buf, /*!< out: output buffer */
870
ulint buf_size, /*!< in: output buffer size
872
ibool* format_in_hex) /*!< out: should the data be
882
/* we assume system_charset_info is UTF-8 */
884
charset_coll = dtype_get_charset_coll(prtype);
886
if (UNIV_LIKELY(dtype_is_utf8(prtype))) {
888
return(ut_str_sql_format(data, data_len, buf, buf_size));
892
if (charset_coll == DATA_MYSQL_BINARY_CHARSET_COLL) {
894
*format_in_hex = TRUE;
899
return(innobase_raw_format(data, data_len, charset_coll,
903
/*******************************************************************//**
904
Formats the raw data in "data" (in InnoDB on-disk format) using
905
"dict_field" and writes the result to "buf".
906
Not more than "buf_size" bytes are written to "buf".
907
The result is always NUL-terminated (provided buf_size is positive) and the
908
number of bytes that were written to "buf" is returned (including the
910
@return number of bytes that were written */
915
const char* data, /*!< in: raw data */
916
ulint data_len, /*!< in: raw data length
918
const dict_field_t* dict_field, /*!< in: index field */
919
char* buf, /*!< out: output buffer */
920
ulint buf_size) /*!< in: output buffer size
933
if (data_len == UNIV_SQL_NULL) {
935
ret = ut_snprintf((char*) buf, buf_size, "NULL") + 1;
937
return(ut_min(ret, buf_size));
940
mtype = dict_field->col->mtype;
941
prtype = dict_field->col->prtype;
943
format_in_hex = FALSE;
948
ret = row_raw_format_int(data, data_len, prtype,
949
buf, buf_size, &format_in_hex);
960
ret = row_raw_format_str(data, data_len, prtype,
961
buf, buf_size, &format_in_hex);
968
/* XXX support more data types */
972
if (UNIV_LIKELY(buf_size > 2)) {
974
memcpy(buf, "0x", 2);
977
ret = 2 + ut_raw_to_hex(data, data_len,
989
#ifdef UNIV_COMPILE_TEST_FUNCS
994
test_row_raw_format_int()
1000
#define CALL_AND_TEST(data, data_len, prtype, buf, buf_size,\
1001
ret_expected, buf_expected, format_in_hex_expected)\
1005
memset(buf, 'x', 10);\
1007
format_in_hex = FALSE;\
1008
fprintf(stderr, "TESTING \"\\x");\
1009
for (i = 0; i < data_len; i++) {\
1010
fprintf(stderr, "%02hhX", data[i]);\
1012
fprintf(stderr, "\", %lu, %lu, %lu\n",\
1013
(ulint) data_len, (ulint) prtype,\
1015
ret = row_raw_format_int(data, data_len, prtype,\
1016
buf, buf_size, &format_in_hex);\
1017
if (ret != ret_expected) {\
1018
fprintf(stderr, "expected ret %lu, got %lu\n",\
1019
(ulint) ret_expected, ret);\
1022
if (strcmp((char*) buf, buf_expected) != 0) {\
1023
fprintf(stderr, "expected buf \"%s\", got \"%s\"\n",\
1024
buf_expected, buf);\
1027
if (format_in_hex != format_in_hex_expected) {\
1028
fprintf(stderr, "expected format_in_hex %d, got %d\n",\
1029
(int) format_in_hex_expected,\
1030
(int) format_in_hex);\
1034
fprintf(stderr, "OK: %lu, \"%s\" %d\n\n",\
1035
(ulint) ret, buf, (int) format_in_hex);\
1042
/* min values for signed 1-8 byte integers */
1044
CALL_AND_TEST("\x00", 1, 0,
1045
buf, sizeof(buf), 5, "-128", 0);
1047
CALL_AND_TEST("\x00\x00", 2, 0,
1048
buf, sizeof(buf), 7, "-32768", 0);
1050
CALL_AND_TEST("\x00\x00\x00", 3, 0,
1051
buf, sizeof(buf), 9, "-8388608", 0);
1053
CALL_AND_TEST("\x00\x00\x00\x00", 4, 0,
1054
buf, sizeof(buf), 12, "-2147483648", 0);
1056
CALL_AND_TEST("\x00\x00\x00\x00\x00", 5, 0,
1057
buf, sizeof(buf), 14, "-549755813888", 0);
1059
CALL_AND_TEST("\x00\x00\x00\x00\x00\x00", 6, 0,
1060
buf, sizeof(buf), 17, "-140737488355328", 0);
1062
CALL_AND_TEST("\x00\x00\x00\x00\x00\x00\x00", 7, 0,
1063
buf, sizeof(buf), 19, "-36028797018963968", 0);
1065
CALL_AND_TEST("\x00\x00\x00\x00\x00\x00\x00\x00", 8, 0,
1066
buf, sizeof(buf), 21, "-9223372036854775808", 0);
1068
/* min values for unsigned 1-8 byte integers */
1070
CALL_AND_TEST("\x00", 1, DATA_UNSIGNED,
1071
buf, sizeof(buf), 2, "0", 0);
1073
CALL_AND_TEST("\x00\x00", 2, DATA_UNSIGNED,
1074
buf, sizeof(buf), 2, "0", 0);
1076
CALL_AND_TEST("\x00\x00\x00", 3, DATA_UNSIGNED,
1077
buf, sizeof(buf), 2, "0", 0);
1079
CALL_AND_TEST("\x00\x00\x00\x00", 4, DATA_UNSIGNED,
1080
buf, sizeof(buf), 2, "0", 0);
1082
CALL_AND_TEST("\x00\x00\x00\x00\x00", 5, DATA_UNSIGNED,
1083
buf, sizeof(buf), 2, "0", 0);
1085
CALL_AND_TEST("\x00\x00\x00\x00\x00\x00", 6, DATA_UNSIGNED,
1086
buf, sizeof(buf), 2, "0", 0);
1088
CALL_AND_TEST("\x00\x00\x00\x00\x00\x00\x00", 7, DATA_UNSIGNED,
1089
buf, sizeof(buf), 2, "0", 0);
1091
CALL_AND_TEST("\x00\x00\x00\x00\x00\x00\x00\x00", 8, DATA_UNSIGNED,
1092
buf, sizeof(buf), 2, "0", 0);
1094
/* max values for signed 1-8 byte integers */
1096
CALL_AND_TEST("\xFF", 1, 0,
1097
buf, sizeof(buf), 4, "127", 0);
1099
CALL_AND_TEST("\xFF\xFF", 2, 0,
1100
buf, sizeof(buf), 6, "32767", 0);
1102
CALL_AND_TEST("\xFF\xFF\xFF", 3, 0,
1103
buf, sizeof(buf), 8, "8388607", 0);
1105
CALL_AND_TEST("\xFF\xFF\xFF\xFF", 4, 0,
1106
buf, sizeof(buf), 11, "2147483647", 0);
1108
CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF", 5, 0,
1109
buf, sizeof(buf), 13, "549755813887", 0);
1111
CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF", 6, 0,
1112
buf, sizeof(buf), 16, "140737488355327", 0);
1114
CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 7, 0,
1115
buf, sizeof(buf), 18, "36028797018963967", 0);
1117
CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8, 0,
1118
buf, sizeof(buf), 20, "9223372036854775807", 0);
1120
/* max values for unsigned 1-8 byte integers */
1122
CALL_AND_TEST("\xFF", 1, DATA_UNSIGNED,
1123
buf, sizeof(buf), 4, "255", 0);
1125
CALL_AND_TEST("\xFF\xFF", 2, DATA_UNSIGNED,
1126
buf, sizeof(buf), 6, "65535", 0);
1128
CALL_AND_TEST("\xFF\xFF\xFF", 3, DATA_UNSIGNED,
1129
buf, sizeof(buf), 9, "16777215", 0);
1131
CALL_AND_TEST("\xFF\xFF\xFF\xFF", 4, DATA_UNSIGNED,
1132
buf, sizeof(buf), 11, "4294967295", 0);
1134
CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF", 5, DATA_UNSIGNED,
1135
buf, sizeof(buf), 14, "1099511627775", 0);
1137
CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF", 6, DATA_UNSIGNED,
1138
buf, sizeof(buf), 16, "281474976710655", 0);
1140
CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 7, DATA_UNSIGNED,
1141
buf, sizeof(buf), 18, "72057594037927935", 0);
1143
CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8, DATA_UNSIGNED,
1144
buf, sizeof(buf), 21, "18446744073709551615", 0);
1146
/* some random values */
1148
CALL_AND_TEST("\x52", 1, 0,
1149
buf, sizeof(buf), 4, "-46", 0);
1151
CALL_AND_TEST("\x0E", 1, DATA_UNSIGNED,
1152
buf, sizeof(buf), 3, "14", 0);
1154
CALL_AND_TEST("\x62\xCE", 2, 0,
1155
buf, sizeof(buf), 6, "-7474", 0);
1157
CALL_AND_TEST("\x29\xD6", 2, DATA_UNSIGNED,
1158
buf, sizeof(buf), 6, "10710", 0);
1160
CALL_AND_TEST("\x7F\xFF\x90", 3, 0,
1161
buf, sizeof(buf), 5, "-112", 0);
1163
CALL_AND_TEST("\x00\xA1\x16", 3, DATA_UNSIGNED,
1164
buf, sizeof(buf), 6, "41238", 0);
1166
CALL_AND_TEST("\x7F\xFF\xFF\xF7", 4, 0,
1167
buf, sizeof(buf), 3, "-9", 0);
1169
CALL_AND_TEST("\x00\x00\x00\x5C", 4, DATA_UNSIGNED,
1170
buf, sizeof(buf), 3, "92", 0);
1172
CALL_AND_TEST("\x7F\xFF\xFF\xFF\xFF\xFF\xDC\x63", 8, 0,
1173
buf, sizeof(buf), 6, "-9117", 0);
1175
CALL_AND_TEST("\x00\x00\x00\x00\x00\x01\x64\x62", 8, DATA_UNSIGNED,
1176
buf, sizeof(buf), 6, "91234", 0);
1184
speedo_reset(&speedo);
1186
for (i = 0; i < 1000000; i++) {
1187
row_raw_format_int("\x23", 1,
1188
0, buf, sizeof(buf),
1190
row_raw_format_int("\x23", 1,
1191
DATA_UNSIGNED, buf, sizeof(buf),
1194
row_raw_format_int("\x00\x00\x00\x00\x00\x01\x64\x62", 8,
1195
0, buf, sizeof(buf),
1197
row_raw_format_int("\x00\x00\x00\x00\x00\x01\x64\x62", 8,
1198
DATA_UNSIGNED, buf, sizeof(buf),
1202
speedo_show(&speedo);
1205
#endif /* UNIV_COMPILE_TEST_FUNCS */