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

Copyright (c) 1994, 2009, Innobase Oy. 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., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA

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

/********************************************************************//**
@file include/data0data.ic
SQL data field and tuple

Created 5/30/1994 Heikki Tuuri
*************************************************************************/

#include "mem0mem.h"
#include "ut0rnd.h"

#ifdef UNIV_DEBUG
/** Dummy variable to catch access to uninitialized fields.  In the
debug version, dtuple_create() will make all fields of dtuple_t point
to data_error. */
extern byte data_error;

/*********************************************************************//**
Gets pointer to the type struct of SQL data field.
@return	pointer to the type struct */
UNIV_INLINE
dtype_t*
dfield_get_type(
/*============*/
	const dfield_t*	field)	/*!< in: SQL data field */
{
	ut_ad(field);

	return((dtype_t*) &(field->type));
}
#endif /* UNIV_DEBUG */

/*********************************************************************//**
Sets the type struct of SQL data field. */
UNIV_INLINE
void
dfield_set_type(
/*============*/
	dfield_t*	field,	/*!< in: SQL data field */
	dtype_t*	type)	/*!< in: pointer to data type struct */
{
	ut_ad(field && type);

	field->type = *type;
}

#ifdef UNIV_DEBUG
/*********************************************************************//**
Gets pointer to the data in a field.
@return	pointer to data */
UNIV_INLINE
void*
dfield_get_data(
/*============*/
	const dfield_t* field)	/*!< in: field */
{
	ut_ad(field);
	ut_ad((field->len == UNIV_SQL_NULL)
	      || (field->data != &data_error));

	return((void*) field->data);
}
#endif /* UNIV_DEBUG */

/*********************************************************************//**
Gets length of field data.
@return	length of data; UNIV_SQL_NULL if SQL null data */
UNIV_INLINE
ulint
dfield_get_len(
/*===========*/
	const dfield_t*	field)	/*!< in: field */
{
	ut_ad(field);
	ut_ad((field->len == UNIV_SQL_NULL)
	      || (field->data != &data_error));

	return(field->len);
}

/*********************************************************************//**
Sets length in a field. */
UNIV_INLINE
void
dfield_set_len(
/*===========*/
	dfield_t*	field,	/*!< in: field */
	ulint		len)	/*!< in: length or UNIV_SQL_NULL */
{
	ut_ad(field);
#ifdef UNIV_VALGRIND_DEBUG
	if (len != UNIV_SQL_NULL) UNIV_MEM_ASSERT_RW(field->data, len);
#endif /* UNIV_VALGRIND_DEBUG */

	field->ext = 0;
	field->len = len;
}

/*********************************************************************//**
Determines if a field is SQL NULL
@return	nonzero if SQL null data */
UNIV_INLINE
ulint
dfield_is_null(
/*===========*/
	const dfield_t* field)	/*!< in: field */
{
	ut_ad(field);

	return(field->len == UNIV_SQL_NULL);
}

/*********************************************************************//**
Determines if a field is externally stored
@return	nonzero if externally stored */
UNIV_INLINE
ulint
dfield_is_ext(
/*==========*/
	const dfield_t* field)	/*!< in: field */
{
	ut_ad(field);

	return(UNIV_UNLIKELY(field->ext));
}

/*********************************************************************//**
Sets the "external storage" flag */
UNIV_INLINE
void
dfield_set_ext(
/*===========*/
	dfield_t*	field)	/*!< in/out: field */
{
	ut_ad(field);

	field->ext = 1;
}

/*********************************************************************//**
Sets pointer to the data and length in a field. */
UNIV_INLINE
void
dfield_set_data(
/*============*/
	dfield_t*	field,	/*!< in: field */
	const void*	data,	/*!< in: data */
	ulint		len)	/*!< in: length or UNIV_SQL_NULL */
{
	ut_ad(field);

#ifdef UNIV_VALGRIND_DEBUG
	if (len != UNIV_SQL_NULL) UNIV_MEM_ASSERT_RW(data, len);
#endif /* UNIV_VALGRIND_DEBUG */
	field->data = (void*) data;
	field->ext = 0;
	field->len = len;
}

