/***************************************************************************** Copyright (c) 1994, 2012, 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 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(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); } } #ifndef UNIV_HOTBACKUP /*********************************************************************//** Tests if two data fields are equal. If len==0, tests the data length and content for equality. If len>0, tests the first len bytes of the content for equality. @return TRUE if both fields are NULL or if they are equal */ UNIV_INLINE ibool dfield_datas_are_binary_equal( /*==========================*/ const dfield_t* field1, /*!< in: field */ const dfield_t* field2, /*!< in: field */ ulint len) /*!< in: maximum prefix to compare, or 0 to compare the whole field length */ { ulint len2 = len; if (field1->len == UNIV_SQL_NULL || len == 0 || field1->len < len) { len = field1->len; } if (field2->len == UNIV_SQL_NULL || len2 == 0 || field2->len < len2) { len2 = field2->len; } return(len == len2 && (len == UNIV_SQL_NULL || !memcmp(field1->data, field2->data, len))); } /*********************************************************************//** Tests if dfield data length and content is equal to the given. @return TRUE if equal */ UNIV_INLINE ibool dfield_data_is_binary_equal( /*========================*/ const dfield_t* field, /*!< in: field */ ulint len, /*!< in: data length or UNIV_SQL_NULL */ const byte* data) /*!< in: data */ { return(len == dfield_get_len(field) && (len == UNIV_SQL_NULL || !memcmp(dfield_get_data(field), data, len))); } #endif /* !UNIV_HOTBACKUP */ /*********************************************************************//** 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 from an already allocated chunk of memory. The size of the chunk must be at least DTUPLE_EST_ALLOC(n_fields). The default value for number of fields used in record comparisons for this tuple is n_fields. @return created tuple (inside buf) */ UNIV_INLINE dtuple_t* dtuple_create_from_mem( /*===================*/ void* buf, /*!< in, out: buffer to use */ ulint buf_size, /*!< in: buffer size */ ulint n_fields) /*!< in: number of fields */ { dtuple_t* tuple; ut_ad(buf != NULL); ut_a(buf_size >= DTUPLE_EST_ALLOC(n_fields)); tuple = (dtuple_t*) buf; 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; } } #endif return(tuple); } /**********************************************************//** 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, DTUPLE_EST_ALLOC(n_fields) bytes will be allocated from this heap */ ulint n_fields) /*!< in: number of fields */ { void* buf; ulint buf_size; dtuple_t* tuple; ut_ad(heap); buf_size = DTUPLE_EST_ALLOC(n_fields); buf = mem_heap_alloc(heap, buf_size); tuple = dtuple_create_from_mem(buf, buf_size, n_fields); #ifdef UNIV_DEBUG 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 */ index_id_t 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_ull(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); }