diff options
author | unknown <monty@donna.mysql.com> | 2001-02-17 14:19:19 +0200 |
---|---|---|
committer | unknown <monty@donna.mysql.com> | 2001-02-17 14:19:19 +0200 |
commit | 2662b59306ef0cd495fa6e2edf7129e58a11393a (patch) | |
tree | bfe39951a73e906579ab819bf5198ad8f3a64a36 /innobase/rem | |
parent | 66de55a56bdcf2f7a9c0c4f8e19b3e761475e202 (diff) | |
download | mariadb-git-2662b59306ef0cd495fa6e2edf7129e58a11393a.tar.gz |
Added Innobase to source distribution
Docs/manual.texi:
Added Innobase documentation
configure.in:
Incremented version
include/my_base.h:
Added option for Innobase
myisam/mi_check.c:
cleanup
mysql-test/t/bdb.test:
cleanup
mysql-test/t/innobase.test:
Extended with new tests from bdb.test
mysql-test/t/merge.test:
Added test of SHOW create
mysys/my_init.c:
Fix for UNIXWARE 7
scripts/mysql_install_db.sh:
Always write how to start mysqld
scripts/safe_mysqld.sh:
Fixed type
sql/ha_innobase.cc:
Update to new version
sql/ha_innobase.h:
Update to new version
sql/handler.h:
Added 'update_table_comment()' and 'append_create_info()'
sql/sql_delete.cc:
Fixes for Innobase
sql/sql_select.cc:
Fixes for Innobase
sql/sql_show.cc:
Append create information (for MERGE tables)
sql/sql_update.cc:
Fixes for Innobase
Diffstat (limited to 'innobase/rem')
-rw-r--r-- | innobase/rem/Makefile.am | 24 | ||||
-rw-r--r-- | innobase/rem/makefilewin | 12 | ||||
-rw-r--r-- | innobase/rem/rem0cmp.c | 899 | ||||
-rw-r--r-- | innobase/rem/rem0rec.c | 541 | ||||
-rw-r--r-- | innobase/rem/ts/makefile | 16 | ||||
-rw-r--r-- | innobase/rem/ts/tsrem.c | 464 |
6 files changed, 1956 insertions, 0 deletions
diff --git a/innobase/rem/Makefile.am b/innobase/rem/Makefile.am new file mode 100644 index 00000000000..ef0cde9bd7a --- /dev/null +++ b/innobase/rem/Makefile.am @@ -0,0 +1,24 @@ +# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +# & Innobase Oy +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +include ../include/Makefile.i + +libs_LIBRARIES = librem.a + +librem_a_SOURCES = rem0rec.c rem0cmp.c + +EXTRA_PROGRAMS = diff --git a/innobase/rem/makefilewin b/innobase/rem/makefilewin new file mode 100644 index 00000000000..51ca4a92012 --- /dev/null +++ b/innobase/rem/makefilewin @@ -0,0 +1,12 @@ +include ..\include\makefile.i + +rem.lib: rem0rec.obj rem0cmp.obj + lib -out:..\libs\rem.lib rem0rec.obj rem0cmp.obj + +rem0rec.obj: rem0rec.c + $(CCOM) $(CFL) -c rem0rec.c + +rem0cmp.obj: rem0cmp.c + $(CCOM) $(CFL) -c rem0cmp.c + + diff --git a/innobase/rem/rem0cmp.c b/innobase/rem/rem0cmp.c new file mode 100644 index 00000000000..edf3903cd51 --- /dev/null +++ b/innobase/rem/rem0cmp.c @@ -0,0 +1,899 @@ +/*********************************************************************** +Comparison services for records + +(c) 1994-1996 Innobase Oy + +Created 7/1/1994 Heikki Tuuri +************************************************************************/ + +#include "rem0cmp.h" + +#ifdef UNIV_NONINL +#include "rem0cmp.ic" +#endif + +/* ALPHABETICAL ORDER + ================== + +The records are put into alphabetical order in the following +way: let F be the first field where two records disagree. +If there is a character in some position n where the the +records disagree, the order is determined by comparison of +the characters at position n, possibly after +collating transformation. If there is no such character, +but the corresponding fields have different lengths, then +if the data type of the fields is paddable, +shorter field is padded with a padding character. If the +data type is not paddable, longer field is considered greater. +Finally, the SQL null is bigger than any other value. + +At the present, the comparison functions return 0 in the case, +where two records disagree only in the way that one +has more fields than the other. */ + +/***************************************************************** +Used in debug checking of cmp_dtuple_... . +This function is used to compare a data tuple to a physical record. If +dtuple has n fields then rec must have either m >= n fields, or it must +differ from dtuple in some of the m fields rec has. */ +static +int +cmp_debug_dtuple_rec_with_match( +/*============================*/ + /* out: 1, 0, -1, if dtuple is greater, equal, + less than rec, respectively, when only the + common first fields are compared */ + dtuple_t* dtuple, /* in: data tuple */ + rec_t* rec, /* in: physical record which differs from + dtuple in some of the common fields, or which + has an equal number or more fields than + dtuple */ + ulint* matched_fields);/* in/out: number of already completely + matched fields; when function returns, + contains the value for current comparison */ +/***************************************************************** +This function is used to compare two data fields for which the data type +is such that we must use MySQL code to compare them. */ + +int +innobase_mysql_cmp( +/*===============*/ + /* out: 1, 0, -1, if a is greater, + equal, less than b, respectively */ + int mysql_type, /* in: MySQL type */ + unsigned char* a, /* in: data field */ + unsigned int a_length, /* in: data field length, + not UNIV_SQL_NULL */ + unsigned char* b, /* in: data field */ + unsigned int b_length); /* in: data field length, + not UNIV_SQL_NULL */ + +/***************************************************************** +Innobase uses this function is to compare two data fields for which the +data type is such that we must compare whole fields. */ +static +int +cmp_whole_field( +/*============*/ + /* out: 1, 0, -1, if a is greater, + equal, less than b, respectively */ + dtype_t* type, /* in: data type */ + unsigned char* a, /* in: data field */ + unsigned int a_length, /* in: data field length, + not UNIV_SQL_NULL */ + unsigned char* b, /* in: data field */ + unsigned int b_length) /* in: data field length, + not UNIV_SQL_NULL */ +{ + float f_1; + float f_2; + double d_1; + double d_2; + int swap_flag = 1; + ulint data_type; + + data_type = type->mtype; + + switch (data_type) { + + case DATA_DECIMAL: + /* Remove preceding spaces */ + for (; a_length && *a == ' '; a++, a_length--); + for (; b_length && *b == ' '; b++, b_length--); + + if (*a == '-') { + if (*b != '-') { + return(-1); + } + + a++; b++; + a_length--; + b_length--; + + swap_flag = -1; + + } else if (*b == '-') { + + return(1); + } + + while (a_length > 0 && (*a == '+' || *a == '0')) { + a++; a_length--; + } + + while (b_length > 0 && (*b == '+' || *b == '0')) { + b++; b_length--; + } + + if (a_length != b_length) { + if (a_length < b_length) { + return(-swap_flag); + } + + return(swap_flag); + } + + while (a_length > 0 && *a == *b) { + + a++; b++; a_length--; + } + + if (a_length == 0) { + + return(0); + } + + if (*a > *b) { + return(swap_flag); + } + + return(-swap_flag); + case DATA_DOUBLE: + d_1 = mach_double_read(a); + d_2 = mach_double_read(b); + + if (d_1 > d_2) { + return(1); + } else if (d_2 > d_1) { + return(-1); + } + + return(0); + + case DATA_FLOAT: + f_1 = mach_float_read(a); + f_2 = mach_float_read(b); + + if (f_1 > f_2) { + return(1); + } else if (f_2 > f_1) { + return(-1); + } + + return(0); + case DATA_MYSQL: + return(innobase_mysql_cmp( + (int)(type->prtype & ~DATA_NOT_NULL), + a, a_length, b, b_length)); + default: + assert(0); + } + + return(0); +} + +/***************************************************************** +This function is used to compare two data fields for which we know the +data type. */ + +int +cmp_data_data_slow( +/*===============*/ + /* out: 1, 0, -1, if data1 is greater, equal, + less than data2, respectively */ + dtype_t* cur_type,/* in: data type of the fields */ + byte* data1, /* in: data field (== a pointer to a memory + buffer) */ + ulint len1, /* in: data field length or UNIV_SQL_NULL */ + byte* data2, /* in: data field (== a pointer to a memory + buffer) */ + ulint len2) /* in: data field length or UNIV_SQL_NULL */ +{ + ulint data1_byte; + ulint data2_byte; + ulint cur_bytes; + + ut_ad(dtype_validate(cur_type)); + + if (len1 == UNIV_SQL_NULL || len2 == UNIV_SQL_NULL) { + + if (len1 == len2) { + + return(0); + } + + if (len1 == UNIV_SQL_NULL) { + /* We define the SQL null to be the smallest possible + value of a field in the alphabetical order */ + + return(-1); + } + + return(1); + } + + if (cur_type->mtype >= DATA_FLOAT) { + return(cmp_whole_field(cur_type, data1, len1, data2, len2)); + } + + /* Compare then the fields */ + + cur_bytes = 0; + + for (;;) { + if (len1 <= cur_bytes) { + if (len2 <= cur_bytes) { + + return(0); + } + + data1_byte = dtype_get_pad_char(cur_type); + + if (data1_byte == ULINT_UNDEFINED) { + + return(-1); + } + } else { + data1_byte = *data1; + } + + if (len2 <= cur_bytes) { + data2_byte = dtype_get_pad_char(cur_type); + + if (data2_byte == ULINT_UNDEFINED) { + + return(1); + } + } else { + data2_byte = *data2; + } + + if (data1_byte == data2_byte) { + /* If the bytes are equal, they will remain such even + after the collation transformation below */ + + goto next_byte; + } + + if (cur_type->mtype <= DATA_CHAR) { + data1_byte = dtype_collate(cur_type, data1_byte); + data2_byte = dtype_collate(cur_type, data2_byte); + } + + if (data1_byte > data2_byte) { + + return(1); + } else if (data1_byte < data2_byte) { + + return(-1); + } + next_byte: + /* Next byte */ + cur_bytes++; + data1++; + data2++; + } + + return(0); +} + +/***************************************************************** +This function is used to compare a data tuple to a physical record. +Only dtuple->n_fields_cmp first fields are taken into account for +the the data tuple! If we denote by n = n_fields_cmp, then rec must +have either m >= n fields, or it must differ from dtuple in some of +the m fields rec has. */ + +int +cmp_dtuple_rec_with_match( +/*======================*/ + /* out: 1, 0, -1, if dtuple is greater, equal, + less than rec, respectively, when only the + common first fields are compared */ + dtuple_t* dtuple, /* in: data tuple */ + rec_t* rec, /* in: physical record which differs from + dtuple in some of the common fields, or which + has an equal number or more fields than + dtuple */ + ulint* matched_fields, /* in/out: number of already completely + matched fields; when function returns, + contains the value for current comparison */ + ulint* matched_bytes) /* in/out: number of already matched + bytes within the first field not completely + matched; when function returns, contains the + value for current comparison */ +{ + dtype_t* cur_type; /* pointer to type of the current + field in dtuple */ + dfield_t* dtuple_field; /* current field in logical record */ + ulint dtuple_f_len; /* the length of the current field + in the logical record */ + byte* dtuple_b_ptr; /* pointer to the current byte in + logical field data */ + ulint dtuple_byte; /* value of current byte to be compared + in dtuple*/ + ulint rec_f_len; /* length of current field in rec */ + byte* rec_b_ptr; /* pointer to the current byte in + rec field */ + ulint rec_byte; /* value of current byte to be + compared in rec */ + ulint cur_field; /* current field number */ + ulint cur_bytes; /* number of already matched bytes + in current field */ + int ret = 3333; /* return value */ + + ut_ad(dtuple && rec && matched_fields && matched_bytes); + ut_ad(dtuple_check_typed(dtuple)); + + cur_field = *matched_fields; + cur_bytes = *matched_bytes; + + ut_ad(cur_field <= dtuple_get_n_fields_cmp(dtuple)); + ut_ad(cur_field <= rec_get_n_fields(rec)); + + /* Match fields in a loop; stop if we run out of fields in dtuple */ + + while (cur_field < dtuple_get_n_fields_cmp(dtuple)) { + + dtuple_field = dtuple_get_nth_field(dtuple, cur_field); + cur_type = dfield_get_type(dtuple_field); + + dtuple_f_len = dfield_get_len(dtuple_field); + + rec_b_ptr = rec_get_nth_field(rec, cur_field, &rec_f_len); + + /* If we have matched yet 0 bytes, it may be that one or + both the fields are SQL null, or the record or dtuple may be + the predefined minimum record */ + + if (cur_bytes == 0) { + if (cur_field == 0) { + + if (rec_get_info_bits(rec) + & REC_INFO_MIN_REC_FLAG) { + + if (dtuple_get_info_bits(dtuple) + & REC_INFO_MIN_REC_FLAG) { + + ret = 0; + } else { + ret = 1; + } + + goto order_resolved; + } + + if (dtuple_get_info_bits(dtuple) + & REC_INFO_MIN_REC_FLAG) { + ret = -1; + + goto order_resolved; + } + } + + if (dtuple_f_len == UNIV_SQL_NULL + || rec_f_len == UNIV_SQL_NULL) { + + if (dtuple_f_len == rec_f_len) { + + goto next_field; + } + + if (rec_f_len == UNIV_SQL_NULL) { + /* We define the SQL null to be the + smallest possible value of a field + in the alphabetical order */ + + ret = 1; + } else { + ret = -1; + } + + goto order_resolved; + } + } + + if (cur_type->mtype >= DATA_FLOAT) { + + ret = cmp_whole_field(cur_type, + dfield_get_data(dtuple_field), dtuple_f_len, + rec_b_ptr, rec_f_len); + + if (ret != 0) { + cur_bytes = 0; + + goto order_resolved; + } else { + goto next_field; + } + } + + /* Set the pointers at the current byte */ + + rec_b_ptr = rec_b_ptr + cur_bytes; + dtuple_b_ptr = (byte*)dfield_get_data(dtuple_field) + + cur_bytes; + /* Compare then the fields */ + + for (;;) { + if (rec_f_len <= cur_bytes) { + if (dtuple_f_len <= cur_bytes) { + + goto next_field; + } + + rec_byte = dtype_get_pad_char(cur_type); + + if (rec_byte == ULINT_UNDEFINED) { + ret = 1; + + goto order_resolved; + } + } else { + rec_byte = *rec_b_ptr; + } + + if (dtuple_f_len <= cur_bytes) { + dtuple_byte = dtype_get_pad_char(cur_type); + + if (dtuple_byte == ULINT_UNDEFINED) { + ret = -1; + + goto order_resolved; + } + } else { + dtuple_byte = *dtuple_b_ptr; + } + + if (dtuple_byte == rec_byte) { + /* If the bytes are equal, they will + remain such even after the collation + transformation below */ + + goto next_byte; + } + + if (cur_type->mtype <= DATA_CHAR) { + rec_byte = dtype_collate(cur_type, rec_byte); + dtuple_byte = dtype_collate(cur_type, + dtuple_byte); + } + + if (dtuple_byte > rec_byte) { + ret = 1; + goto order_resolved; + + } else if (dtuple_byte < rec_byte) { + ret = -1; + goto order_resolved; + } + next_byte: + /* Next byte */ + cur_bytes++; + rec_b_ptr++; + dtuple_b_ptr++; + } + + next_field: + cur_field++; + cur_bytes = 0; + } + + ut_ad(cur_bytes == 0); + + ret = 0; /* If we ran out of fields, dtuple was equal to rec + up to the common fields */ +order_resolved: + ut_ad((ret >= - 1) && (ret <= 1)); + ut_ad(ret == cmp_debug_dtuple_rec_with_match(dtuple, rec, + matched_fields)); + ut_ad(*matched_fields == cur_field); /* In the debug version, the + above cmp_debug_... sets + *matched_fields to a value */ + *matched_fields = cur_field; + *matched_bytes = cur_bytes; + + return(ret); +} + +/****************************************************************** +Compares a data tuple to a physical record. */ + +int +cmp_dtuple_rec( +/*===========*/ + /* out: 1, 0, -1, if dtuple is greater, equal, + less than rec, respectively; see the comments + for cmp_dtuple_rec_with_match */ + dtuple_t* dtuple, /* in: data tuple */ + rec_t* rec) /* in: physical record */ +{ + ulint matched_fields = 0; + ulint matched_bytes = 0; + + return(cmp_dtuple_rec_with_match(dtuple, rec, &matched_fields, + &matched_bytes)); +} + +/****************************************************************** +Checks if a dtuple is a prefix of a record. The last field in dtuple +is allowed to be a prefix of the corresponding field in the record. */ + +ibool +cmp_dtuple_is_prefix_of_rec( +/*========================*/ + /* out: TRUE if prefix */ + dtuple_t* dtuple, /* in: data tuple */ + rec_t* rec) /* in: physical record */ +{ + ulint n_fields; + ulint matched_fields = 0; + ulint matched_bytes = 0; + + n_fields = dtuple_get_n_fields(dtuple); + + if (n_fields > rec_get_n_fields(rec)) { + + return(FALSE); + } + + cmp_dtuple_rec_with_match(dtuple, rec, &matched_fields, + &matched_bytes); + if (matched_fields == n_fields) { + + return(TRUE); + } + + if (matched_fields == n_fields - 1 + && matched_bytes == dfield_get_len( + dtuple_get_nth_field(dtuple, n_fields - 1))) { + return(TRUE); + } + + return(FALSE); +} + +/****************************************************************** +Compares a prefix of a data tuple to a prefix of a physical record for +equality. If there are less fields in rec than parameter n_fields, FALSE +is returned. NOTE that n_fields_cmp of dtuple does not affect this +comparison. */ + +ibool +cmp_dtuple_rec_prefix_equal( +/*========================*/ + /* out: TRUE if equal */ + dtuple_t* dtuple, /* in: data tuple */ + rec_t* rec, /* in: physical record */ + ulint n_fields) /* in: number of fields which should be + compared; must not exceed the number of + fields in dtuple */ +{ + ulint matched_fields = 0; + ulint matched_bytes = 0; + + ut_ad(n_fields <= dtuple_get_n_fields(dtuple)); + + if (rec_get_n_fields(rec) < n_fields) { + + return(FALSE); + } + + cmp_dtuple_rec_with_match(dtuple, rec, &matched_fields, + &matched_bytes); + if (matched_fields >= n_fields) { + + return(TRUE); + } + + return(FALSE); +} + +/***************************************************************** +This function is used to compare two physical records. Only the common +first fields are compared. */ + +int +cmp_rec_rec_with_match( +/*===================*/ + /* out: 1, 0 , -1 if rec1 is greater, equal, + less, respectively, than rec2; only the common + first fields are compared */ + rec_t* rec1, /* in: physical record */ + rec_t* rec2, /* in: physical record */ + dict_index_t* index, /* in: data dictionary index */ + ulint* matched_fields, /* in/out: number of already completely + matched fields; when the function returns, + contains the value the for current + comparison */ + ulint* matched_bytes) /* in/out: number of already matched + bytes within the first field not completely + matched; when the function returns, contains + the value for the current comparison */ +{ + dtype_t* cur_type; /* pointer to type struct of the + current field in index */ + ulint rec1_n_fields; /* the number of fields in rec */ + ulint rec1_f_len; /* length of current field in rec */ + byte* rec1_b_ptr; /* pointer to the current byte in rec field */ + ulint rec1_byte; /* value of current byte to be compared in + rec */ + ulint rec2_n_fields; /* the number of fields in rec */ + ulint rec2_f_len; /* length of current field in rec */ + byte* rec2_b_ptr; /* pointer to the current byte in rec field */ + ulint rec2_byte; /* value of current byte to be compared in + rec */ + ulint cur_field; /* current field number */ + ulint cur_bytes; /* number of already matched bytes in current + field */ + int ret = 3333; /* return value */ + + ut_ad(rec1 && rec2 && index); + + rec1_n_fields = rec_get_n_fields(rec1); + rec2_n_fields = rec_get_n_fields(rec2); + + cur_field = *matched_fields; + cur_bytes = *matched_bytes; + + /* Match fields in a loop; stop if we run out of fields in either + record */ + + while ((cur_field < rec1_n_fields) && (cur_field < rec2_n_fields)) { + + if (index->type & DICT_UNIVERSAL) { + cur_type = dtype_binary; + } else { + cur_type = dict_col_get_type( + dict_field_get_col( + dict_index_get_nth_field(index, cur_field))); + } + + rec1_b_ptr = rec_get_nth_field(rec1, cur_field, &rec1_f_len); + rec2_b_ptr = rec_get_nth_field(rec2, cur_field, &rec2_f_len); + + if (cur_bytes == 0) { + if (cur_field == 0) { + /* Test if rec is the predefined minimum + record */ + if (rec_get_info_bits(rec1) + & REC_INFO_MIN_REC_FLAG) { + + if (rec_get_info_bits(rec2) + & REC_INFO_MIN_REC_FLAG) { + ret = 0; + } else { + ret = -1; + } + + goto order_resolved; + + } else if (rec_get_info_bits(rec2) + & REC_INFO_MIN_REC_FLAG) { + + ret = 1; + + goto order_resolved; + } + } + + if (rec1_f_len == UNIV_SQL_NULL + || rec2_f_len == UNIV_SQL_NULL) { + + if (rec1_f_len == rec2_f_len) { + + goto next_field; + + } else if (rec2_f_len == UNIV_SQL_NULL) { + + /* We define the SQL null to be the + smallest possible value of a field + in the alphabetical order */ + + ret = 1; + } else { + ret = -1; + } + + goto order_resolved; + } + } + + if (cur_type->mtype >= DATA_FLOAT) { + ret = cmp_whole_field(cur_type, + rec1_b_ptr, rec1_f_len, + rec2_b_ptr, rec2_f_len); + if (ret != 0) { + cur_bytes = 0; + + goto order_resolved; + } else { + goto next_field; + } + } + + /* Set the pointers at the current byte */ + rec1_b_ptr = rec1_b_ptr + cur_bytes; + rec2_b_ptr = rec2_b_ptr + cur_bytes; + + /* Compare then the fields */ + for (;;) { + if (rec2_f_len <= cur_bytes) { + + if (rec1_f_len <= cur_bytes) { + + goto next_field; + } + + rec2_byte = dtype_get_pad_char(cur_type); + + if (rec2_byte == ULINT_UNDEFINED) { + ret = 1; + + goto order_resolved; + } + } else { + rec2_byte = *rec2_b_ptr; + } + + if (rec1_f_len <= cur_bytes) { + rec1_byte = dtype_get_pad_char(cur_type); + + if (rec1_byte == ULINT_UNDEFINED) { + ret = -1; + + goto order_resolved; + } + } else { + rec1_byte = *rec1_b_ptr; + } + + if (rec1_byte == rec2_byte) { + /* If the bytes are equal, they will remain + such even after the collation transformation + below */ + + goto next_byte; + } + + if (cur_type->mtype <= DATA_CHAR) { + rec1_byte = dtype_collate(cur_type, rec1_byte); + rec2_byte = dtype_collate(cur_type, rec2_byte); + } + + if (rec1_byte < rec2_byte) { + ret = -1; + goto order_resolved; + } else if (rec1_byte > rec2_byte) { + ret = 1; + goto order_resolved; + } + next_byte: + /* Next byte */ + + cur_bytes++; + rec1_b_ptr++; + rec2_b_ptr++; + } + + next_field: + cur_field++; + cur_bytes = 0; + } + + ut_ad(cur_bytes == 0); + + ret = 0; /* If we ran out of fields, rec1 was equal to rec2 up + to the common fields */ +order_resolved: + + ut_ad((ret >= - 1) && (ret <= 1)); + + *matched_fields = cur_field; + *matched_bytes = cur_bytes; + + return(ret); +} + +/***************************************************************** +Used in debug checking of cmp_dtuple_... . +This function is used to compare a data tuple to a physical record. If +dtuple has n fields then rec must have either m >= n fields, or it must +differ from dtuple in some of the m fields rec has. */ +static +int +cmp_debug_dtuple_rec_with_match( +/*============================*/ + /* out: 1, 0, -1, if dtuple is greater, equal, + less than rec, respectively, when only the + common first fields are compared */ + dtuple_t* dtuple, /* in: data tuple */ + rec_t* rec, /* in: physical record which differs from + dtuple in some of the common fields, or which + has an equal number or more fields than + dtuple */ + ulint* matched_fields) /* in/out: number of already completely + matched fields; when function returns, + contains the value for current comparison */ +{ + dtype_t* cur_type; /* pointer to type of the current + field in dtuple */ + dfield_t* dtuple_field; /* current field in logical record */ + ulint dtuple_f_len; /* the length of the current field + in the logical record */ + byte* dtuple_f_data; /* pointer to the current logical + field data */ + ulint rec_f_len; /* length of current field in rec */ + byte* rec_f_data; /* pointer to the current rec field */ + int ret = 3333; /* return value */ + ulint cur_field; /* current field number */ + + ut_ad(dtuple && rec && matched_fields); + ut_ad(dtuple_check_typed(dtuple)); + + ut_ad(*matched_fields <= dtuple_get_n_fields_cmp(dtuple)); + ut_ad(*matched_fields <= rec_get_n_fields(rec)); + + cur_field = *matched_fields; + + if (cur_field == 0) { + if (rec_get_info_bits(rec) & REC_INFO_MIN_REC_FLAG) { + + if (dtuple_get_info_bits(dtuple) + & REC_INFO_MIN_REC_FLAG) { + ret = 0; + } else { + ret = 1; + } + + goto order_resolved; + } + + if (dtuple_get_info_bits(dtuple) & REC_INFO_MIN_REC_FLAG) { + ret = -1; + + goto order_resolved; + } + } + + /* Match fields in a loop; stop if we run out of fields in dtuple */ + + while (cur_field < dtuple_get_n_fields_cmp(dtuple)) { + + dtuple_field = dtuple_get_nth_field(dtuple, cur_field); + + cur_type = dfield_get_type(dtuple_field); + + dtuple_f_data = dfield_get_data(dtuple_field); + dtuple_f_len = dfield_get_len(dtuple_field); + + rec_f_data = rec_get_nth_field(rec, cur_field, &rec_f_len); + + ret = cmp_data_data(cur_type, dtuple_f_data, dtuple_f_len, + rec_f_data, rec_f_len); + if (ret != 0) { + goto order_resolved; + } + + cur_field++; + } + + ret = 0; /* If we ran out of fields, dtuple was equal to rec + up to the common fields */ +order_resolved: + ut_ad((ret >= - 1) && (ret <= 1)); + + *matched_fields = cur_field; + + return(ret); +} diff --git a/innobase/rem/rem0rec.c b/innobase/rem/rem0rec.c new file mode 100644 index 00000000000..9ddfe7a4b9a --- /dev/null +++ b/innobase/rem/rem0rec.c @@ -0,0 +1,541 @@ +/************************************************************************ +Record manager + +(c) 1994-1996 Innobase Oy + +Created 5/30/1994 Heikki Tuuri +*************************************************************************/ + +#include "rem0rec.h" + +#ifdef UNIV_NONINL +#include "rem0rec.ic" +#endif + +/* PHYSICAL RECORD + =============== + +The physical record, which is the data type of all the records +found in index pages of the database, has the following format +(lower addresses and more significant bits inside a byte are below +represented on a higher text line): + +| offset of the end of the last field of data, the most significant + bit is set to 1 if and only if the field is SQL-null | +... +| offset of the end of the first field of data + the SQL-null bit | +| 4 bits used to delete mark a record, and mark a predefined + minimum record in alphabetical order | +| 4 bits giving the number of records owned by this record + (this term is explained in page0page.h) | +| 13 bits giving the order number of this record in the + heap of the index page | +| 10 bits giving the number of fields in this record | +| 1 bit which is set to 1 if the offsets above are given in + one byte format, 0 if in two byte format | +| two bytes giving the pointer to the next record in the page | +ORIGIN of the record +| first field of data | +... +| last field of data | + +The origin of the record is the start address of the first field +of data. The offsets are given relative to the origin. +The offsets of the data fields are stored in an inverted +order because then the offset of the first fields are near the +origin, giving maybe a better processor cache hit rate in searches. + +The offsets of the data fields are given as one-byte +(if there are less than 127 bytes of data in the record) +or two-byte unsigned integers. The most significant bit +is not part of the offset, instead it indicates the SQL-null +if the bit is set to 1. + +CANONICAL COORDINATES. A record can be seen as a single +string of 'characters' in the following way: catenate the bytes +in each field, in the order of fields. An SQL-null field +is taken to be an empty sequence of bytes. Then after +the position of each field insert in the string +the 'character' <FIELD-END>, except that after an SQL-null field +insert <NULL-FIELD-END>. Now the ordinal position of each +byte in this canonical string is its canonical coordinate. +So, for the record ("AA", SQL-NULL, "BB", ""), the canonical +string is "AA<FIELD_END><NULL-FIELD-END>BB<FIELD-END><FIELD-END>". +We identify prefixes (= initial segments) of a record +with prefixes of the canonical string. The canonical +length of the prefix is the length of the corresponding +prefix of the canonical string. The canonical length of +a record is the length of its canonical string. + +For example, the maximal common prefix of records +("AA", SQL-NULL, "BB", "C") and ("AA", SQL-NULL, "B", "C") +is "AA<FIELD-END><NULL-FIELD-END>B", and its canonical +length is 5. + +A complete-field prefix of a record is a prefix which ends at the +end of some field (containing also <FIELD-END>). +A record is a complete-field prefix of another record, if +the corresponding canonical strings have the same property. */ + +ulint rec_dummy; /* this is used to fool compiler in + rec_validate */ + +/**************************************************************** +The following function is used to get a pointer to the nth data field in a +record. */ + +byte* +rec_get_nth_field( +/*==============*/ + /* out: pointer to the field */ + rec_t* rec, /* in: record */ + ulint n, /* in: index of the field */ + ulint* len) /* out: length of the field; UNIV_SQL_NULL if SQL + null */ +{ + ulint os; + ulint next_os; + + ut_ad(rec && len); + ut_ad(n < rec_get_n_fields(rec)); + + if (rec_get_1byte_offs_flag(rec)) { + os = rec_1_get_field_start_offs(rec, n); + + next_os = rec_1_get_field_end_info(rec, n); + + if (next_os & REC_1BYTE_SQL_NULL_MASK) { + *len = UNIV_SQL_NULL; + + return(rec + os); + } + + next_os = next_os & ~REC_1BYTE_SQL_NULL_MASK; + } else { + os = rec_2_get_field_start_offs(rec, n); + + next_os = rec_2_get_field_end_info(rec, n); + + if (next_os & REC_2BYTE_SQL_NULL_MASK) { + *len = UNIV_SQL_NULL; + + return(rec + os); + } + + next_os = next_os & ~REC_2BYTE_SQL_NULL_MASK; + } + + *len = next_os - os; + + ut_ad(*len < UNIV_PAGE_SIZE); + + return(rec + os); +} + +/*************************************************************** +Sets the value of the ith field SQL null bit. */ + +void +rec_set_nth_field_null_bit( +/*=======================*/ + rec_t* rec, /* in: record */ + ulint i, /* in: ith field */ + ibool val) /* in: value to set */ +{ + ulint info; + + if (rec_get_1byte_offs_flag(rec)) { + + info = rec_1_get_field_end_info(rec, i); + + if (val) { + info = info | REC_1BYTE_SQL_NULL_MASK; + } else { + info = info & ~REC_1BYTE_SQL_NULL_MASK; + } + + rec_1_set_field_end_info(rec, i, info); + + return; + } + + info = rec_2_get_field_end_info(rec, i); + + if (val) { + info = info | REC_2BYTE_SQL_NULL_MASK; + } else { + info = info & ~REC_2BYTE_SQL_NULL_MASK; + } + + rec_2_set_field_end_info(rec, i, info); +} + +/*************************************************************** +Sets a record field to SQL null. The physical size of the field is not +changed. */ + +void +rec_set_nth_field_sql_null( +/*=======================*/ + rec_t* rec, /* in: record */ + ulint n) /* in: index of the field */ +{ + ulint offset; + + offset = rec_get_field_start_offs(rec, n); + + data_write_sql_null(rec + offset, rec_get_nth_field_size(rec, n)); + + rec_set_nth_field_null_bit(rec, n, TRUE); +} + +/************************************************************* +Builds a physical record out of a data tuple and stores it beginning from +address destination. */ + +rec_t* +rec_convert_dtuple_to_rec_low( +/*==========================*/ + /* out: pointer to the origin of physical + record */ + byte* destination, /* in: start address of the physical record */ + dtuple_t* dtuple, /* in: data tuple */ + ulint data_size) /* in: data size of dtuple */ +{ + dfield_t* field; + ulint n_fields; + rec_t* rec; + ulint end_offset; + ulint ored_offset; + byte* data; + ulint len; + ulint i; + + ut_ad(destination && dtuple); + ut_ad(dtuple_validate(dtuple)); + ut_ad(dtuple_check_typed(dtuple)); + ut_ad(dtuple_get_data_size(dtuple) == data_size); + + n_fields = dtuple_get_n_fields(dtuple); + + ut_ad(n_fields > 0); + + /* Calculate the offset of the origin in the physical record */ + + rec = destination + rec_get_converted_extra_size(data_size, n_fields); + + /* Store the number of fields */ + rec_set_n_fields(rec, n_fields); + + /* Set the info bits of the record */ + rec_set_info_bits(rec, dtuple_get_info_bits(dtuple)); + + /* Store the data and the offsets */ + + end_offset = 0; + + if (data_size <= REC_1BYTE_OFFS_LIMIT) { + + rec_set_1byte_offs_flag(rec, TRUE); + + for (i = 0; i < n_fields; i++) { + + field = dtuple_get_nth_field(dtuple, i); + + data = dfield_get_data(field); + len = dfield_get_len(field); + + if (len == UNIV_SQL_NULL) { + len = dtype_get_sql_null_size(dfield_get_type(field)); + data_write_sql_null(rec + end_offset, len); + + end_offset += len; + ored_offset = end_offset | REC_1BYTE_SQL_NULL_MASK; + } else { + /* If the data is not SQL null, store it */ + ut_memcpy(rec + end_offset, data, len); + + end_offset += len; + ored_offset = end_offset; + } + + rec_1_set_field_end_info(rec, i, ored_offset); + } + } else { + rec_set_1byte_offs_flag(rec, FALSE); + + for (i = 0; i < n_fields; i++) { + + field = dtuple_get_nth_field(dtuple, i); + + data = dfield_get_data(field); + len = dfield_get_len(field); + + if (len == UNIV_SQL_NULL) { + len = dtype_get_sql_null_size(dfield_get_type(field)); + data_write_sql_null(rec + end_offset, len); + + end_offset += len; + ored_offset = end_offset | REC_2BYTE_SQL_NULL_MASK; + } else { + /* If the data is not SQL null, store it */ + ut_memcpy(rec + end_offset, data, len); + + end_offset += len; + ored_offset = end_offset; + } + + rec_2_set_field_end_info(rec, i, ored_offset); + } + } + + ut_ad(rec_validate(rec)); + + return(rec); +} + +/****************************************************************** +Copies the first n fields of a physical record to a data tuple. The fields +are copied to the memory heap. */ + +void +rec_copy_prefix_to_dtuple( +/*======================*/ + dtuple_t* tuple, /* in: data tuple */ + rec_t* rec, /* in: physical record */ + ulint n_fields, /* in: number of fields to copy */ + mem_heap_t* heap) /* in: memory heap */ +{ + dfield_t* field; + byte* data; + ulint len; + byte* buf = NULL; + ulint i; + + ut_ad(rec_validate(rec)); + ut_ad(dtuple_check_typed(tuple)); + + dtuple_set_info_bits(tuple, rec_get_info_bits(rec)); + + for (i = 0; i < n_fields; i++) { + + field = dtuple_get_nth_field(tuple, i); + data = rec_get_nth_field(rec, i, &len); + + if (len != UNIV_SQL_NULL) { + buf = mem_heap_alloc(heap, len); + + ut_memcpy(buf, data, len); + } + + dfield_set_data(field, buf, len); + } +} + +/****************************************************************** +Copies the first n fields of a physical record to a new physical record in +a buffer. */ + +rec_t* +rec_copy_prefix_to_buf( +/*===================*/ + /* out, own: copied record */ + rec_t* rec, /* in: physical record */ + ulint n_fields, /* in: number of fields to copy */ + byte** buf, /* in/out: memory buffer for the copied prefix, + or NULL */ + ulint* buf_size) /* in/out: buffer size */ +{ + rec_t* copy_rec; + ulint area_start; + ulint area_end; + ulint prefix_len; + + ut_ad(rec_validate(rec)); + + area_end = rec_get_field_start_offs(rec, n_fields); + + if (rec_get_1byte_offs_flag(rec)) { + area_start = REC_N_EXTRA_BYTES + n_fields; + } else { + area_start = REC_N_EXTRA_BYTES + 2 * n_fields; + } + + prefix_len = area_start + area_end; + + if ((*buf == NULL) || (*buf_size < prefix_len)) { + if (*buf != NULL) { + mem_free(*buf); + } + + *buf = mem_alloc(prefix_len); + *buf_size = prefix_len; + } + + ut_memcpy(*buf, rec - area_start, prefix_len); + + copy_rec = *buf + area_start; + + rec_set_n_fields(copy_rec, n_fields); + + return(copy_rec); +} + +/******************************************************************* +Validates the consistency of a physical record. */ + +ibool +rec_validate( +/*=========*/ + /* out: TRUE if ok */ + rec_t* rec) /* in: physical record */ +{ + ulint i; + byte* data; + ulint len; + ulint n_fields; + ulint len_sum = 0; + ulint sum = 0; + + ut_a(rec); + n_fields = rec_get_n_fields(rec); + + if ((n_fields == 0) || (n_fields > REC_MAX_N_FIELDS)) { + ut_a(0); + } + + for (i = 0; i < n_fields; i++) { + data = rec_get_nth_field(rec, i, &len); + + ut_a((len < UNIV_PAGE_SIZE) || (len == UNIV_SQL_NULL)); + + if (len != UNIV_SQL_NULL) { + len_sum += len; + sum += *(data + len -1); /* dereference the + end of the field to + cause a memory trap + if possible */ + } else { + len_sum += rec_get_nth_field_size(rec, i); + } + } + + ut_a(len_sum == (ulint)(rec_get_end(rec) - rec)); + + rec_dummy = sum; /* This is here only to fool the compiler */ + + return(TRUE); +} + +/******************************************************************* +Prints a physical record. */ + +void +rec_print( +/*======*/ + rec_t* rec) /* in: physical record */ +{ + byte* data; + ulint len; + char* offs; + ulint n; + ulint i; + + ut_ad(rec); + + if (rec_get_1byte_offs_flag(rec)) { + offs = "TRUE"; + } else { + offs = "FALSE"; + } + + n = rec_get_n_fields(rec); + + printf( + "PHYSICAL RECORD: n_fields %lu; 1-byte offs %s; info bits %lu\n", + n, offs, rec_get_info_bits(rec)); + + for (i = 0; i < n; i++) { + + data = rec_get_nth_field(rec, i, &len); + + printf(" %lu:", i); + + if (len != UNIV_SQL_NULL) { + if (len <= 30) { + + ut_print_buf(data, len); + } else { + ut_print_buf(data, 30); + + printf("...(truncated)"); + } + } else { + printf(" SQL NULL, size %lu ", + rec_get_nth_field_size(rec, i)); + + } + printf(";"); + } + + printf("\n"); + + rec_validate(rec); +} + +/******************************************************************* +Prints a physical record to a buffer. */ + +ulint +rec_sprintf( +/*========*/ + /* out: printed length in bytes */ + char* buf, /* in: buffer to print to */ + ulint buf_len,/* in: buffer length */ + rec_t* rec) /* in: physical record */ +{ + byte* data; + ulint len; + ulint k; + ulint n; + ulint i; + + ut_ad(rec); + + n = rec_get_n_fields(rec); + k = 0; + + if (k + 30 > buf_len) { + + return(k); + } + + k += sprintf(buf + k, "RECORD: info bits %lu", rec_get_info_bits(rec)); + + for (i = 0; i < n; i++) { + + if (k + 30 > buf_len) { + + return(k); + } + + data = rec_get_nth_field(rec, i, &len); + + k += sprintf(buf + k, " %lu:", i); + + if (len != UNIV_SQL_NULL) { + if (k + 30 + 5 * len > buf_len) { + + return(k); + } + + k += ut_sprintf_buf(buf + k, data, len); + } else { + k += sprintf(buf + k, " SQL NULL"); + } + + k += sprintf(buf + k, ";"); + } + + return(k); +} diff --git a/innobase/rem/ts/makefile b/innobase/rem/ts/makefile new file mode 100644 index 00000000000..c429afa273e --- /dev/null +++ b/innobase/rem/ts/makefile @@ -0,0 +1,16 @@ + + + +include ..\..\makefile.i + +tsrem: ..\rem.lib tsrem.c + $(CCOM) $(CFL) -I.. -I..\.. ..\rem.lib ..\..\page.lib ..\..\mtr.lib ..\..\btr.lib ..\..\log.lib ..\..\dyn.lib ..\..\fil.lib ..\..\buf.lib ..\..\dict.lib ..\..\data.lib ..\..\mach.lib ..\..\ha.lib ..\..\ut.lib ..\..\sync.lib ..\..\mem.lib ..\..\os.lib tsrem.c $(LFL) + + + + + + + + + diff --git a/innobase/rem/ts/tsrem.c b/innobase/rem/ts/tsrem.c new file mode 100644 index 00000000000..4f2bdde0068 --- /dev/null +++ b/innobase/rem/ts/tsrem.c @@ -0,0 +1,464 @@ +/************************************************************************ +The test for the record manager + +(c) 1994-1996 Innobase Oy + +Created 1/25/1994 Heikki Tuuri +*************************************************************************/ + +#include "sync0sync.h" +#include "mem0mem.h" +#include "data0data.h" +#include "data0type.h" +#include "dict0dict.h" +#include "buf0buf.h" +#include "fil0fil.h" +#include "../rem0rec.h" +#include "../rem0cmp.h" + +byte buf1[100000]; + +/********************************************************************* +Test for data tuples. */ + +void +test1(void) +/*=======*/ +{ + dtype_t* type; + dtuple_t* tuple, *tuple2; + dfield_t* field; + mem_heap_t* heap; + ulint i, j; + ulint n; + char* p_Pascal; + char* p_Cobol; + + heap = mem_heap_create(0); + + printf("-------------------------------------------\n"); + printf("DATA TUPLE-TEST 1. Basic tests.\n"); + + tuple = dtuple_create(heap, 2); + + field = dtuple_get_nth_field(tuple, 0); + dfield_set_data(field, "Pascal", 7); + dtype_set(dfield_get_type(field), DATA_CHAR, DATA_ENGLISH, 7, 0); + + field = dtuple_get_nth_field(tuple, 1); + dfield_set_data(field, "Cobol", 6); + dtype_set(dfield_get_type(field), DATA_CHAR, DATA_ENGLISH, 6, 0); + + dtuple_validate(tuple); + dtuple_print(tuple); + + tuple2 = dtuple_create(heap, 10); + + for (i = 0; i < 10; i++) { + field = dtuple_get_nth_field(tuple2, i); + dfield_set_data(field, NULL, UNIV_SQL_NULL); + dtype_set(dfield_get_type(field), DATA_CHAR, DATA_ENGLISH, + 6, 0); + } + + dtuple_print(tuple2); + + printf("-------------------------------------------\n"); + printf("DATA TUPLE-TEST 2. Accessor function tests.\n"); + + tuple = dtuple_create(heap, 2); + + p_Pascal = "Pascal"; + p_Cobol = "Cobol"; + + field = dtuple_get_nth_field(tuple, 0); + dfield_set_data(field, p_Pascal, 7); + dtype_set(dfield_get_type(field), DATA_CHAR, DATA_ENGLISH, 7, 0); + + field = dtuple_get_nth_field(tuple, 1); + dfield_set_data(field, p_Cobol, 6); + dtype_set(dfield_get_type(field), DATA_VARCHAR, DATA_ENGLISH, 16, 3); + + ut_a(dtuple_get_n_fields(tuple) == 2); + + field = dtuple_get_nth_field(tuple, 0); + ut_a(p_Pascal == dfield_get_data(field)); + ut_a(7 == dfield_get_len(field)); + type = dfield_get_type(field); + ut_a(type->mtype == DATA_CHAR); + ut_a(type->prtype == DATA_ENGLISH); + ut_a(type->len == 7); + ut_a(type->prec == 0); + + field = dtuple_get_nth_field(tuple, 1); + ut_a(p_Cobol == dfield_get_data(field)); + ut_a(6 == dfield_get_len(field)); + type = dfield_get_type(field); + ut_a(type->mtype == DATA_VARCHAR); + ut_a(type->prtype == DATA_ENGLISH); + ut_a(type->len == 16); + ut_a(type->prec == 3); + + printf("-------------------------------------------\n"); + printf("DATA TYPE-TEST 3. Other function tests\n"); + + ut_a(dtuple_get_data_size(tuple) == 13); + + ut_a(dtuple_fold(tuple, 2) == dtuple_fold(tuple, 2)); + ut_a(dtuple_fold(tuple, 1) != dtuple_fold(tuple, 2)); + + printf("-------------------------------------------\n"); + printf("DATA TUPLE-TEST 4. Random tuple generation test\n"); + + for (i = 0; i < 500; i++) { + tuple = dtuple_gen_rnd_tuple(heap); + printf("%lu ", i); + + dtuple_validate(tuple); + n = dtuple_get_n_fields(tuple); + + if (n < 25) { + tuple2 = dtuple_create(heap, n); + for (j = 0; j < n; j++) { + dfield_copy( + dtuple_get_nth_field(tuple2, j), + dtuple_get_nth_field(tuple, j)); + } + dtuple_validate(tuple2); + + ut_a(dtuple_fold(tuple, n) == + dtuple_fold(tuple2, n)); + } + } + + mem_print_info(); + mem_heap_free(heap); +} + +/********************************************************************** +Test for physical records. */ + +void +test2(void) +/*=======*/ +{ + dtuple_t* tuple, *tuple2; + dfield_t* field; + mem_heap_t* heap; + ulint i, n; + char* p_Pascal; + char* p_Cobol; + rec_t* rec, *rec2; + byte* data; + ulint len; + byte* buf; + + heap = mem_heap_create(0); + + printf("-------------------------------------------\n"); + printf("REC-TEST 1. Basic tests.\n"); + + tuple = dtuple_create(heap, 2); + + p_Pascal = "Pascal"; + p_Cobol = "Cobol"; + + field = dtuple_get_nth_field(tuple, 0); + dfield_set_data(field, "Pascal", 7); + dtype_set(dfield_get_type(field), DATA_CHAR, DATA_ENGLISH, 7, 0); + + field = dtuple_get_nth_field(tuple, 1); + dfield_set_data(field, "Cobol", 6); + dtype_set(dfield_get_type(field), DATA_CHAR, DATA_ENGLISH, 6, 0); + + tuple2 = dtuple_create(heap, 37); + + for (i = 0; i < 37; i++) { + field = dtuple_get_nth_field(tuple2, i); + dfield_set_data(field, NULL, UNIV_SQL_NULL); + dtype_set(dfield_get_type(field), DATA_CHAR, + DATA_ENGLISH, 6, 0); + } + + rec = rec_convert_dtuple_to_rec(buf1, tuple); + + rec_validate(rec); + rec_print(rec); + + rec2 = rec_convert_dtuple_to_rec(buf1 + 1000, tuple2); + + rec_validate(rec2); + + data = rec_get_nth_field(rec, 0, &len); + + ut_a(0 == memcmp(p_Pascal, data, 7)); + ut_a(len == 7); + + data = rec_get_nth_field(rec, 1, &len); + + ut_a(0 == memcmp(p_Cobol, data, 6)); + ut_a(len == 6); + + ut_a(2 == rec_get_n_fields(rec)); + + for (i = 0; i < 37; i++) { + data = rec_get_nth_field(rec2, i, &len); + ut_a(len == UNIV_SQL_NULL); + } + + printf("-------------------------------------------\n"); + printf("REC-TEST 2. Test of accessor functions\n"); + + rec_set_next_offs(rec, 8190); + rec_set_n_owned(rec, 15); + rec_set_heap_no(rec, 0); + + ut_a(rec_get_next_offs(rec) == 8190); + ut_a(rec_get_n_owned(rec) == 15); + ut_a(rec_get_heap_no(rec) == 0); + + rec_set_next_offs(rec, 1); + rec_set_n_owned(rec, 1); + rec_set_heap_no(rec, 8190); + + ut_a(rec_get_next_offs(rec) == 1); + ut_a(rec_get_n_owned(rec) == 1); + ut_a(rec_get_heap_no(rec) == 8190); + + buf = mem_heap_alloc(heap, 6); + + rec_copy_nth_field(buf, rec, 1, &len); + + ut_a(ut_memcmp(p_Cobol, buf, len) == 0); + ut_a(len == 6); + + rec_set_nth_field(rec, 1, "Algol", 6); + + rec_validate(rec); + + rec_copy_nth_field(buf, rec, 1, &len); + + ut_a(ut_memcmp("Algol", buf, len) == 0); + ut_a(len == 6); + + ut_a(rec_get_data_size(rec) == 13); + ut_a((ulint)(rec_get_end(rec) - rec) == 13); + ut_a(14 == (ulint)(rec - rec_get_start(rec))); + + ut_a(rec_get_size(rec) == 27); + + mem_heap_free(heap); + + printf("-------------------------------------------\n"); + printf("REC-TEST 3. Massive test of conversions \n"); + + heap = mem_heap_create(0); + + for (i = 0; i < 100; i++) { + + tuple = dtuple_gen_rnd_tuple(heap); + + if (i % 10 == 0) { + printf("%lu ", i); + } + + if (i % 10 == 0) { + printf( + "data tuple generated: %lu fields, data size %lu\n", + dtuple_get_n_fields(tuple), + dtuple_get_data_size(tuple)); + } + + dtuple_validate(tuple); + + rec = rec_convert_dtuple_to_rec(buf1, tuple); + + rec_validate(rec); + + n = dtuple_get_n_fields(tuple); + + ut_a(cmp_dtuple_rec_prefix_equal(tuple, rec, n)); + ut_a(dtuple_fold(tuple, n) == rec_fold(rec, n)); + ut_a(rec_get_converted_size(tuple) == rec_get_size(rec)); + ut_a(rec_get_data_size(rec) == dtuple_get_data_size(tuple)); + } + + mem_print_info(); + mem_heap_free(heap); +} + +/********************************************************************** +Test for comparisons. */ + +void +test3(void) +/*=======*/ +{ + dtuple_t* tuple, *tuple2, *tuple3; + dfield_t* field; + mem_heap_t* heap; + ulint i, j; + ulint field_match, byte_match; + rec_t* rec; + rec_t* rec2; + ulint tm, oldtm; + dict_index_t* index; + dict_table_t* table; + + heap = mem_heap_create(0); + + printf("-------------------------------------------\n"); + printf("CMP-TEST 1. Basic tests.\n"); + + tuple = dtuple_create(heap, 2); + + field = dtuple_get_nth_field(tuple, 0); + dfield_set_data(field, "Pascal", 7); + dtype_set(dfield_get_type(field), DATA_CHAR, DATA_ENGLISH, 7, 0); + + field = dtuple_get_nth_field(tuple, 1); + dfield_set_data(field, "Cobol", 6); + dtype_set(dfield_get_type(field), DATA_CHAR, DATA_ENGLISH, 6, 0); + + tuple2 = dtuple_create(heap, 2); + + field = dtuple_get_nth_field(tuple2, 0); + dfield_set_data(field, "Pascal", 7); + dtype_set(dfield_get_type(field), DATA_CHAR, DATA_ENGLISH, 7, 0); + + field = dtuple_get_nth_field(tuple2, 1); + dfield_set_data(field, "Cobom", 6); + dtype_set(dfield_get_type(field), DATA_CHAR, DATA_ENGLISH, 6, 0); + + tuple3 = dtuple_create(heap, 2); + + field = dtuple_get_nth_field(tuple3, 0); + dfield_set_data(field, "PaSCal", 7); + dtype_set(dfield_get_type(field), DATA_CHAR, DATA_ENGLISH, 7, 0); + + field = dtuple_get_nth_field(tuple3, 1); + dfield_set_data(field, "CobOL", 6); + dtype_set(dfield_get_type(field), DATA_CHAR, DATA_ENGLISH, 6, 0); + + rec = rec_convert_dtuple_to_rec(buf1, tuple); + + rec_validate(rec); + + ut_a(!cmp_dtuple_rec_prefix_equal(tuple2, rec, 2)); + ut_a(cmp_dtuple_rec_prefix_equal(tuple, rec, 2)); + ut_a(cmp_dtuple_rec_prefix_equal(tuple3, rec, 2)); + + oldtm = ut_clock(); + j = 0; + for (i = 0; i < 1000; i++) { + field_match = 1; + byte_match = 4; + if (1 == cmp_dtuple_rec_with_match(tuple2, rec, + &field_match, &byte_match)) { + j++; + } + } + tm = ut_clock(); + printf("Time for fast comp. %lu records = %lu\n", j, tm - oldtm); + + ut_a(field_match == 1); + ut_a(byte_match == 4); + + oldtm = ut_clock(); + j = 0; + for (i = 0; i < 1000; i++) { + field_match = 0; + byte_match = 0; + if (1 == cmp_dtuple_rec_with_match(tuple2, rec, + &field_match, &byte_match)) { + j++; + } + } + tm = ut_clock(); + printf("Time for test comp. %lu records = %lu\n", j, tm - oldtm); + + ut_a(field_match == 1); + ut_a(byte_match == 4); + + printf("-------------------------------------------\n"); + printf( + "CMP-TEST 2. A systematic test of comparisons and conversions\n"); + + tuple = dtuple_create(heap, 3); + tuple2 = dtuple_create(heap, 3); + + table = dict_table_create("TS_TABLE1", 3); + + dict_table_add_col(table, "COL1", DATA_VARCHAR, DATA_ENGLISH, 10, 0); + dict_table_add_col(table, "COL2", DATA_VARCHAR, DATA_ENGLISH, 10, 0); + dict_table_add_col(table, "COL3", DATA_VARCHAR, DATA_ENGLISH, 10, 0); + + ut_a(0 == dict_table_publish(table)); + + index = dict_index_create("TS_TABLE1", "IND1", 0, 3, 0); + + dict_index_add_field(index, "COL1", 0); + dict_index_add_field(index, "COL2", 0); + dict_index_add_field(index, "COL3", 0); + + ut_a(0 == dict_index_publish(index)); + + index = dict_index_get("TS_TABLE1", "IND1"); + ut_a(index); + + /* Compare all test data tuples to each other */ + for (i = 0; i < 512; i++) { + dtuple_gen_test_tuple(tuple, i); + rec = rec_convert_dtuple_to_rec(buf1, tuple); + ut_a(rec_validate(rec)); + + ut_a(0 == cmp_dtuple_rec(tuple, rec)); + + for (j = 0; j < 512; j++) { + dtuple_gen_test_tuple(tuple2, j); + ut_a(dtuple_validate(tuple2)); + + rec2 = rec_convert_dtuple_to_rec(buf1 + 500, tuple2); + + if (j < i) { + ut_a(-1 == cmp_dtuple_rec(tuple2, rec)); + ut_a(-1 == cmp_rec_rec(rec2, rec, index)); + } else if (j == i) { + ut_a(0 == cmp_dtuple_rec(tuple2, rec)); + ut_a(0 == cmp_rec_rec(rec2, rec, index)); + } else if (j > i) { + ut_a(1 == cmp_dtuple_rec(tuple2, rec)); + ut_a(1 == cmp_rec_rec(rec2, rec, index)); + } + } + } + mem_heap_free(heap); +} + +/******************************************************************** +Main test function. */ + +void +main(void) +/*======*/ +{ + ulint tm, oldtm; + + sync_init(); + mem_init(); + fil_init(25); + buf_pool_init(100, 100); + dict_init(); + + oldtm = ut_clock(); + + ut_rnd_set_seed(19); + + test1(); + test2(); + test3(); + + tm = ut_clock(); + printf("CPU time for test %lu microseconds\n", tm - oldtm); + printf("TESTS COMPLETED SUCCESSFULLY!\n"); +} |