/*********************************************************************//**
Sets a data field to SQL NULL. */
UNIV_INLINE
void
dfield_set_null(
/*============*/
	dfield_t*	field)	/*!< in/out: field */
{
	dfield_set_data(field, NULL, UNIV_SQL_NULL);
}

/*********************************************************************//**
Copies the data and len fields. */
UNIV_INLINE
void
dfield_copy_data(
/*=============*/
	dfield_t*	field1,	/*!< out: field to copy to */
	const dfield_t*	field2)	/*!< in: field to copy from */
{
	ut_ad(field1 && field2);

	field1->data = field2->data;
	field1->len = field2->len;
	field1->ext = field2->ext;
}

/*********************************************************************//**
Copies a data field to another. */
UNIV_INLINE
void
dfield_copy(
/*========*/
	dfield_t*	field1,	/*!< out: field to copy to */
	const dfield_t*	field2)	/*!< in: field to copy from */
{
	*field1 = *field2;
}

/*********************************************************************//**
Copies the data pointed to by a data field. */
UNIV_INLINE
void
dfield_dup(
/*=======*/
	dfield_t*	field,	/*!< in/out: data field */
	mem_heap_t*	heap)	/*!< in: memory heap where allocated */
{
	if (!dfield_is_null(field)) {
		UNIV_MEM_ASSERT_RW(field->data, field->len);
		field->data = mem_heap_dup(heap, field->data, field->len);
	}
}

/*********************************************************************//**
Tests if data length and content is equal for two dfields.
@return	TRUE if equal */
UNIV_INLINE
ibool
dfield_datas_are_binary_equal(
/*==========================*/
	const dfield_t*	field1,	/*!< in: field */
	const dfield_t*	field2)	/*!< in: field */
{
	ulint	len;

	len = field1->len;

	return(len == field2->len
	       && (len == UNIV_SQL_NULL
		   || !memcmp(field1->data, field2->data, len)));
}

/*********************************************************************//**
Gets info bits in a data tuple.
@return	info bits */
UNIV_INLINE
ulint
dtuple_get_info_bits(
/*=================*/
	const dtuple_t*	tuple)	/*!< in: tuple */
{
	ut_ad(tuple);

	return(tuple->info_bits);
}

/*********************************************************************//**
Sets info bits in a data tuple. */
UNIV_INLINE
void
dtuple_set_info_bits(
/*=================*/
	dtuple_t*	tuple,		/*!< in: tuple */
	ulint		info_bits)	/*!< in: info bits */
{
	ut_ad(tuple);

	tuple->info_bits = info_bits;
}

/*********************************************************************//**
Gets number of fields used in record comparisons.
@return	number of fields used in comparisons in rem0cmp.* */
UNIV_INLINE
ulint
dtuple_get_n_fields_cmp(
/*====================*/
	const dtuple_t*	tuple)	/*!< in: tuple */
{
	ut_ad(tuple);

	return(tuple->n_fields_cmp);
}

/*********************************************************************//**
Sets number of fields used in record comparisons. */
UNIV_INLINE
void
dtuple_set_n_fields_cmp(
/*====================*/
	dtuple_t*	tuple,		/*!< in: tuple */
	ulint		n_fields_cmp)	/*!< in: number of fields used in
					comparisons in rem0cmp.* */
{
	ut_ad(tuple);
	ut_ad(n_fields_cmp <= tuple->n_fields);

	tuple->n_fields_cmp = n_fields_cmp;
}

/*********************************************************************//**
Gets number of fields in a data tuple.
@return	number of fields */
UNIV_INLINE
ulint
dtuple_get_n_fields(
/*================*/
	const dtuple_t*	tuple)	/*!< in: tuple */
{
	ut_ad(tuple);

	return(tuple->n_fields);
}

