/*****************************************************************************

Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.

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; version 2 of the License.

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.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA

*****************************************************************************/

/**************************************************//**
@file data/data0type.cc
Data types

Created 1/16/1996 Heikki Tuuri
*******************************************************/

#include "data0type.h"

#ifdef UNIV_NONINL
#include "data0type.ic"
#endif

#ifndef UNIV_HOTBACKUP
# include "ha_prototypes.h"

/* 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. */

UNIV_INTERN ulint	data_mysql_default_charset_coll;

/*********************************************************************//**
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.
@return	length of the prefix, in bytes */
UNIV_INTERN
ulint
dtype_get_at_most_n_mbchars(
/*========================*/
	ulint		prtype,		/*!< in: precise type */
	ulint		mbminmaxlen,	/*!< in: minimum and maximum length of
					a multi-byte character */
	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 */
{
	ulint	mbminlen = DATA_MBMINLEN(mbminmaxlen);
	ulint	mbmaxlen = DATA_MBMAXLEN(mbminmaxlen);

	ut_a(data_len != UNIV_SQL_NULL);
	ut_ad(!mbmaxlen || !(prefix_len % mbmaxlen));

	if (mbminlen != mbmaxlen) {
		ut_a(!(prefix_len % mbmaxlen));
		return(innobase_get_at_most_n_mbchars(
			dtype_get_charset_coll(prtype),
			prefix_len, data_len, str));
	}

	if (prefix_len < data_len) {

		return(prefix_len);

	}

	return(data_len);
}
#endif /* UNIV_HOTBACKUP */

/*********************************************************************//**
Checks if a data main type is a string type. Also a BLOB is considered a
string type.
@return	TRUE if string type */
UNIV_INTERN
ibool
dtype_is_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.
@return	TRUE if binary string type */
UNIV_INTERN
ibool
dtype_is_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.
@return	TRUE if non-binary string type */
UNIV_INTERN
ibool
dtype_is_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);
}

/*********************************************************************//**
Forms a precise type from the < 4.1.2 format precise type plus the
charset-collation code.
@return precise type, including the charset-collation code */
UNIV_INTERN
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 <= MAX_CHAR_COLL_NUM);

	return(old_prtype + (charset_coll << 16));
}

/*********************************************************************//**
Validates a data type structure.
@return	TRUE if ok */
UNIV_INTERN
ibool
dtype_validate(
/*===========*/
	const dtype_t*	type)	/*!< in: type struct to validate */
{
	ut_a(type);
	ut_a(type->mtype >= DATA_VARCHAR);
	ut_a(type->mtype <= DATA_MYSQL);

	if (type->mtype == DATA_SYS) {
		ut_a((type->prtype & DATA_MYSQL_TYPE_MASK) < DATA_N_SYS_COLS);
	}

#ifndef UNIV_HOTBACKUP
	ut_a(dtype_get_mbminlen(type) <= dtype_get_mbmaxlen(type));
#endif /* !UNIV_HOTBACKUP */

	return(TRUE);
}

#ifndef UNIV_HOTBACKUP
/*********************************************************************//**
Prints a data type structure. */
UNIV_INTERN
void
dtype_print(
/*========*/
	const dtype_t*	type)	/*!< in: type */
{
	ulint	mtype;
	ulint	prtype;
	ulint	len;

	ut_a(type);

	mtype = type->mtype;
	prtype = type->prtype;

	switch (mtype) {
	case DATA_VARCHAR:
		fputs("DATA_VARCHAR", stderr);
		break;

	case DATA_CHAR:
		fputs("DATA_CHAR", stderr);
		break;

	case DATA_BINARY:
		fputs("DATA_BINARY", stderr);
		break;

	case DATA_FIXBINARY:
		fputs("DATA_FIXBINARY", stderr);
		break;

	case DATA_BLOB:
		fputs("DATA_BLOB", stderr);
		break;

	case DATA_INT:
		fputs("DATA_INT", stderr);
		break;

	case DATA_MYSQL:
		fputs("DATA_MYSQL", stderr);
		break;

	case DATA_SYS:
		fputs("DATA_SYS", stderr);
		break;

	case DATA_FLOAT:
		fputs("DATA_FLOAT", stderr);
		break;

	case DATA_DOUBLE:
		fputs("DATA_DOUBLE", stderr);
		break;

	case DATA_DECIMAL:
		fputs("DATA_DECIMAL", stderr);
		break;

	case DATA_VARMYSQL:
		fputs("DATA_VARMYSQL", stderr);
		break;

	default:
		fprintf(stderr, "type %lu", (ulong) mtype);
		break;
	}

	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_ENGLISH) {
			fputs("DATA_ENGLISH", stderr);
		} else {
			fprintf(stderr, "prtype %lu", (ulong) prtype);
		}
	} else {
		if (prtype & DATA_UNSIGNED) {
			fputs(" DATA_UNSIGNED", stderr);
		}

		if (prtype & DATA_BINARY_TYPE) {
			fputs(" DATA_BINARY_TYPE", stderr);
		}

		if (prtype & DATA_NOT_NULL) {
			fputs(" DATA_NOT_NULL", stderr);
		}
	}

	fprintf(stderr, " len %lu", (ulong) len);
}
#endif /* !UNIV_HOTBACKUP */
