/****************************************************** Data types (c) 1996 Innobase Oy Created 1/16/1996 Heikki Tuuri *******************************************************/ #include "mach0data.h" #ifndef UNIV_HOTBACKUP /********************************************************************** Get the variable length bounds of the given character set. NOTE: the prototype of this function is copied from ha_innodb.cc! If you change this function, you MUST change also the prototype here! */ extern void innobase_get_cset_width( /*====================*/ ulint cset, /* in: MySQL charset-collation code */ ulint* mbminlen, /* out: minimum length of a char (in bytes) */ ulint* mbmaxlen); /* out: maximum length of a char (in bytes) */ #endif /* !UNIV_HOTBACKUP */ /************************************************************************* Gets the MySQL charset-collation code for MySQL string types. */ UNIV_INLINE ulint dtype_get_charset_coll( /*===================*/ ulint prtype) /* in: precise data type */ { return((prtype >> 16) & 0xFFUL); } /************************************************************************* Gets the MySQL type code from a dtype. */ UNIV_INLINE ulint dtype_get_mysql_type( /*=================*/ /* out: MySQL type code; this is NOT an InnoDB type code! */ dtype_t* type) /* in: type struct */ { return(type->prtype & 0xFFUL); } /************************************************************************* Compute the mbminlen and mbmaxlen members of a data type structure. */ UNIV_INLINE void dtype_get_mblen( /*============*/ ulint mtype, /* in: main type */ ulint prtype, /* in: precise type (and collation) */ ulint* mbminlen, /* out: minimum length of a multi-byte character */ ulint* mbmaxlen) /* out: maximum length of a multi-byte character */ { if (dtype_is_string_type(mtype)) { #ifndef UNIV_HOTBACKUP innobase_get_cset_width(dtype_get_charset_coll(prtype), mbminlen, mbmaxlen); ut_ad(*mbminlen <= *mbmaxlen); ut_ad(*mbminlen <= 2); /* mbminlen in dtype_t is 0..3 */ ut_ad(*mbmaxlen < 1 << 3); /* mbmaxlen in dtype_t is 0..7 */ #else /* !UNIV_HOTBACKUP */ ut_a(mtype <= DATA_BINARY); *mbminlen = *mbmaxlen = 1; #endif /* !UNIV_HOTBACKUP */ } else { *mbminlen = *mbmaxlen = 0; } } /************************************************************************* Compute the mbminlen and mbmaxlen members of a data type structure. */ UNIV_INLINE void dtype_set_mblen( /*============*/ dtype_t* type) /* in/out: type */ { ulint mbminlen; ulint mbmaxlen; dtype_get_mblen(type->mtype, type->prtype, &mbminlen, &mbmaxlen); type->mbminlen = mbminlen; type->mbmaxlen = mbmaxlen; ut_ad(dtype_validate(type)); } /************************************************************************* Sets a data type structure. */ UNIV_INLINE void dtype_set( /*======*/ dtype_t* type, /* in: type struct to init */ ulint mtype, /* in: main data type */ ulint prtype, /* in: precise type */ ulint len) /* in: precision of type */ { ut_ad(type); ut_ad(mtype <= DATA_MTYPE_MAX); type->mtype = mtype; type->prtype = prtype; type->len = len; dtype_set_mblen(type); } /************************************************************************* Copies a data type structure. */ UNIV_INLINE void dtype_copy( /*=======*/ dtype_t* type1, /* in: type struct to copy to */ const dtype_t* type2) /* in: type struct to copy from */ { *type1 = *type2; ut_ad(dtype_validate(type1)); } /************************************************************************* Gets the SQL main data type. */ UNIV_INLINE ulint dtype_get_mtype( /*============*/ dtype_t* type) { ut_ad(type); return(type->mtype); } /************************************************************************* Gets the precise data type. */ UNIV_INLINE ulint dtype_get_prtype( /*=============*/ dtype_t* type) { ut_ad(type); return(type->prtype); } /************************************************************************* Gets the type length. */ UNIV_INLINE ulint dtype_get_len( /*==========*/ dtype_t* type) { ut_ad(type); return(type->len); } /************************************************************************* Gets the minimum length of a character, in bytes. */ UNIV_INLINE ulint dtype_get_mbminlen( /*===============*/ /* out: minimum length of a char, in bytes, or 0 if this is not a character type */ const dtype_t* type) /* in: type */ { ut_ad(type); return(type->mbminlen); } /************************************************************************* Gets the maximum length of a character, in bytes. */ UNIV_INLINE ulint dtype_get_mbmaxlen( /*===============*/ /* out: maximum length of a char, in bytes, or 0 if this is not a character type */ const dtype_t* type) /* in: type */ { ut_ad(type); return(type->mbmaxlen); } /************************************************************************* Gets the padding character code for a type. */ UNIV_INLINE ulint dtype_get_pad_char( /*===============*/ /* out: padding character code, or ULINT_UNDEFINED if no padding specified */ ulint mtype, /* in: main type */ ulint prtype) /* in: precise type */ { switch (mtype) { case DATA_FIXBINARY: case DATA_BINARY: if (UNIV_UNLIKELY(dtype_get_charset_coll(prtype) == DATA_MYSQL_BINARY_CHARSET_COLL)) { /* Starting from 5.0.18, do not pad VARBINARY or BINARY columns. */ return(ULINT_UNDEFINED); } /* Fall through */ case DATA_CHAR: case DATA_VARCHAR: case DATA_MYSQL: case DATA_VARMYSQL: /* Space is the padding character for all char and binary strings, and starting from 5.0.3, also for TEXT strings. */ return(0x20); case DATA_BLOB: if (!(prtype & DATA_BINARY_TYPE)) { return(0x20); } /* Fall through */ default: /* No padding specified */ return(ULINT_UNDEFINED); } } /************************************************************************** Stores for a type the information which determines its alphabetical ordering and the storage size of an SQL NULL value. This is the >= 4.1.x storage format. */ UNIV_INLINE void dtype_new_store_for_order_and_null_size( /*====================================*/ byte* buf, /* in: buffer for DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE bytes where we store the info */ dtype_t* type, /* in: type struct */ ulint prefix_len)/* in: prefix length to replace type->len, or 0 */ { #if 6 != DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE #error "6 != DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE" #endif ulint len; buf[0] = (byte)(type->mtype & 0xFFUL); if (type->prtype & DATA_BINARY_TYPE) { buf[0] = buf[0] | 128; } /* In versions < 4.1.2 we had: if (type->prtype & DATA_NONLATIN1) { buf[0] = buf[0] | 64; } */ buf[1] = (byte)(type->prtype & 0xFFUL); len = prefix_len ? prefix_len : type->len; mach_write_to_2(buf + 2, len & 0xFFFFUL); ut_ad(dtype_get_charset_coll(type->prtype) < 256); mach_write_to_2(buf + 4, dtype_get_charset_coll(type->prtype)); if (type->prtype & DATA_NOT_NULL) { buf[4] |= 128; } } /************************************************************************** Reads to a type the stored information which determines its alphabetical ordering and the storage size of an SQL NULL value. This is the < 4.1.x storage format. */ UNIV_INLINE void dtype_read_for_order_and_null_size( /*===============================*/ dtype_t* type, /* in: type struct */ byte* buf) /* in: buffer for stored type order info */ { #if 4 != DATA_ORDER_NULL_TYPE_BUF_SIZE # error "4 != DATA_ORDER_NULL_TYPE_BUF_SIZE" #endif type->mtype = buf[0] & 63; type->prtype = buf[1]; if (buf[0] & 128) { type->prtype = type->prtype | DATA_BINARY_TYPE; } type->len = mach_read_from_2(buf + 2); type->prtype = dtype_form_prtype(type->prtype, data_mysql_default_charset_coll); dtype_set_mblen(type); } /************************************************************************** Reads to a type the stored information which determines its alphabetical ordering and the storage size of an SQL NULL value. This is the >= 4.1.x storage format. */ UNIV_INLINE void dtype_new_read_for_order_and_null_size( /*===================================*/ dtype_t* type, /* in: type struct */ byte* buf) /* in: buffer for stored type order info */ { ulint charset_coll; #if 6 != DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE #error "6 != DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE" #endif type->mtype = buf[0] & 63; type->prtype = buf[1]; if (buf[0] & 128) { type->prtype |= DATA_BINARY_TYPE; } if (buf[4] & 128) { type->prtype |= DATA_NOT_NULL; } type->len = mach_read_from_2(buf + 2); mach_read_from_2(buf + 4); charset_coll = mach_read_from_2(buf + 4) & 0x7fff; if (dtype_is_string_type(type->mtype)) { ut_a(charset_coll < 256); if (charset_coll == 0) { /* This insert buffer record was inserted with MySQL version < 4.1.2, and the charset-collation code was not explicitly stored to dtype->prtype at that time. It must be the default charset-collation of this MySQL installation. */ charset_coll = data_mysql_default_charset_coll; } type->prtype = dtype_form_prtype(type->prtype, charset_coll); } dtype_set_mblen(type); } /*************************************************************************** Returns the size of a fixed size data type, 0 if not a fixed size type. */ UNIV_INLINE ulint dtype_get_fixed_size_low( /*=====================*/ /* out: fixed size, or 0 */ ulint mtype, /* in: main type */ ulint prtype, /* in: precise type */ ulint len, /* in: length */ ulint mbminlen, /* in: minimum length of a multibyte char */ ulint mbmaxlen) /* in: maximum length of a multibyte char */ { switch (mtype) { case DATA_SYS: #ifdef UNIV_DEBUG switch (prtype & DATA_MYSQL_TYPE_MASK) { case DATA_ROW_ID: ut_ad(len == DATA_ROW_ID_LEN); break; case DATA_TRX_ID: ut_ad(len == DATA_TRX_ID_LEN); break; case DATA_ROLL_PTR: ut_ad(len == DATA_ROLL_PTR_LEN); break; default: ut_ad(0); return(0); } #endif /* UNIV_DEBUG */ case DATA_CHAR: case DATA_FIXBINARY: case DATA_INT: case DATA_FLOAT: case DATA_DOUBLE: return(len); case DATA_MYSQL: if (prtype & DATA_BINARY_TYPE) { return(len); } else { #ifdef UNIV_HOTBACKUP if (mbminlen == mbmaxlen) { return(len); } #else /* UNIV_HOTBACKUP */ /* We play it safe here and ask MySQL for mbminlen and mbmaxlen. Although mbminlen and mbmaxlen are initialized if and only if prtype is (in one of the 3 functions in this file), it could be that none of these functions has been called. */ ulint i_mbminlen, i_mbmaxlen; innobase_get_cset_width( dtype_get_charset_coll(prtype), &i_mbminlen, &i_mbmaxlen); if (UNIV_UNLIKELY(mbminlen != i_mbminlen) || UNIV_UNLIKELY(mbmaxlen != i_mbmaxlen)) { ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: " "mbminlen=%lu, " "mbmaxlen=%lu, " "type->mbminlen=%lu, " "type->mbmaxlen=%lu\n", (ulong) i_mbminlen, (ulong) i_mbmaxlen, (ulong) mbminlen, (ulong) mbmaxlen); } if (mbminlen == mbmaxlen) { return(len); } #endif /* !UNIV_HOTBACKUP */ } /* fall through for variable-length charsets */ case DATA_VARCHAR: case DATA_BINARY: case DATA_DECIMAL: case DATA_VARMYSQL: case DATA_BLOB: return(0); default: ut_error; } return(0); } /*************************************************************************** Returns the minimum size of a data type. */ UNIV_INLINE ulint dtype_get_min_size_low( /*===================*/ /* out: minimum size */ ulint mtype, /* in: main type */ ulint prtype, /* in: precise type */ ulint len, /* in: length */ ulint mbminlen, /* in: minimum length of a multibyte char */ ulint mbmaxlen) /* in: maximum length of a multibyte char */ { switch (mtype) { case DATA_SYS: #ifdef UNIV_DEBUG switch (prtype & DATA_MYSQL_TYPE_MASK) { case DATA_ROW_ID: ut_ad(len == DATA_ROW_ID_LEN); break; case DATA_TRX_ID: ut_ad(len == DATA_TRX_ID_LEN); break; case DATA_ROLL_PTR: ut_ad(len == DATA_ROLL_PTR_LEN); break; default: ut_ad(0); return(0); } #endif /* UNIV_DEBUG */ case DATA_CHAR: case DATA_FIXBINARY: case DATA_INT: case DATA_FLOAT: case DATA_DOUBLE: return(len); case DATA_MYSQL: if ((prtype & DATA_BINARY_TYPE) || mbminlen == mbmaxlen) { return(len); } /* this is a variable-length character set */ ut_a(mbminlen > 0); ut_a(mbmaxlen > mbminlen); ut_a(len % mbmaxlen == 0); return(len * mbminlen / mbmaxlen); case DATA_VARCHAR: case DATA_BINARY: case DATA_DECIMAL: case DATA_VARMYSQL: case DATA_BLOB: return(0); default: ut_error; } return(0); } /*************************************************************************** Returns the maximum size of a data type. Note: types in system tables may be incomplete and return incorrect information. */ UNIV_INLINE ulint dtype_get_max_size_low( /*===================*/ /* out: maximum size */ ulint mtype, /* in: main type */ ulint len) /* in: length */ { switch (mtype) { case DATA_SYS: case DATA_CHAR: case DATA_FIXBINARY: case DATA_INT: case DATA_FLOAT: case DATA_DOUBLE: case DATA_MYSQL: case DATA_VARCHAR: case DATA_BINARY: case DATA_DECIMAL: case DATA_VARMYSQL: return(len); case DATA_BLOB: break; default: ut_error; } return(ULINT_MAX); } /*************************************************************************** Returns the ROW_FORMAT=REDUNDANT stored SQL NULL size of a type. For fixed length types it is the fixed length of the type, otherwise 0. */ UNIV_INLINE ulint dtype_get_sql_null_size( /*====================*/ /* out: SQL null storage size in ROW_FORMAT=REDUNDANT */ const dtype_t* type) /* in: type */ { return(dtype_get_fixed_size_low(type->mtype, type->prtype, type->len, type->mbminlen, type->mbmaxlen)); }