#ifdef UNIV_DEBUG
/*********************************************************************//**
Gets nth field of a tuple.
@return	nth field */
UNIV_INLINE
dfield_t*
dtuple_get_nth_field(
/*=================*/
	const dtuple_t*	tuple,	/*!< in: tuple */
	ulint		n)	/*!< in: index of field */
{
	ut_ad(tuple);
	ut_ad(n < tuple->n_fields);

	return((dfield_t*) tuple->fields + n);
}
#endif /* UNIV_DEBUG */

/**********************************************************//**
Creates a data tuple to a memory heap. The default value for number
of fields used in record comparisons for this tuple is n_fields.
@return	own: created tuple */
UNIV_INLINE
dtuple_t*
dtuple_create(
/*==========*/
	mem_heap_t*	heap,	/*!< in: memory heap where the tuple
				is created */
	ulint		n_fields) /*!< in: number of fields */
{
	dtuple_t*	tuple;

	ut_ad(heap);

	tuple = (dtuple_t*) mem_heap_alloc(heap, sizeof(dtuple_t)
					   + n_fields * sizeof(dfield_t));
	tuple->info_bits = 0;
	tuple->n_fields = n_fields;
	tuple->n_fields_cmp = n_fields;
	tuple->fields = (dfield_t*) &tuple[1];

#ifdef UNIV_DEBUG
	tuple->magic_n = DATA_TUPLE_MAGIC_N;

	{	/* In the debug version, initialize fields to an error value */
		ulint	i;

		for (i = 0; i < n_fields; i++) {
			dfield_t*       field;

			field = dtuple_get_nth_field(tuple, i);

			dfield_set_len(field, UNIV_SQL_NULL);
			field->data = &data_error;
			dfield_get_type(field)->mtype = DATA_ERROR;
		}
	}

	UNIV_MEM_INVALID(tuple->fields, n_fields * sizeof *tuple->fields);
#endif
	return(tuple);
}

/**********************************************************//**
Wrap data fields in a tuple. The default value for number
of fields used in record comparisons for this tuple is n_fields.
@return	data tuple */
UNIV_INLINE
const dtuple_t*
dtuple_from_fields(
/*===============*/
	dtuple_t*	tuple,		/*!< in: storage for data tuple */
	const dfield_t*	fields,		/*!< in: fields */
	ulint		n_fields)	/*!< in: number of fields */
{
	tuple->info_bits = 0;
	tuple->n_fields = tuple->n_fields_cmp = n_fields;
	tuple->fields = (dfield_t*) fields;
	ut_d(tuple->magic_n = DATA_TUPLE_MAGIC_N);

	return(tuple);
}

/*********************************************************************//**
Copies a data tuple to another.  This is a shallow copy; if a deep copy
is desired, dfield_dup() will have to be invoked on each field.
@return	own: copy of tuple */
UNIV_INLINE
dtuple_t*
dtuple_copy(
/*========*/
	const dtuple_t*	tuple,	/*!< in: tuple to copy from */
	mem_heap_t*	heap)	/*!< in: memory heap
				where the tuple is created */
{
	ulint		n_fields	= dtuple_get_n_fields(tuple);
	dtuple_t*	new_tuple	= dtuple_create(heap, n_fields);
	ulint		i;

	for (i = 0; i < n_fields; i++) {
		dfield_copy(dtuple_get_nth_field(new_tuple, i),
			    dtuple_get_nth_field(tuple, i));
	}

	return(new_tuple);
}

/**********************************************************//**
The following function returns the sum of data lengths of a tuple. The space
occupied by the field structs or the tuple struct is not counted. Neither
is possible space in externally stored parts of the field.
@return	sum of data lengths */
UNIV_INLINE
ulint
dtuple_get_data_size(
/*=================*/
	const dtuple_t*	tuple,	/*!< in: typed data tuple */
	ulint		comp)	/*!< in: nonzero=ROW_FORMAT=COMPACT  */
{
	const dfield_t*	field;
	ulint		n_fields;
	ulint		len;
	ulint		i;
	ulint		sum	= 0;

	ut_ad(tuple);
	ut_ad(dtuple_check_typed(tuple));
	ut_ad(tuple->magic_n == DATA_TUPLE_MAGIC_N);

	n_fields = tuple->n_fields;

	for (i = 0; i < n_fields; i++) {
		field = dtuple_get_nth_field(tuple,  i);
		len = dfield_get_len(field);

		if (len == UNIV_SQL_NULL) {
			len = dtype_get_sql_null_size(dfield_get_type(field),
						      comp);
		}

		sum += len;
	}

	return(sum);
}

