/************************************************************************
SQL data field and tuple

(c) 1994-1996 Innobase Oy

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

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

#ifdef UNIV_DEBUG
extern byte data_error;
#endif /* UNIV_DEBUG */

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

	return(&(field->type));
}

/*************************************************************************
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;
}

/*************************************************************************
Gets pointer to the data in a field. */
UNIV_INLINE
void* 
dfield_get_data(
/*============*/
				/* out: pointer to data */
	dfield_t* field)	/* in: field */
{
	ut_ad(field);
	ut_ad((field->len == UNIV_SQL_NULL)
	      || (field->data != &data_error)); 

	return(field->data);
}

/*************************************************************************
Gets length of field data. */
UNIV_INLINE
ulint
dfield_get_len(
/*===========*/
				/* out: length of data; UNIV_SQL_NULL if 
				SQL null data */
	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);

	field->len = len;
}

/*************************************************************************
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);

	field->data = (void*) data;
	field->len = len;
}

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

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

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

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

	len = field1->len;
	
	if ((len != field2->len)
	    || ((len != UNIV_SQL_NULL)
	        && (0 != ut_memcmp(field1->data, field2->data, len)))) {
	    	
		return(FALSE);
	}

	return(TRUE);
}

/*************************************************************************
Gets info bits in a data tuple. */
UNIV_INLINE
ulint
dtuple_get_info_bits(
/*=================*/
				/* out: info bits */
	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. */
UNIV_INLINE
ulint
dtuple_get_n_fields_cmp(
/*====================*/
				/* out: number of fields used in comparisons
				in rem0cmp.* */
	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. */
UNIV_INLINE
ulint
dtuple_get_n_fields(
/*================*/
				/* out: number of fields */
	dtuple_t* 	tuple)	/* in: tuple */
{
	ut_ad(tuple);

	return(tuple->n_fields);
}

/*************************************************************************
Gets nth field of a tuple. */
UNIV_INLINE
dfield_t* 
dtuple_get_nth_field(
/*=================*/
				/* out: nth field */
	dtuple_t* 	tuple,	/* in: tuple */
	ulint		n)	/* in: index of field */
{
	ut_ad(tuple);
	ut_ad(n < tuple->n_fields);

	return(tuple->fields + n);
}

/**************************************************************
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. */
UNIV_INLINE
dtuple_t*
dtuple_create(
/*==========*/
	 	 		/* out, own: created tuple */
	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*)(((byte*)tuple) + sizeof(dtuple_t));

#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++) {
			(tuple->fields + i)->data = &data_error;
			dfield_get_type(tuple->fields + i)->mtype = DATA_ERROR;
		}
	}
#endif
	return(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. */
UNIV_INLINE
ulint
dtuple_get_data_size(
/*=================*/
				/* out: sum of data lengths */
	dtuple_t*	tuple)	/* in: typed data tuple */
{
	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));
		}

		sum += len;
	}
	
	return(sum);
}

/***********************************************************************
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, 0);
	}
}

/****************************************************************
Folds a prefix given as the number of fields of a tuple. */
UNIV_INLINE
ulint
dtuple_fold(
/*========*/
				/* out: the folded value */
	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 */
{
	dfield_t*	field;
	ulint		i;
	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 = (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 = (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 */
{
	ulint	j;

	for (j = 0; j < len; j++) {
		data[j] = '\0';
	}
}

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

	n = dtuple_get_n_fields(tuple);

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

			return(TRUE);
		}
	}

	return(FALSE);
}