/******************************************************
Data types

(c) 1996 Innobase Oy

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

#include "mach0data.h"

/*************************************************************************
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: length of type */
	ulint		prec)	/* in: precision of type */
{
	ut_ad(type);
	ut_ad(mtype <= DATA_MTYPE_MAX);
	
	type->mtype = mtype;
	type->prtype = prtype;
	type->len = len;
	type->prec = prec;
	type->chrset = 0;

	ut_ad(dtype_validate(type));
}

/*************************************************************************
Copies a data type structure. */
UNIV_INLINE
void
dtype_copy(
/*=======*/
	dtype_t*	type1,	/* in: type struct to copy to */
	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 type precision. */
UNIV_INLINE
ulint
dtype_get_prec(
/*===========*/
	dtype_t*	type)
{
	ut_ad(type);

	return(type->prec);
}

/*************************************************************************
Gets the padding character code for the type. */
UNIV_INLINE
ulint
dtype_get_pad_char(
/*===============*/
				/* out: padding character code, or
				ULINT_UNDEFINED if no padding specified */
	dtype_t*	type)	/* in: type */
{
	if (type->mtype == DATA_CHAR
	    || type->mtype == DATA_VARCHAR
	    || type->mtype == DATA_BINARY
	    || type->mtype == DATA_FIXBINARY
	    || type->mtype == DATA_MYSQL
	    || type->mtype == DATA_VARMYSQL) {

		/* Space is the padding character for all char and binary
	        strings */

		return((ulint)' ');
	}

	/* 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 */
{
	ut_ad(6 == DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
	
	buf[0] = (byte)(type->mtype & 0xFFUL);

	if (type->prtype & DATA_BINARY_TYPE) {
		buf[0] = buf[0] | 128;
	}

	if (type->prtype & DATA_NONLATIN1) {
		buf[0] = buf[0] | 64;
	}

	buf[1] = (byte)(type->prtype & 0xFFUL);

	mach_write_to_2(buf + 2, type->len & 0xFFFFUL);

	mach_write_to_2(buf + 4, type->chrset & 0xFFFFUL);
}

/**************************************************************************
Reads to a type the stored information which determines its alphabetical
ordering and the storage size of an SQL NULL value. */
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 */
{
	ut_ad(4 == DATA_ORDER_NULL_TYPE_BUF_SIZE);
	
	type->mtype = buf[0] & 63;
	type->prtype = buf[1];

	if (buf[0] & 128) {
	        type->prtype = type->prtype | DATA_BINARY_TYPE;
	}

	if (buf[0] & 64) {
	        type->prtype = type->prtype | DATA_NONLATIN1;
	}

	type->len = mach_read_from_2(buf + 2);
}	

/**************************************************************************
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 */
{
	ut_ad(6 == DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
	
	type->mtype = buf[0] & 63;
	type->prtype = buf[1];

	if (buf[0] & 128) {
	        type->prtype = type->prtype | DATA_BINARY_TYPE;
	}

	if (buf[0] & 64) {
	        type->prtype = type->prtype | DATA_NONLATIN1;
	}

	type->len = mach_read_from_2(buf + 2);

	type->chrset = mach_read_from_2(buf + 4);
}	

/***************************************************************************
Returns the size of a fixed size data type, 0 if not a fixed size type. */
UNIV_INLINE
ulint
dtype_get_fixed_size(
/*=================*/
				/* out: fixed size, or 0 */
	dtype_t*	type)	/* in: type */
{
	ulint	mtype;

	mtype = dtype_get_mtype(type);

	switch (mtype) {
	case DATA_CHAR:
	case DATA_FIXBINARY:
	case DATA_INT:
	case DATA_FLOAT:
	case DATA_DOUBLE:
	case DATA_MYSQL:
			return(dtype_get_len(type));

	case DATA_SYS: 	if (type->prtype == DATA_ROW_ID) {
				return(DATA_ROW_ID_LEN);
			} else if (type->prtype == DATA_TRX_ID) {
				return(DATA_TRX_ID_LEN);
			} else if (type->prtype == DATA_ROLL_PTR) {
				return(DATA_ROLL_PTR_LEN);
			} else {
				return(0);
			}
	case DATA_VARCHAR:
	case DATA_BINARY:
	case DATA_DECIMAL:
	case DATA_VARMYSQL:
	case DATA_BLOB:
			return(0); 
	default:	ut_a(0);
	}

	return(0);
}

/***************************************************************************
Returns a stored SQL NULL size for 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 */
	dtype_t*	type)	/* in: type */
{
	return(dtype_get_fixed_size(type));
}

/***************************************************************************
Returns TRUE if a type is of a fixed size. */
UNIV_INLINE
ibool
dtype_is_fixed_size(
/*================*/
				/* out: TRUE if fixed size */
	dtype_t*	type)	/* in: type */
{
	ulint	size;

	size = dtype_get_fixed_size(type);

	if (size) {
		return(TRUE);
	}

	return(FALSE);
}
