summaryrefslogtreecommitdiff
path: root/storage/innobase/data
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/data')
-rw-r--r--storage/innobase/data/Makefile.am24
-rw-r--r--storage/innobase/data/data0data.c662
-rw-r--r--storage/innobase/data/data0type.c260
3 files changed, 946 insertions, 0 deletions
diff --git a/storage/innobase/data/Makefile.am b/storage/innobase/data/Makefile.am
new file mode 100644
index 00000000000..eeb6f129de0
--- /dev/null
+++ b/storage/innobase/data/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
+
+noinst_LIBRARIES = libdata.a
+
+libdata_a_SOURCES = data0data.c data0type.c
+
+EXTRA_PROGRAMS =
diff --git a/storage/innobase/data/data0data.c b/storage/innobase/data/data0data.c
new file mode 100644
index 00000000000..19304a7a8e1
--- /dev/null
+++ b/storage/innobase/data/data0data.c
@@ -0,0 +1,662 @@
+/************************************************************************
+SQL data field and tuple
+
+(c) 1994-1996 Innobase Oy
+
+Created 5/30/1994 Heikki Tuuri
+*************************************************************************/
+
+#include "data0data.h"
+
+#ifdef UNIV_NONINL
+#include "data0data.ic"
+#endif
+
+#include "rem0rec.h"
+#include "rem0cmp.h"
+#include "page0page.h"
+#include "dict0dict.h"
+#include "btr0cur.h"
+
+byte data_error; /* data pointers of tuple fields are initialized
+ to point here for error checking */
+
+#ifdef UNIV_DEBUG
+ulint data_dummy; /* this is used to fool the compiler in
+ dtuple_validate */
+#endif /* UNIV_DEBUG */
+
+/* Some non-inlined functions used in the MySQL interface: */
+void
+dfield_set_data_noninline(
+ dfield_t* field, /* in: field */
+ void* data, /* in: data */
+ ulint len) /* in: length or UNIV_SQL_NULL */
+{
+ dfield_set_data(field, data, len);
+}
+void*
+dfield_get_data_noninline(
+ dfield_t* field) /* in: field */
+{
+ return(dfield_get_data(field));
+}
+ulint
+dfield_get_len_noninline(
+ dfield_t* field) /* in: field */
+{
+ return(dfield_get_len(field));
+}
+ulint
+dtuple_get_n_fields_noninline(
+ dtuple_t* tuple) /* in: tuple */
+{
+ return(dtuple_get_n_fields(tuple));
+}
+dfield_t*
+dtuple_get_nth_field_noninline(
+ dtuple_t* tuple, /* in: tuple */
+ ulint n) /* in: index of field */
+{
+ return(dtuple_get_nth_field(tuple, n));
+}
+
+/*************************************************************************
+Tests if dfield data length and content is equal to the given. */
+
+ibool
+dfield_data_is_binary_equal(
+/*========================*/
+ /* out: TRUE if equal */
+ dfield_t* field, /* in: field */
+ ulint len, /* in: data length or UNIV_SQL_NULL */
+ byte* data) /* in: data */
+{
+ if (len != field->len) {
+
+ return(FALSE);
+ }
+
+ if (len == UNIV_SQL_NULL) {
+
+ return(TRUE);
+ }
+
+ if (0 != ut_memcmp(field->data, data, len)) {
+
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+/****************************************************************
+Returns TRUE if lengths of two dtuples are equal and respective data fields
+in them are equal when compared with collation in char fields (not as binary
+strings). */
+
+ibool
+dtuple_datas_are_ordering_equal(
+/*============================*/
+ /* out: TRUE if length and fieds are equal
+ when compared with cmp_data_data:
+ NOTE: in character type fields some letters
+ are identified with others! (collation) */
+ dtuple_t* tuple1, /* in: tuple 1 */
+ dtuple_t* tuple2) /* in: tuple 2 */
+{
+ dfield_t* field1;
+ dfield_t* field2;
+ ulint n_fields;
+ ulint i;
+
+ ut_ad(tuple1 && tuple2);
+ ut_ad(tuple1->magic_n == DATA_TUPLE_MAGIC_N);
+ ut_ad(tuple2->magic_n == DATA_TUPLE_MAGIC_N);
+ ut_ad(dtuple_check_typed(tuple1));
+ ut_ad(dtuple_check_typed(tuple2));
+
+ n_fields = dtuple_get_n_fields(tuple1);
+
+ if (n_fields != dtuple_get_n_fields(tuple2)) {
+
+ return(FALSE);
+ }
+
+ for (i = 0; i < n_fields; i++) {
+
+ field1 = dtuple_get_nth_field(tuple1, i);
+ field2 = dtuple_get_nth_field(tuple2, i);
+
+ if (0 != cmp_dfield_dfield(field1, field2)) {
+
+ return(FALSE);
+ }
+ }
+
+ return(TRUE);
+}
+
+/*************************************************************************
+Creates a dtuple for use in MySQL. */
+
+dtuple_t*
+dtuple_create_for_mysql(
+/*====================*/
+ /* out, own created dtuple */
+ void** heap, /* out: created memory heap */
+ ulint n_fields) /* in: number of fields */
+{
+ *heap = (void*)mem_heap_create(500);
+
+ return(dtuple_create(*((mem_heap_t**)heap), n_fields));
+}
+
+/*************************************************************************
+Frees a dtuple used in MySQL. */
+
+void
+dtuple_free_for_mysql(
+/*==================*/
+ void* heap) /* in: memory heap where tuple was created */
+{
+ mem_heap_free((mem_heap_t*)heap);
+}
+
+/*************************************************************************
+Sets number of fields used in a tuple. Normally this is set in
+dtuple_create, but if you want later to set it smaller, you can use this. */
+
+void
+dtuple_set_n_fields(
+/*================*/
+ dtuple_t* tuple, /* in: tuple */
+ ulint n_fields) /* in: number of fields */
+{
+ ut_ad(tuple);
+
+ tuple->n_fields = n_fields;
+ tuple->n_fields_cmp = n_fields;
+}
+
+/**************************************************************
+Checks that a data field is typed. */
+static
+ibool
+dfield_check_typed_no_assert(
+/*=========================*/
+ /* out: TRUE if ok */
+ dfield_t* field) /* in: data field */
+{
+ if (dfield_get_type(field)->mtype > DATA_MYSQL
+ || dfield_get_type(field)->mtype < DATA_VARCHAR) {
+
+ fprintf(stderr,
+"InnoDB: Error: data field type %lu, len %lu\n",
+ (ulong) dfield_get_type(field)->mtype,
+ (ulong) dfield_get_len(field));
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+/**************************************************************
+Checks that a data tuple is typed. */
+
+ibool
+dtuple_check_typed_no_assert(
+/*=========================*/
+ /* out: TRUE if ok */
+ dtuple_t* tuple) /* in: tuple */
+{
+ dfield_t* field;
+ ulint i;
+
+ if (dtuple_get_n_fields(tuple) > REC_MAX_N_FIELDS) {
+ fprintf(stderr,
+"InnoDB: Error: index entry has %lu fields\n",
+ (ulong) dtuple_get_n_fields(tuple));
+ dump:
+ fputs("InnoDB: Tuple contents: ", stderr);
+ dtuple_print(stderr, tuple);
+ putc('\n', stderr);
+
+ return(FALSE);
+ }
+
+ for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
+
+ field = dtuple_get_nth_field(tuple, i);
+
+ if (!dfield_check_typed_no_assert(field)) {
+ goto dump;
+ }
+ }
+
+ return(TRUE);
+}
+
+/**************************************************************
+Checks that a data field is typed. Asserts an error if not. */
+
+ibool
+dfield_check_typed(
+/*===============*/
+ /* out: TRUE if ok */
+ dfield_t* field) /* in: data field */
+{
+ if (dfield_get_type(field)->mtype > DATA_MYSQL
+ || dfield_get_type(field)->mtype < DATA_VARCHAR) {
+
+ fprintf(stderr,
+"InnoDB: Error: data field type %lu, len %lu\n",
+ (ulong) dfield_get_type(field)->mtype,
+ (ulong) dfield_get_len(field));
+
+ ut_error;
+ }
+
+ return(TRUE);
+}
+
+/**************************************************************
+Checks that a data tuple is typed. Asserts an error if not. */
+
+ibool
+dtuple_check_typed(
+/*===============*/
+ /* out: TRUE if ok */
+ dtuple_t* tuple) /* in: tuple */
+{
+ dfield_t* field;
+ ulint i;
+
+ for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
+
+ field = dtuple_get_nth_field(tuple, i);
+
+ ut_a(dfield_check_typed(field));
+ }
+
+ return(TRUE);
+}
+
+#ifdef UNIV_DEBUG
+/**************************************************************
+Validates the consistency of a tuple which must be complete, i.e,
+all fields must have been set. */
+
+ibool
+dtuple_validate(
+/*============*/
+ /* out: TRUE if ok */
+ dtuple_t* tuple) /* in: tuple */
+{
+ dfield_t* field;
+ byte* data;
+ ulint n_fields;
+ ulint len;
+ ulint i;
+ ulint j;
+
+ ut_ad(tuple->magic_n == DATA_TUPLE_MAGIC_N);
+
+ n_fields = dtuple_get_n_fields(tuple);
+
+ /* We dereference all the data of each field to test
+ for memory traps */
+
+ for (i = 0; i < n_fields; i++) {
+
+ field = dtuple_get_nth_field(tuple, i);
+ len = dfield_get_len(field);
+
+ if (len != UNIV_SQL_NULL) {
+
+ data = field->data;
+
+ for (j = 0; j < len; j++) {
+
+ data_dummy += *data; /* fool the compiler not
+ to optimize out this
+ code */
+ data++;
+ }
+ }
+ }
+
+ ut_a(dtuple_check_typed(tuple));
+
+ return(TRUE);
+}
+#endif /* UNIV_DEBUG */
+
+/*****************************************************************
+Pretty prints a dfield value according to its data type. */
+
+void
+dfield_print(
+/*=========*/
+ dfield_t* dfield) /* in: dfield */
+{
+ byte* data;
+ ulint len;
+ ulint mtype;
+ ulint i;
+
+ len = dfield_get_len(dfield);
+ data = dfield_get_data(dfield);
+
+ if (len == UNIV_SQL_NULL) {
+ fputs("NULL", stderr);
+
+ return;
+ }
+
+ mtype = dtype_get_mtype(dfield_get_type(dfield));
+
+ if ((mtype == DATA_CHAR) || (mtype == DATA_VARCHAR)) {
+
+ for (i = 0; i < len; i++) {
+ int c = *data++;
+ putc(isprint(c) ? c : ' ', stderr);
+ }
+ } else if (mtype == DATA_INT) {
+ ut_a(len == 4); /* only works for 32-bit integers */
+ fprintf(stderr, "%d", (int)mach_read_from_4(data));
+ } else {
+ ut_error;
+ }
+}
+
+/*****************************************************************
+Pretty prints a dfield value according to its data type. Also the hex string
+is printed if a string contains non-printable characters. */
+
+void
+dfield_print_also_hex(
+/*==================*/
+ dfield_t* dfield) /* in: dfield */
+{
+ byte* data;
+ ulint len;
+ ulint mtype;
+ ulint i;
+ ibool print_also_hex;
+
+ len = dfield_get_len(dfield);
+ data = dfield_get_data(dfield);
+
+ if (len == UNIV_SQL_NULL) {
+ fputs("NULL", stderr);
+
+ return;
+ }
+
+ mtype = dtype_get_mtype(dfield_get_type(dfield));
+
+ if ((mtype == DATA_CHAR) || (mtype == DATA_VARCHAR)) {
+
+ print_also_hex = FALSE;
+
+ for (i = 0; i < len; i++) {
+ int c = *data++;
+ if (!isprint(c)) {
+ print_also_hex = TRUE;
+ c = ' ';
+ }
+ putc(c, stderr);
+ }
+
+ if (!print_also_hex) {
+
+ return;
+ }
+
+ fputs(" Hex: ", stderr);
+
+ data = dfield_get_data(dfield);
+
+ for (i = 0; i < len; i++) {
+ fprintf(stderr, "%02lx", (ulint)*data);
+
+ data++;
+ }
+ } else if (mtype == DATA_INT) {
+ ut_a(len == 4); /* only works for 32-bit integers */
+ fprintf(stderr, "%d", (int)mach_read_from_4(data));
+ } else {
+ ut_error;
+ }
+}
+
+/**************************************************************
+The following function prints the contents of a tuple. */
+
+void
+dtuple_print(
+/*=========*/
+ FILE* f, /* in: output stream */
+ dtuple_t* tuple) /* in: tuple */
+{
+ dfield_t* field;
+ ulint n_fields;
+ ulint i;
+
+ n_fields = dtuple_get_n_fields(tuple);
+
+ fprintf(f, "DATA TUPLE: %lu fields;\n", (ulong) n_fields);
+
+ for (i = 0; i < n_fields; i++) {
+ fprintf(f, " %lu:", (ulong) i);
+
+ field = dtuple_get_nth_field(tuple, i);
+
+ if (field->len != UNIV_SQL_NULL) {
+ ut_print_buf(f, field->data, field->len);
+ } else {
+ fputs(" SQL NULL", f);
+ }
+
+ putc(';', f);
+ }
+
+ putc('\n', f);
+ ut_ad(dtuple_validate(tuple));
+}
+
+/******************************************************************
+Moves parts of long fields in entry to the big record vector so that
+the size of tuple drops below the maximum record size allowed in the
+database. Moves data only from those fields which are not necessary
+to determine uniquely the insertion place of the tuple in the index. */
+
+big_rec_t*
+dtuple_convert_big_rec(
+/*===================*/
+ /* out, own: created big record vector,
+ NULL if we are not able to shorten
+ the entry enough, i.e., if there are
+ too many short fields in entry */
+ dict_index_t* index, /* in: index */
+ dtuple_t* entry, /* in: index entry */
+ ulint* ext_vec,/* in: array of externally stored fields,
+ or NULL: if a field already is externally
+ stored, then we cannot move it to the vector
+ this function returns */
+ ulint n_ext_vec)/* in: number of elements is ext_vec */
+{
+ mem_heap_t* heap;
+ big_rec_t* vector;
+ dfield_t* dfield;
+ ulint size;
+ ulint n_fields;
+ ulint longest;
+ ulint longest_i = ULINT_MAX;
+ ibool is_externally_stored;
+ ulint i;
+ ulint j;
+
+ ut_a(dtuple_check_typed_no_assert(entry));
+
+ size = rec_get_converted_size(index, entry);
+
+ if (UNIV_UNLIKELY(size > 1000000000)) {
+ fprintf(stderr,
+"InnoDB: Warning: tuple size very big: %lu\n", (ulong) size);
+ fputs("InnoDB: Tuple contents: ", stderr);
+ dtuple_print(stderr, entry);
+ putc('\n', stderr);
+ }
+
+ heap = mem_heap_create(size + dtuple_get_n_fields(entry)
+ * sizeof(big_rec_field_t) + 1000);
+
+ vector = mem_heap_alloc(heap, sizeof(big_rec_t));
+
+ vector->heap = heap;
+ vector->fields = mem_heap_alloc(heap, dtuple_get_n_fields(entry)
+ * sizeof(big_rec_field_t));
+
+ /* Decide which fields to shorten: the algorithm is to look for
+ the longest field whose type is DATA_BLOB */
+
+ n_fields = 0;
+
+ while (rec_get_converted_size(index, entry)
+ >= ut_min(page_get_free_space_of_empty(
+ index->table->comp) / 2,
+ REC_MAX_DATA_SIZE)) {
+
+ longest = 0;
+ for (i = dict_index_get_n_unique_in_tree(index);
+ i < dtuple_get_n_fields(entry); i++) {
+
+ /* Skip over fields which already are externally
+ stored */
+
+ is_externally_stored = FALSE;
+
+ if (ext_vec) {
+ for (j = 0; j < n_ext_vec; j++) {
+ if (ext_vec[j] == i) {
+ is_externally_stored = TRUE;
+ }
+ }
+ }
+
+ if (!is_externally_stored) {
+
+ dfield = dtuple_get_nth_field(entry, i);
+
+ if (dfield->len != UNIV_SQL_NULL &&
+ dfield->len > longest) {
+
+ longest = dfield->len;
+
+ longest_i = i;
+ }
+ }
+ }
+
+ /* We do not store externally fields which are smaller than
+ DICT_MAX_INDEX_COL_LEN */
+
+ ut_a(DICT_MAX_INDEX_COL_LEN > REC_1BYTE_OFFS_LIMIT);
+
+ if (longest < BTR_EXTERN_FIELD_REF_SIZE + 10
+ + DICT_MAX_INDEX_COL_LEN) {
+ /* Cannot shorten more */
+
+ mem_heap_free(heap);
+
+ return(NULL);
+ }
+
+ /* Move data from field longest_i to big rec vector;
+ we do not let data size of the remaining entry
+ drop below 128 which is the limit for the 2-byte
+ offset storage format in a physical record. This
+ we accomplish by storing 128 bytes of data in entry
+ itself, and only the remaining part to big rec vec.
+
+ We store the first bytes locally to the record. Then
+ we can calculate all ordering fields in all indexes
+ from locally stored data. */
+
+ dfield = dtuple_get_nth_field(entry, longest_i);
+ vector->fields[n_fields].field_no = longest_i;
+
+ ut_a(dfield->len > DICT_MAX_INDEX_COL_LEN);
+
+ vector->fields[n_fields].len = dfield->len
+ - DICT_MAX_INDEX_COL_LEN;
+
+ vector->fields[n_fields].data = mem_heap_alloc(heap,
+ vector->fields[n_fields].len);
+
+ /* Copy data (from the end of field) to big rec vector */
+
+ ut_memcpy(vector->fields[n_fields].data,
+ ((byte*)dfield->data) + dfield->len
+ - vector->fields[n_fields].len,
+ vector->fields[n_fields].len);
+ dfield->len = dfield->len - vector->fields[n_fields].len
+ + BTR_EXTERN_FIELD_REF_SIZE;
+
+ /* Set the extern field reference in dfield to zero */
+ memset(((byte*)dfield->data)
+ + dfield->len - BTR_EXTERN_FIELD_REF_SIZE,
+ 0, BTR_EXTERN_FIELD_REF_SIZE);
+ n_fields++;
+ }
+
+ vector->n_fields = n_fields;
+ return(vector);
+}
+
+/******************************************************************
+Puts back to entry the data stored in vector. Note that to ensure the
+fields in entry can accommodate the data, vector must have been created
+from entry with dtuple_convert_big_rec. */
+
+void
+dtuple_convert_back_big_rec(
+/*========================*/
+ dict_index_t* index __attribute__((unused)), /* in: index */
+ dtuple_t* entry, /* in: entry whose data was put to vector */
+ big_rec_t* vector) /* in, own: big rec vector; it is
+ freed in this function */
+{
+ dfield_t* dfield;
+ ulint i;
+
+ for (i = 0; i < vector->n_fields; i++) {
+
+ dfield = dtuple_get_nth_field(entry,
+ vector->fields[i].field_no);
+ /* Copy data from big rec vector */
+
+ ut_memcpy(((byte*)dfield->data)
+ + dfield->len - BTR_EXTERN_FIELD_REF_SIZE,
+ vector->fields[i].data,
+ vector->fields[i].len);
+ dfield->len = dfield->len + vector->fields[i].len
+ - BTR_EXTERN_FIELD_REF_SIZE;
+ }
+
+ mem_heap_free(vector->heap);
+}
+
+/******************************************************************
+Frees the memory in a big rec vector. */
+
+void
+dtuple_big_rec_free(
+/*================*/
+ big_rec_t* vector) /* in, own: big rec vector; it is
+ freed in this function */
+{
+ mem_heap_free(vector->heap);
+}
diff --git a/storage/innobase/data/data0type.c b/storage/innobase/data/data0type.c
new file mode 100644
index 00000000000..d4264ad2926
--- /dev/null
+++ b/storage/innobase/data/data0type.c
@@ -0,0 +1,260 @@
+/******************************************************
+Data types
+
+(c) 1996 Innobase Oy
+
+Created 1/16/1996 Heikki Tuuri
+*******************************************************/
+
+#include "data0type.h"
+
+#ifdef UNIV_NONINL
+#include "data0type.ic"
+#endif
+
+/**********************************************************************
+This function is used to find the storage length in bytes of the first n
+characters for prefix indexes using a multibyte character set. The function
+finds charset information and returns length of prefix_len characters in the
+index field in bytes.
+
+NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
+this function, you MUST change also the prototype here! */
+
+ulint
+innobase_get_at_most_n_mbchars(
+/*===========================*/
+ /* out: number of bytes occupied by the first
+ n characters */
+ ulint charset_id, /* in: character set id */
+ ulint prefix_len, /* in: prefix length in bytes of the index
+ (this has to be divided by mbmaxlen to get the
+ number of CHARACTERS n in the prefix) */
+ ulint data_len, /* in: length of the string in bytes */
+ const char* str); /* in: character string */
+
+/* At the database startup we store the default-charset collation number of
+this MySQL installation to this global variable. If we have < 4.1.2 format
+column definitions, or records in the insert buffer, we use this
+charset-collation code for them. */
+
+ulint data_mysql_default_charset_coll = 99999999;
+
+dtype_t dtype_binary_val = {DATA_BINARY, 0, 0, 0, 0, 0};
+dtype_t* dtype_binary = &dtype_binary_val;
+
+/*************************************************************************
+Determine how many bytes the first n characters of the given string occupy.
+If the string is shorter than n characters, returns the number of bytes
+the characters in the string occupy. */
+
+ulint
+dtype_get_at_most_n_mbchars(
+/*========================*/
+ /* out: length of the prefix,
+ in bytes */
+ const dtype_t* dtype, /* in: data type */
+ ulint prefix_len, /* in: length of the requested
+ prefix, in characters, multiplied by
+ dtype_get_mbmaxlen(dtype) */
+ ulint data_len, /* in: length of str (in bytes) */
+ const char* str) /* in: the string whose prefix
+ length is being determined */
+{
+#ifndef UNIV_HOTBACKUP
+ ut_a(data_len != UNIV_SQL_NULL);
+ ut_ad(!dtype->mbmaxlen || !(prefix_len % dtype->mbmaxlen));
+
+ if (dtype->mbminlen != dtype->mbmaxlen) {
+ ut_a(!(prefix_len % dtype->mbmaxlen));
+ return(innobase_get_at_most_n_mbchars(
+ dtype_get_charset_coll(dtype->prtype),
+ prefix_len, data_len, str));
+ }
+
+ if (prefix_len < data_len) {
+
+ return(prefix_len);
+
+ }
+
+ return(data_len);
+#else /* UNIV_HOTBACKUP */
+ /* This function depends on MySQL code that is not included in
+ InnoDB Hot Backup builds. Besides, this function should never
+ be called in InnoDB Hot Backup. */
+ ut_error;
+#endif /* UNIV_HOTBACKUP */
+}
+
+/*************************************************************************
+Checks if a data main type is a string type. Also a BLOB is considered a
+string type. */
+
+ibool
+dtype_is_string_type(
+/*=================*/
+ /* out: TRUE if string type */
+ ulint mtype) /* in: InnoDB main data type code: DATA_CHAR, ... */
+{
+ if (mtype <= DATA_BLOB
+ || mtype == DATA_MYSQL
+ || mtype == DATA_VARMYSQL) {
+
+ return(TRUE);
+ }
+
+ return(FALSE);
+}
+
+/*************************************************************************
+Checks if a type is a binary string type. Note that for tables created with
+< 4.0.14, we do not know if a DATA_BLOB column is a BLOB or a TEXT column. For
+those DATA_BLOB columns this function currently returns FALSE. */
+
+ibool
+dtype_is_binary_string_type(
+/*========================*/
+ /* out: TRUE if binary string type */
+ ulint mtype, /* in: main data type */
+ ulint prtype) /* in: precise type */
+{
+ if ((mtype == DATA_FIXBINARY)
+ || (mtype == DATA_BINARY)
+ || (mtype == DATA_BLOB && (prtype & DATA_BINARY_TYPE))) {
+
+ return(TRUE);
+ }
+
+ return(FALSE);
+}
+
+/*************************************************************************
+Checks if a type is a non-binary string type. That is, dtype_is_string_type is
+TRUE and dtype_is_binary_string_type is FALSE. Note that for tables created
+with < 4.0.14, we do not know if a DATA_BLOB column is a BLOB or a TEXT column.
+For those DATA_BLOB columns this function currently returns TRUE. */
+
+ibool
+dtype_is_non_binary_string_type(
+/*============================*/
+ /* out: TRUE if non-binary string type */
+ ulint mtype, /* in: main data type */
+ ulint prtype) /* in: precise type */
+{
+ if (dtype_is_string_type(mtype) == TRUE
+ && dtype_is_binary_string_type(mtype, prtype) == FALSE) {
+
+ return(TRUE);
+ }
+
+ return(FALSE);
+}
+
+/*************************************************************************
+Gets the MySQL charset-collation code for MySQL string types. */
+
+ulint
+dtype_get_charset_coll_noninline(
+/*=============================*/
+ ulint prtype) /* in: precise data type */
+{
+ return(dtype_get_charset_coll(prtype));
+}
+
+/*************************************************************************
+Forms a precise type from the < 4.1.2 format precise type plus the
+charset-collation code. */
+
+ulint
+dtype_form_prtype(
+/*==============*/
+ ulint old_prtype, /* in: the MySQL type code and the flags
+ DATA_BINARY_TYPE etc. */
+ ulint charset_coll) /* in: MySQL charset-collation code */
+{
+ ut_a(old_prtype < 256 * 256);
+ ut_a(charset_coll < 256);
+
+ return(old_prtype + (charset_coll << 16));
+}
+
+/*************************************************************************
+Validates a data type structure. */
+
+ibool
+dtype_validate(
+/*===========*/
+ /* out: TRUE if ok */
+ dtype_t* type) /* in: type struct to validate */
+{
+ ut_a(type);
+ ut_a((type->mtype >= DATA_VARCHAR) && (type->mtype <= DATA_MYSQL));
+
+ if (type->mtype == DATA_SYS) {
+ ut_a((type->prtype & DATA_MYSQL_TYPE_MASK) < DATA_N_SYS_COLS);
+ }
+
+ ut_a(type->mbminlen <= type->mbmaxlen);
+
+ return(TRUE);
+}
+
+/*************************************************************************
+Prints a data type structure. */
+
+void
+dtype_print(
+/*========*/
+ dtype_t* type) /* in: type */
+{
+ ulint mtype;
+ ulint prtype;
+ ulint len;
+
+ ut_a(type);
+
+ mtype = type->mtype;
+ prtype = type->prtype;
+ if (mtype == DATA_VARCHAR) {
+ fputs("DATA_VARCHAR", stderr);
+ } else if (mtype == DATA_CHAR) {
+ fputs("DATA_CHAR", stderr);
+ } else if (mtype == DATA_BINARY) {
+ fputs("DATA_BINARY", stderr);
+ } else if (mtype == DATA_INT) {
+ fputs("DATA_INT", stderr);
+ } else if (mtype == DATA_MYSQL) {
+ fputs("DATA_MYSQL", stderr);
+ } else if (mtype == DATA_SYS) {
+ fputs("DATA_SYS", stderr);
+ } else {
+ fprintf(stderr, "type %lu", (ulong) mtype);
+ }
+
+ len = type->len;
+
+ if ((type->mtype == DATA_SYS)
+ || (type->mtype == DATA_VARCHAR)
+ || (type->mtype == DATA_CHAR)) {
+ putc(' ', stderr);
+ if (prtype == DATA_ROW_ID) {
+ fputs("DATA_ROW_ID", stderr);
+ len = DATA_ROW_ID_LEN;
+ } else if (prtype == DATA_ROLL_PTR) {
+ fputs("DATA_ROLL_PTR", stderr);
+ len = DATA_ROLL_PTR_LEN;
+ } else if (prtype == DATA_TRX_ID) {
+ fputs("DATA_TRX_ID", stderr);
+ len = DATA_TRX_ID_LEN;
+ } else if (prtype == DATA_MIX_ID) {
+ fputs("DATA_MIX_ID", stderr);
+ } else if (prtype == DATA_ENGLISH) {
+ fputs("DATA_ENGLISH", stderr);
+ } else {
+ fprintf(stderr, "prtype %lu", (ulong) mtype);
+ }
+ }
+
+ fprintf(stderr, " len %lu prec %lu", (ulong) len, (ulong) type->prec);
+}