mirror of
https://github.com/MariaDB/server.git
synced 2025-01-18 04:53:01 +01:00
571 lines
14 KiB
Text
571 lines
14 KiB
Text
/******************************************************
|
|
Data types
|
|
|
|
(c) 1996 Innobase Oy
|
|
|
|
Created 1/16/1996 Heikki Tuuri
|
|
*******************************************************/
|
|
|
|
#include "mach0data.h"
|
|
#include "ha_prototypes.h"
|
|
|
|
/*************************************************************************
|
|
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);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Determines if a MySQL string type is a subset of UTF-8. This function
|
|
may return false negatives, in case further character-set collation
|
|
codes are introduced in MySQL later. */
|
|
UNIV_INLINE
|
|
ibool
|
|
dtype_is_utf8(
|
|
/*==========*/
|
|
/* out: TRUE if a subset of UTF-8 */
|
|
ulint prtype) /* in: precise data type */
|
|
{
|
|
/* These codes have been copied from strings/ctype-extra.c
|
|
and strings/ctype-utf8.c. */
|
|
switch (dtype_get_charset_coll(prtype)) {
|
|
case 11: /* ascii_general_ci */
|
|
case 65: /* ascii_bin */
|
|
case 33: /* utf8_general_ci */
|
|
case 83: /* utf8_bin */
|
|
case 254: /* utf8_general_cs */
|
|
return(TRUE);
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
/*************************************************************************
|
|
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! */
|
|
const 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(
|
|
/*============*/
|
|
const dtype_t* type)
|
|
{
|
|
ut_ad(type);
|
|
|
|
return(type->mtype);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Gets the precise data type. */
|
|
UNIV_INLINE
|
|
ulint
|
|
dtype_get_prtype(
|
|
/*=============*/
|
|
const dtype_t* type)
|
|
{
|
|
ut_ad(type);
|
|
|
|
return(type->prtype);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Gets the type length. */
|
|
UNIV_INLINE
|
|
ulint
|
|
dtype_get_len(
|
|
/*==========*/
|
|
const 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 */
|
|
const 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 */
|
|
const 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 */
|
|
const 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);
|
|
|
|
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));
|
|
}
|