1
/*****************************************************************************
3
Copyright (c) 1996, 2009, 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., 59 Temple
15
Place, Suite 330, Boston, MA 02111-1307 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->mbminlen, col->mbmaxlen,
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
*ext = row_ext_create(j, ext_cols, row,
299
dict_table_zip_size(index->table),
306
mem_heap_free(tmp_heap);
312
/*******************************************************************//**
313
Converts an index record to a typed data tuple.
314
@return index entry built; does not set info_bits, and the data fields
315
in the entry will point directly to rec */
318
row_rec_to_index_entry_low(
319
/*=======================*/
320
const rec_t* rec, /*!< in: record in the index */
321
const dict_index_t* index, /*!< in: index */
322
const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */
323
ulint* n_ext, /*!< out: number of externally
325
mem_heap_t* heap) /*!< in: memory heap from which
326
the memory needed is allocated */
335
ut_ad(rec && heap && index);
336
/* Because this function may be invoked by row0merge.c
337
on a record whose header is in different format, the check
338
rec_offs_validate(rec, index, offsets) must be avoided here. */
342
rec_len = rec_offs_n_fields(offsets);
344
entry = dtuple_create(heap, rec_len);
346
dtuple_set_n_fields_cmp(entry,
347
dict_index_get_n_unique_in_tree(index));
348
ut_ad(rec_len == dict_index_get_n_fields(index));
350
dict_index_copy_types(entry, index, rec_len);
352
for (i = 0; i < rec_len; i++) {
354
dfield = dtuple_get_nth_field(entry, i);
355
field = rec_get_nth_field(rec, offsets, i, &len);
357
dfield_set_data(dfield, field, len);
359
if (rec_offs_nth_extern(offsets, i)) {
360
dfield_set_ext(dfield);
365
ut_ad(dtuple_check_typed(entry));
370
/*******************************************************************//**
371
Converts an index record to a typed data tuple. NOTE that externally
372
stored (often big) fields are NOT copied to heap.
373
@return own: index entry built; see the NOTE below! */
376
row_rec_to_index_entry(
377
/*===================*/
378
ulint type, /*!< in: ROW_COPY_DATA, or
379
ROW_COPY_POINTERS: the former
380
copies also the data fields to
381
heap as the latter only places
382
pointers to data fields on the
384
const rec_t* rec, /*!< in: record in the index;
386
ROW_COPY_POINTERS the data
387
fields in the row will point
388
directly into this record,
389
therefore, the buffer page of
390
this record must be at least
391
s-latched and the latch held
392
as long as the dtuple is used! */
393
const dict_index_t* index, /*!< in: index */
394
ulint* offsets,/*!< in/out: rec_get_offsets(rec) */
395
ulint* n_ext, /*!< out: number of externally
397
mem_heap_t* heap) /*!< in: memory heap from which
398
the memory needed is allocated */
403
ut_ad(rec && heap && index);
404
ut_ad(rec_offs_validate(rec, index, offsets));
406
if (type == ROW_COPY_DATA) {
407
/* Take a copy of rec to heap */
408
buf = mem_heap_alloc(heap, rec_offs_size(offsets));
409
rec = rec_copy(buf, rec, offsets);
410
/* Avoid a debug assertion in rec_offs_validate(). */
411
rec_offs_make_valid(rec, index, offsets);
414
entry = row_rec_to_index_entry_low(rec, index, offsets, n_ext, heap);
416
dtuple_set_info_bits(entry,
417
rec_get_info_bits(rec, rec_offs_comp(offsets)));
422
/*******************************************************************//**
423
Builds from a secondary index record a row reference with which we can
424
search the clustered index record.
425
@return own: row reference built; see the NOTE below! */
430
ulint type, /*!< in: ROW_COPY_DATA, or ROW_COPY_POINTERS:
431
the former copies also the data fields to
432
heap, whereas the latter only places pointers
433
to data fields on the index page */
434
dict_index_t* index, /*!< in: secondary index */
435
const rec_t* rec, /*!< in: record in the index;
436
NOTE: in the case ROW_COPY_POINTERS
437
the data fields in the row will point
438
directly into this record, therefore,
439
the buffer page of this record must be
440
at least s-latched and the latch held
441
as long as the row reference is used! */
442
mem_heap_t* heap) /*!< in: memory heap from which the memory
443
needed is allocated */
446
dict_index_t* clust_index;
454
ulint clust_col_prefix_len;
456
mem_heap_t* tmp_heap = NULL;
457
ulint offsets_[REC_OFFS_NORMAL_SIZE];
458
ulint* offsets = offsets_;
459
rec_offs_init(offsets_);
461
ut_ad(index && rec && heap);
462
ut_ad(!dict_index_is_clust(index));
464
offsets = rec_get_offsets(rec, index, offsets,
465
ULINT_UNDEFINED, &tmp_heap);
466
/* Secondary indexes must not contain externally stored columns. */
467
ut_ad(!rec_offs_any_extern(offsets));
469
if (type == ROW_COPY_DATA) {
470
/* Take a copy of rec to heap */
472
buf = mem_heap_alloc(heap, rec_offs_size(offsets));
474
rec = rec_copy(buf, rec, offsets);
475
/* Avoid a debug assertion in rec_offs_validate(). */
476
rec_offs_make_valid(rec, index, offsets);
479
table = index->table;
481
clust_index = dict_table_get_first_index(table);
483
ref_len = dict_index_get_n_unique(clust_index);
485
ref = dtuple_create(heap, ref_len);
487
dict_index_copy_types(ref, clust_index, ref_len);
489
for (i = 0; i < ref_len; i++) {
490
dfield = dtuple_get_nth_field(ref, i);
492
pos = dict_index_get_nth_field_pos(index, clust_index, i);
494
ut_a(pos != ULINT_UNDEFINED);
496
field = rec_get_nth_field(rec, offsets, pos, &len);
498
dfield_set_data(dfield, field, len);
500
/* If the primary key contains a column prefix, then the
501
secondary index may contain a longer prefix of the same
502
column, or the full column, and we must adjust the length
505
clust_col_prefix_len = dict_index_get_nth_field(
506
clust_index, i)->prefix_len;
508
if (clust_col_prefix_len > 0) {
509
if (len != UNIV_SQL_NULL) {
512
= dfield_get_type(dfield);
514
dfield_set_len(dfield,
515
dtype_get_at_most_n_mbchars(
519
clust_col_prefix_len,
520
len, (char*) field));
525
ut_ad(dtuple_check_typed(ref));
527
mem_heap_free(tmp_heap);
533
/*******************************************************************//**
534
Builds from a secondary index record a row reference with which we can
535
search the clustered index record. */
538
row_build_row_ref_in_tuple(
539
/*=======================*/
540
dtuple_t* ref, /*!< in/out: row reference built;
541
see the NOTE below! */
542
const rec_t* rec, /*!< in: record in the index;
543
NOTE: the data fields in ref
544
will point directly into this
545
record, therefore, the buffer
546
page of this record must be at
547
least s-latched and the latch
548
held as long as the row
549
reference is used! */
550
const dict_index_t* index, /*!< in: secondary index */
551
ulint* offsets,/*!< in: rec_get_offsets(rec, index)
553
trx_t* trx) /*!< in: transaction */
555
const dict_index_t* clust_index;
561
ulint clust_col_prefix_len;
563
mem_heap_t* heap = NULL;
564
ulint offsets_[REC_OFFS_NORMAL_SIZE];
565
rec_offs_init(offsets_);
570
ut_ad(!dict_index_is_clust(index));
572
if (UNIV_UNLIKELY(!index->table)) {
573
fputs("InnoDB: table ", stderr);
575
ut_print_name(stderr, trx, TRUE, index->table_name);
576
fputs(" for index ", stderr);
577
ut_print_name(stderr, trx, FALSE, index->name);
578
fputs(" not found\n", stderr);
582
clust_index = dict_table_get_first_index(index->table);
584
if (UNIV_UNLIKELY(!clust_index)) {
585
fputs("InnoDB: clust index for table ", stderr);
590
offsets = rec_get_offsets(rec, index, offsets_,
591
ULINT_UNDEFINED, &heap);
593
ut_ad(rec_offs_validate(rec, index, offsets));
596
/* Secondary indexes must not contain externally stored columns. */
597
ut_ad(!rec_offs_any_extern(offsets));
598
ref_len = dict_index_get_n_unique(clust_index);
600
ut_ad(ref_len == dtuple_get_n_fields(ref));
602
dict_index_copy_types(ref, clust_index, ref_len);
604
for (i = 0; i < ref_len; i++) {
605
dfield = dtuple_get_nth_field(ref, i);
607
pos = dict_index_get_nth_field_pos(index, clust_index, i);
609
ut_a(pos != ULINT_UNDEFINED);
611
field = rec_get_nth_field(rec, offsets, pos, &len);
613
dfield_set_data(dfield, field, len);
615
/* If the primary key contains a column prefix, then the
616
secondary index may contain a longer prefix of the same
617
column, or the full column, and we must adjust the length
620
clust_col_prefix_len = dict_index_get_nth_field(
621
clust_index, i)->prefix_len;
623
if (clust_col_prefix_len > 0) {
624
if (len != UNIV_SQL_NULL) {
627
= dfield_get_type(dfield);
629
dfield_set_len(dfield,
630
dtype_get_at_most_n_mbchars(
634
clust_col_prefix_len,
635
len, (char*) field));
640
ut_ad(dtuple_check_typed(ref));
641
if (UNIV_LIKELY_NULL(heap)) {
646
/***************************************************************//**
647
Searches the clustered index record for a row, if we have the row reference.
648
@return TRUE if found */
651
row_search_on_row_ref(
652
/*==================*/
653
btr_pcur_t* pcur, /*!< out: persistent cursor, which must
654
be closed by the caller */
655
ulint mode, /*!< in: BTR_MODIFY_LEAF, ... */
656
const dict_table_t* table, /*!< in: table */
657
const dtuple_t* ref, /*!< in: row reference */
658
mtr_t* mtr) /*!< in/out: mtr */
664
ut_ad(dtuple_check_typed(ref));
666
index = dict_table_get_first_index(table);
668
ut_a(dtuple_get_n_fields(ref) == dict_index_get_n_unique(index));
670
btr_pcur_open(index, ref, PAGE_CUR_LE, mode, pcur, mtr);
672
low_match = btr_pcur_get_low_match(pcur);
674
rec = btr_pcur_get_rec(pcur);
676
if (page_rec_is_infimum(rec)) {
681
if (low_match != dtuple_get_n_fields(ref)) {
689
/*********************************************************************//**
690
Fetches the clustered index record for a secondary index record. The latches
691
on the secondary index record are preserved.
692
@return record or NULL, if no record found */
697
ulint mode, /*!< in: BTR_MODIFY_LEAF, ... */
698
const rec_t* rec, /*!< in: record in a secondary index */
699
dict_index_t* index, /*!< in: secondary index */
700
dict_index_t** clust_index,/*!< out: clustered index */
701
mtr_t* mtr) /*!< in: mtr */
710
ut_ad(!dict_index_is_clust(index));
712
table = index->table;
714
heap = mem_heap_create(256);
716
ref = row_build_row_ref(ROW_COPY_POINTERS, index, rec, heap);
718
found = row_search_on_row_ref(&pcur, mode, table, ref, mtr);
720
clust_rec = found ? btr_pcur_get_rec(&pcur) : NULL;
724
btr_pcur_close(&pcur);
726
*clust_index = dict_table_get_first_index(table);
731
/***************************************************************//**
732
Searches an index record.
733
@return TRUE if found */
736
row_search_index_entry(
737
/*===================*/
738
dict_index_t* index, /*!< in: index */
739
const dtuple_t* entry, /*!< in: index entry */
740
ulint mode, /*!< in: BTR_MODIFY_LEAF, ... */
741
btr_pcur_t* pcur, /*!< in/out: persistent cursor, which must
742
be closed by the caller */
743
mtr_t* mtr) /*!< in: mtr */
749
ut_ad(dtuple_check_typed(entry));
751
btr_pcur_open(index, entry, PAGE_CUR_LE, mode, pcur, mtr);
752
low_match = btr_pcur_get_low_match(pcur);
754
rec = btr_pcur_get_rec(pcur);
756
n_fields = dtuple_get_n_fields(entry);
758
return(!page_rec_is_infimum(rec) && low_match == n_fields);
761
#if !defined(BUILD_DRIZZLE)
766
/*******************************************************************//**
767
Formats the raw data in "data" (in InnoDB on-disk format) that is of
768
type DATA_INT using "prtype" and writes the result to "buf".
769
If the data is in unknown format, then nothing is written to "buf",
770
0 is returned and "format_in_hex" is set to TRUE, otherwise
771
"format_in_hex" is left untouched.
772
Not more than "buf_size" bytes are written to "buf".
773
The result is always '\0'-terminated (provided buf_size > 0) and the
774
number of bytes that were written to "buf" is returned (including the
776
@return number of bytes that were written */
781
const char* data, /*!< in: raw data */
782
ulint data_len, /*!< in: raw data length
784
ulint prtype, /*!< in: precise type */
785
char* buf, /*!< out: output buffer */
786
ulint buf_size, /*!< in: output buffer size
788
ibool* format_in_hex) /*!< out: should the data be
793
if (data_len <= sizeof(ullint)) {
796
ibool unsigned_type = prtype & DATA_UNSIGNED;
798
value = mach_read_int_type((const byte*) data,
799
data_len, unsigned_type);
803
ret = ut_snprintf(buf, buf_size, "%llu",
807
ret = ut_snprintf(buf, buf_size, "%lld",
808
(long long) value) + 1;
813
*format_in_hex = TRUE;
817
return(ut_min(ret, buf_size));
820
/*******************************************************************//**
821
Formats the raw data in "data" (in InnoDB on-disk format) that is of
822
type DATA_(CHAR|VARCHAR|MYSQL|VARMYSQL) using "prtype" and writes the
824
If the data is in binary format, then nothing is written to "buf",
825
0 is returned and "format_in_hex" is set to TRUE, otherwise
826
"format_in_hex" is left untouched.
827
Not more than "buf_size" bytes are written to "buf".
828
The result is always '\0'-terminated (provided buf_size > 0) and the
829
number of bytes that were written to "buf" is returned (including the
831
@return number of bytes that were written */
836
const char* data, /*!< in: raw data */
837
ulint data_len, /*!< in: raw data length
839
ulint prtype, /*!< in: precise type */
840
char* buf, /*!< out: output buffer */
841
ulint buf_size, /*!< in: output buffer size
843
ibool* format_in_hex) /*!< out: should the data be
853
/* we assume system_charset_info is UTF-8 */
855
charset_coll = dtype_get_charset_coll(prtype);
857
if (UNIV_LIKELY(dtype_is_utf8(prtype))) {
859
return(ut_str_sql_format(data, data_len, buf, buf_size));
863
if (charset_coll == DATA_MYSQL_BINARY_CHARSET_COLL) {
865
*format_in_hex = TRUE;
870
return(innobase_raw_format(data, data_len, charset_coll,
874
/*******************************************************************//**
875
Formats the raw data in "data" (in InnoDB on-disk format) using
876
"dict_field" and writes the result to "buf".
877
Not more than "buf_size" bytes are written to "buf".
878
The result is always NUL-terminated (provided buf_size is positive) and the
879
number of bytes that were written to "buf" is returned (including the
881
@return number of bytes that were written */
886
const char* data, /*!< in: raw data */
887
ulint data_len, /*!< in: raw data length
889
const dict_field_t* dict_field, /*!< in: index field */
890
char* buf, /*!< out: output buffer */
891
ulint buf_size) /*!< in: output buffer size
904
if (data_len == UNIV_SQL_NULL) {
906
ret = ut_snprintf((char*) buf, buf_size, "NULL") + 1;
908
return(ut_min(ret, buf_size));
911
mtype = dict_field->col->mtype;
912
prtype = dict_field->col->prtype;
914
format_in_hex = FALSE;
919
ret = row_raw_format_int(data, data_len, prtype,
920
buf, buf_size, &format_in_hex);
927
ret = row_raw_format_str(data, data_len, prtype,
928
buf, buf_size, &format_in_hex);
930
/* XXX support more data types */
933
format_in_hex = TRUE;
938
if (UNIV_LIKELY(buf_size > 2)) {
940
memcpy(buf, "0x", 2);
943
ret = 2 + ut_raw_to_hex(data, data_len,
955
#ifdef UNIV_COMPILE_TEST_FUNCS
960
test_row_raw_format_int()
966
#define CALL_AND_TEST(data, data_len, prtype, buf, buf_size,\
967
ret_expected, buf_expected, format_in_hex_expected)\
971
memset(buf, 'x', 10);\
973
format_in_hex = FALSE;\
974
fprintf(stderr, "TESTING \"\\x");\
975
for (i = 0; i < data_len; i++) {\
976
fprintf(stderr, "%02hhX", data[i]);\
978
fprintf(stderr, "\", %lu, %lu, %lu\n",\
979
(ulint) data_len, (ulint) prtype,\
981
ret = row_raw_format_int(data, data_len, prtype,\
982
buf, buf_size, &format_in_hex);\
983
if (ret != ret_expected) {\
984
fprintf(stderr, "expected ret %lu, got %lu\n",\
985
(ulint) ret_expected, ret);\
988
if (strcmp((char*) buf, buf_expected) != 0) {\
989
fprintf(stderr, "expected buf \"%s\", got \"%s\"\n",\
993
if (format_in_hex != format_in_hex_expected) {\
994
fprintf(stderr, "expected format_in_hex %d, got %d\n",\
995
(int) format_in_hex_expected,\
996
(int) format_in_hex);\
1000
fprintf(stderr, "OK: %lu, \"%s\" %d\n\n",\
1001
(ulint) ret, buf, (int) format_in_hex);\
1008
/* min values for signed 1-8 byte integers */
1010
CALL_AND_TEST("\x00", 1, 0,
1011
buf, sizeof(buf), 5, "-128", 0);
1013
CALL_AND_TEST("\x00\x00", 2, 0,
1014
buf, sizeof(buf), 7, "-32768", 0);
1016
CALL_AND_TEST("\x00\x00\x00", 3, 0,
1017
buf, sizeof(buf), 9, "-8388608", 0);
1019
CALL_AND_TEST("\x00\x00\x00\x00", 4, 0,
1020
buf, sizeof(buf), 12, "-2147483648", 0);
1022
CALL_AND_TEST("\x00\x00\x00\x00\x00", 5, 0,
1023
buf, sizeof(buf), 14, "-549755813888", 0);
1025
CALL_AND_TEST("\x00\x00\x00\x00\x00\x00", 6, 0,
1026
buf, sizeof(buf), 17, "-140737488355328", 0);
1028
CALL_AND_TEST("\x00\x00\x00\x00\x00\x00\x00", 7, 0,
1029
buf, sizeof(buf), 19, "-36028797018963968", 0);
1031
CALL_AND_TEST("\x00\x00\x00\x00\x00\x00\x00\x00", 8, 0,
1032
buf, sizeof(buf), 21, "-9223372036854775808", 0);
1034
/* min values for unsigned 1-8 byte integers */
1036
CALL_AND_TEST("\x00", 1, DATA_UNSIGNED,
1037
buf, sizeof(buf), 2, "0", 0);
1039
CALL_AND_TEST("\x00\x00", 2, DATA_UNSIGNED,
1040
buf, sizeof(buf), 2, "0", 0);
1042
CALL_AND_TEST("\x00\x00\x00", 3, DATA_UNSIGNED,
1043
buf, sizeof(buf), 2, "0", 0);
1045
CALL_AND_TEST("\x00\x00\x00\x00", 4, DATA_UNSIGNED,
1046
buf, sizeof(buf), 2, "0", 0);
1048
CALL_AND_TEST("\x00\x00\x00\x00\x00", 5, DATA_UNSIGNED,
1049
buf, sizeof(buf), 2, "0", 0);
1051
CALL_AND_TEST("\x00\x00\x00\x00\x00\x00", 6, DATA_UNSIGNED,
1052
buf, sizeof(buf), 2, "0", 0);
1054
CALL_AND_TEST("\x00\x00\x00\x00\x00\x00\x00", 7, DATA_UNSIGNED,
1055
buf, sizeof(buf), 2, "0", 0);
1057
CALL_AND_TEST("\x00\x00\x00\x00\x00\x00\x00\x00", 8, DATA_UNSIGNED,
1058
buf, sizeof(buf), 2, "0", 0);
1060
/* max values for signed 1-8 byte integers */
1062
CALL_AND_TEST("\xFF", 1, 0,
1063
buf, sizeof(buf), 4, "127", 0);
1065
CALL_AND_TEST("\xFF\xFF", 2, 0,
1066
buf, sizeof(buf), 6, "32767", 0);
1068
CALL_AND_TEST("\xFF\xFF\xFF", 3, 0,
1069
buf, sizeof(buf), 8, "8388607", 0);
1071
CALL_AND_TEST("\xFF\xFF\xFF\xFF", 4, 0,
1072
buf, sizeof(buf), 11, "2147483647", 0);
1074
CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF", 5, 0,
1075
buf, sizeof(buf), 13, "549755813887", 0);
1077
CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF", 6, 0,
1078
buf, sizeof(buf), 16, "140737488355327", 0);
1080
CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 7, 0,
1081
buf, sizeof(buf), 18, "36028797018963967", 0);
1083
CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8, 0,
1084
buf, sizeof(buf), 20, "9223372036854775807", 0);
1086
/* max values for unsigned 1-8 byte integers */
1088
CALL_AND_TEST("\xFF", 1, DATA_UNSIGNED,
1089
buf, sizeof(buf), 4, "255", 0);
1091
CALL_AND_TEST("\xFF\xFF", 2, DATA_UNSIGNED,
1092
buf, sizeof(buf), 6, "65535", 0);
1094
CALL_AND_TEST("\xFF\xFF\xFF", 3, DATA_UNSIGNED,
1095
buf, sizeof(buf), 9, "16777215", 0);
1097
CALL_AND_TEST("\xFF\xFF\xFF\xFF", 4, DATA_UNSIGNED,
1098
buf, sizeof(buf), 11, "4294967295", 0);
1100
CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF", 5, DATA_UNSIGNED,
1101
buf, sizeof(buf), 14, "1099511627775", 0);
1103
CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF", 6, DATA_UNSIGNED,
1104
buf, sizeof(buf), 16, "281474976710655", 0);
1106
CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 7, DATA_UNSIGNED,
1107
buf, sizeof(buf), 18, "72057594037927935", 0);
1109
CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8, DATA_UNSIGNED,
1110
buf, sizeof(buf), 21, "18446744073709551615", 0);
1112
/* some random values */
1114
CALL_AND_TEST("\x52", 1, 0,
1115
buf, sizeof(buf), 4, "-46", 0);
1117
CALL_AND_TEST("\x0E", 1, DATA_UNSIGNED,
1118
buf, sizeof(buf), 3, "14", 0);
1120
CALL_AND_TEST("\x62\xCE", 2, 0,
1121
buf, sizeof(buf), 6, "-7474", 0);
1123
CALL_AND_TEST("\x29\xD6", 2, DATA_UNSIGNED,
1124
buf, sizeof(buf), 6, "10710", 0);
1126
CALL_AND_TEST("\x7F\xFF\x90", 3, 0,
1127
buf, sizeof(buf), 5, "-112", 0);
1129
CALL_AND_TEST("\x00\xA1\x16", 3, DATA_UNSIGNED,
1130
buf, sizeof(buf), 6, "41238", 0);
1132
CALL_AND_TEST("\x7F\xFF\xFF\xF7", 4, 0,
1133
buf, sizeof(buf), 3, "-9", 0);
1135
CALL_AND_TEST("\x00\x00\x00\x5C", 4, DATA_UNSIGNED,
1136
buf, sizeof(buf), 3, "92", 0);
1138
CALL_AND_TEST("\x7F\xFF\xFF\xFF\xFF\xFF\xDC\x63", 8, 0,
1139
buf, sizeof(buf), 6, "-9117", 0);
1141
CALL_AND_TEST("\x00\x00\x00\x00\x00\x01\x64\x62", 8, DATA_UNSIGNED,
1142
buf, sizeof(buf), 6, "91234", 0);
1150
speedo_reset(&speedo);
1152
for (i = 0; i < 1000000; i++) {
1153
row_raw_format_int("\x23", 1,
1154
0, buf, sizeof(buf),
1156
row_raw_format_int("\x23", 1,
1157
DATA_UNSIGNED, buf, sizeof(buf),
1160
row_raw_format_int("\x00\x00\x00\x00\x00\x01\x64\x62", 8,
1161
0, buf, sizeof(buf),
1163
row_raw_format_int("\x00\x00\x00\x00\x00\x01\x64\x62", 8,
1164
DATA_UNSIGNED, buf, sizeof(buf),
1168
speedo_show(&speedo);
1171
#endif /* UNIV_COMPILE_TEST_FUNCS */