/*********************************************************************//**
Computes the number of externally stored fields in a data tuple.
@return	number of externally stored fields */
UNIV_INLINE
ulint
dtuple_get_n_ext(
/*=============*/
	const dtuple_t*	tuple)	/*!< in: tuple */
{
	ulint	n_ext		= 0;
	ulint	n_fields	= tuple->n_fields;
	ulint	i;

	ut_ad(tuple);
	ut_ad(dtuple_check_typed(tuple));
	ut_ad(tuple->magic_n == DATA_TUPLE_MAGIC_N);

	for (i = 0; i < n_fields; i++) {
		n_ext += dtuple_get_nth_field(tuple, i)->ext;
	}

	return(n_ext);
}

/*******************************************************************//**
Sets types of fields binary in a tuple. */
UNIV_INLINE
void
dtuple_set_types_binary(
/*====================*/
	dtuple_t*	tuple,	/*!< in: data tuple */
	ulint		n)	/*!< in: number of fields to set */
{
	dtype_t*	dfield_type;
	ulint		i;

	for (i = 0; i < n; i++) {
		dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
		dtype_set(dfield_type, DATA_BINARY, 0, 0);
	}
}

/************************************************************//**
Folds a prefix given as the number of fields of a tuple.
@return	the folded value */
UNIV_INLINE
ulint
dtuple_fold(
/*========*/
	const dtuple_t*	tuple,	/*!< in: the tuple */
	ulint		n_fields,/*!< in: number of complete fields to fold */
	ulint		n_bytes,/*!< in: number of bytes to fold in an
				incomplete last field */
	dulint		tree_id)/*!< in: index tree id */
{
	const dfield_t*	field;
	ulint		i;
	const byte*	data;
	ulint		len;
	ulint		fold;

	ut_ad(tuple);
	ut_ad(tuple->magic_n == DATA_TUPLE_MAGIC_N);
	ut_ad(dtuple_check_typed(tuple));

	fold = ut_fold_dulint(tree_id);

	for (i = 0; i < n_fields; i++) {
		field = dtuple_get_nth_field(tuple, i);

		data = (const byte*) dfield_get_data(field);
		len = dfield_get_len(field);

		if (len != UNIV_SQL_NULL) {
			fold = ut_fold_ulint_pair(fold,
						  ut_fold_binary(data, len));
		}
	}

	if (n_bytes > 0) {
		field = dtuple_get_nth_field(tuple, i);

		data = (const byte*) dfield_get_data(field);
		len = dfield_get_len(field);

		if (len != UNIV_SQL_NULL) {
			if (len > n_bytes) {
				len = n_bytes;
			}

			fold = ut_fold_ulint_pair(fold,
						  ut_fold_binary(data, len));
		}
	}

	return(fold);
}

/**********************************************************************//**
Writes an SQL null field full of zeros. */
UNIV_INLINE
void
data_write_sql_null(
/*================*/
	byte*	data,	/*!< in: pointer to a buffer of size len */
	ulint	len)	/*!< in: SQL null size in bytes */
{
	memset(data, 0, len);
}

/**********************************************************************//**
Checks if a dtuple contains an SQL null value.
@return	TRUE if some field is SQL null */
UNIV_INLINE
ibool
dtuple_contains_null(
/*=================*/
	const dtuple_t*	tuple)	/*!< in: dtuple */
{
	ulint	n;
	ulint	i;

	n = dtuple_get_n_fields(tuple);

	for (i = 0; i < n; i++) {
		if (dfield_is_null(dtuple_get_nth_field(tuple, i))) {

			return(TRUE);
		}
	}

	return(FALSE);
}

/**************************************************************//**
Frees the memory in a big rec vector. */
UNIV_INLINE
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);
}