diff options
Diffstat (limited to 'innobase/dict/dict0dict.c')
-rw-r--r-- | innobase/dict/dict0dict.c | 1870 |
1 files changed, 1870 insertions, 0 deletions
diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c new file mode 100644 index 00000000000..098d34c70e3 --- /dev/null +++ b/innobase/dict/dict0dict.c @@ -0,0 +1,1870 @@ +/********************************************************************** +Data dictionary system + +(c) 1996 Innobase Oy + +Created 1/8/1996 Heikki Tuuri +***********************************************************************/ + +#include "dict0dict.h" + +#ifdef UNIV_NONINL +#include "dict0dict.ic" +#endif + +#include "buf0buf.h" +#include "data0type.h" +#include "mach0data.h" +#include "dict0boot.h" +#include "dict0mem.h" +#include "trx0undo.h" +#include "btr0btr.h" +#include "btr0sea.h" +#include "pars0pars.h" +#include "pars0sym.h" +#include "que0que.h" + + +dict_sys_t* dict_sys = NULL; /* the dictionary system */ + +#define DICT_HEAP_SIZE 100 /* initial memory heap size when + creating a table or index object */ +#define DICT_POOL_PER_PROCEDURE_HASH 512 /* buffer pool max size per stored + procedure hash table fixed size in + bytes */ +#define DICT_POOL_PER_TABLE_HASH 512 /* buffer pool max size per table + hash table fixed size in bytes */ +#define DICT_POOL_PER_COL_HASH 128 /* buffer pool max size per column + hash table fixed size in bytes */ +#define DICT_POOL_PER_VARYING 4 /* buffer pool max size per data + dictionary varying size in bytes */ + +/************************************************************************** +Frees tables from the end of table_LRU if the dictionary cache occupies +too much space. */ +static +void +dict_table_LRU_trim(void); +/*=====================*/ +/************************************************************************** +Adds a column to the data dictionary hash table. */ +static +void +dict_col_add_to_cache( +/*==================*/ + dict_table_t* table, /* in: table */ + dict_col_t* col); /* in: column */ +/************************************************************************** +Repositions a column in the data dictionary hash table when the table name +changes. */ +static +void +dict_col_reposition_in_cache( +/*=========================*/ + dict_table_t* table, /* in: table */ + dict_col_t* col, /* in: column */ + char* new_name); /* in: new table name */ +/************************************************************************** +Removes a column from the data dictionary hash table. */ +static +void +dict_col_remove_from_cache( +/*=======================*/ + dict_table_t* table, /* in: table */ + dict_col_t* col); /* in: column */ +/************************************************************************** +Removes an index from the dictionary cache. */ +static +void +dict_index_remove_from_cache( +/*=========================*/ + dict_table_t* table, /* in: table */ + dict_index_t* index); /* in, own: index */ +/*********************************************************************** +Adds a column to index. */ +UNIV_INLINE +void +dict_index_add_col( +/*===============*/ + dict_index_t* index, /* in: index */ + dict_col_t* col, /* in: column */ + ulint order); /* in: order criterion */ +/*********************************************************************** +Copies fields contained in index2 to index1. */ +static +void +dict_index_copy( +/*============*/ + dict_index_t* index1, /* in: index to copy to */ + dict_index_t* index2, /* in: index to copy from */ + ulint start, /* in: first position to copy */ + ulint end); /* in: last position to copy */ +/*********************************************************************** +Tries to find column names for the index in the column hash table and +sets the col field of the index. */ +static +ibool +dict_index_find_cols( +/*=================*/ + /* out: TRUE if success */ + dict_table_t* table, /* in: table */ + dict_index_t* index); /* in: index */ +/*********************************************************************** +Builds the internal dictionary cache representation for a clustered +index, containing also system fields not defined by the user. */ +static +dict_index_t* +dict_index_build_internal_clust( +/*============================*/ + /* out, own: the internal representation + of the clustered index */ + dict_table_t* table, /* in: table */ + dict_index_t* index); /* in: user representation of a clustered + index */ +/*********************************************************************** +Builds the internal dictionary cache representation for a non-clustered +index, containing also system fields not defined by the user. */ +static +dict_index_t* +dict_index_build_internal_non_clust( +/*================================*/ + /* out, own: the internal representation + of the non-clustered index */ + dict_table_t* table, /* in: table */ + dict_index_t* index); /* in: user representation of a non-clustered + index */ +/************************************************************************** +In an index tree, finds the index corresponding to a record in the tree. */ +UNIV_INLINE +dict_index_t* +dict_tree_find_index_low( +/*=====================*/ + /* out: index */ + dict_tree_t* tree, /* in: index tree */ + rec_t* rec); /* in: record for which to find correct index */ +/************************************************************************** +Prints a table data. */ +static +void +dict_table_print_low( +/*=================*/ + dict_table_t* table); /* in: table */ +/************************************************************************** +Prints a column data. */ +static +void +dict_col_print_low( +/*===============*/ + dict_col_t* col); /* in: column */ +/************************************************************************** +Prints an index data. */ +static +void +dict_index_print_low( +/*=================*/ + dict_index_t* index); /* in: index */ +/************************************************************************** +Prints a field data. */ +static +void +dict_field_print_low( +/*=================*/ + dict_field_t* field); /* in: field */ + +/************************************************************************ +Reserves the dictionary system mutex for MySQL. */ + +void +dict_mutex_enter_for_mysql(void) +/*============================*/ +{ + mutex_enter(&(dict_sys->mutex)); +} + +/************************************************************************ +Releases the dictionary system mutex for MySQL. */ + +void +dict_mutex_exit_for_mysql(void) +/*===========================*/ +{ + mutex_exit(&(dict_sys->mutex)); +} + +/************************************************************************ +Gets the nth column of a table. */ + +dict_col_t* +dict_table_get_nth_col_noninline( +/*=============================*/ + /* out: pointer to column object */ + dict_table_t* table, /* in: table */ + ulint pos) /* in: position of column */ +{ + return(dict_table_get_nth_col(table, pos)); +} + +/************************************************************************ +Gets the first index on the table (the clustered index). */ + +dict_index_t* +dict_table_get_first_index_noninline( +/*=================================*/ + /* out: index, NULL if none exists */ + dict_table_t* table) /* in: table */ +{ + return(dict_table_get_first_index(table)); +} + +/************************************************************************ +Gets the next index on the table. */ + +dict_index_t* +dict_table_get_next_index_noninline( +/*================================*/ + /* out: index, NULL if none left */ + dict_index_t* index) /* in: index */ +{ + return(dict_table_get_next_index(index)); +} + +/************************************************************************** +Returns an index object. */ + +dict_index_t* +dict_table_get_index_noninline( +/*===========================*/ + /* out: index, NULL if does not exist */ + dict_table_t* table, /* in: table */ + char* name) /* in: index name */ +{ + return(dict_table_get_index(table, name)); +} + +/************************************************************************ +Looks for column n in an index. */ + +ulint +dict_index_get_nth_col_pos( +/*=======================*/ + /* out: position in internal representation + of the index; if not contained, returns + ULINT_UNDEFINED */ + dict_index_t* index, /* in: index */ + ulint n) /* in: column number */ +{ + dict_field_t* field; + dict_col_t* col; + ulint pos; + ulint n_fields; + + ut_ad(index); + ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); + + if (index->type & DICT_CLUSTERED) { + col = dict_table_get_nth_col(index->table, n); + + return(col->clust_pos); + } + + n_fields = dict_index_get_n_fields(index); + + for (pos = 0; pos < n_fields; pos++) { + field = dict_index_get_nth_field(index, pos); + col = field->col; + + if (dict_col_get_no(col) == n) { + + return(pos); + } + } + + return(ULINT_UNDEFINED); +} + +/************************************************************************** +Returns a table object, based on table id, and memoryfixes it. */ + +dict_table_t* +dict_table_get_on_id( +/*=================*/ + /* out: table, NULL if does not exist */ + dulint table_id, /* in: table id */ + trx_t* trx) /* in: transaction handle */ +{ + dict_table_t* table; + + if (ut_dulint_cmp(table_id, DICT_FIELDS_ID) <= 0) { + /* It is a system table which will always exist in the table + cache: we avoid acquiring the dictionary mutex, because + if we are doing a rollback to handle an error in TABLE + CREATE, for example, we already have the mutex! */ + + ut_ad(mutex_own(&(dict_sys->mutex))); + + return(dict_table_get_on_id_low(table_id, trx)); + } + + mutex_enter(&(dict_sys->mutex)); + + table = dict_table_get_on_id_low(table_id, trx); + + mutex_exit(&(dict_sys->mutex)); + + return(table); +} + +/************************************************************************ +Looks for column n postion in the clustered index. */ + +ulint +dict_table_get_nth_col_pos( +/*=======================*/ + /* out: position in internal representation + of the clustered index */ + dict_table_t* table, /* in: table */ + ulint n) /* in: column number */ +{ + return(dict_index_get_nth_col_pos(dict_table_get_first_index(table), + n)); +} + +/************************************************************************** +Inits the data dictionary module. */ + +void +dict_init(void) +/*===========*/ +{ + dict_sys = mem_alloc(sizeof(dict_sys_t)); + + mutex_create(&(dict_sys->mutex)); + mutex_set_level(&(dict_sys->mutex), SYNC_DICT); + + dict_sys->table_hash = hash_create(buf_pool_get_max_size() / + (DICT_POOL_PER_TABLE_HASH * + UNIV_WORD_SIZE)); + dict_sys->table_id_hash = hash_create(buf_pool_get_max_size() / + (DICT_POOL_PER_TABLE_HASH * + UNIV_WORD_SIZE)); + dict_sys->col_hash = hash_create(buf_pool_get_max_size() / + (DICT_POOL_PER_COL_HASH * + UNIV_WORD_SIZE)); + dict_sys->procedure_hash = hash_create(buf_pool_get_max_size() / + (DICT_POOL_PER_PROCEDURE_HASH * + UNIV_WORD_SIZE)); + dict_sys->size = 0; + + UT_LIST_INIT(dict_sys->table_LRU); +} + +/************************************************************************** +Returns a table object and memoryfixes it. NOTE! This is a high-level +function to be used mainly from outside the 'dict' directory. Inside this +directory dict_table_get_low is usually the appropriate function. */ + +dict_table_t* +dict_table_get( +/*===========*/ + /* out: table, NULL if does not exist */ + char* table_name, /* in: table name */ + trx_t* trx) /* in: transaction handle or NULL */ +{ + dict_table_t* table; + + UT_NOT_USED(trx); + + mutex_enter(&(dict_sys->mutex)); + + table = dict_table_get_low(table_name); + + mutex_exit(&(dict_sys->mutex)); + + if (table != NULL) { + if (table->stat_last_estimate_counter == (ulint)(-1)) { + dict_update_statistics(table); + } + } + + return(table); +} + +/************************************************************************** +Adds a table object to the dictionary cache. */ + +void +dict_table_add_to_cache( +/*====================*/ + dict_table_t* table) /* in: table */ +{ + ulint fold; + ulint id_fold; + ulint i; + + ut_ad(table); + ut_ad(mutex_own(&(dict_sys->mutex))); + ut_ad(table->n_def == table->n_cols - DATA_N_SYS_COLS); + ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); + ut_ad(table->cached == FALSE); + + fold = ut_fold_string(table->name); + id_fold = ut_fold_dulint(table->id); + + table->cached = TRUE; + + /* NOTE: the system columns MUST be added in the following order + (so that they can be indexed by the numerical value of DATA_ROW_ID, + etc.) and as the last columns of the table memory object. + The clustered index will not always physically contain all + system columns. */ + + dict_mem_table_add_col(table, "DB_ROW_ID", DATA_SYS, DATA_ROW_ID, 0, 0); + ut_ad(DATA_ROW_ID == 0); + dict_mem_table_add_col(table, "DB_TRX_ID", DATA_SYS, DATA_TRX_ID, 0, 0); + ut_ad(DATA_TRX_ID == 1); + dict_mem_table_add_col(table, "DB_ROLL_PTR", DATA_SYS, DATA_ROLL_PTR, + 0, 0); + ut_ad(DATA_ROLL_PTR == 2); + + dict_mem_table_add_col(table, "DB_MIX_ID", DATA_SYS, DATA_MIX_ID, 0, 0); + ut_ad(DATA_MIX_ID == 3); + ut_ad(DATA_N_SYS_COLS == 4); /* This assert reminds that if a new + system column is added to the program, + it should be dealt with here */ + + /* Look for a table with the same name: error if such exists */ + { + dict_table_t* table2; + HASH_SEARCH(name_hash, dict_sys->table_hash, fold, table2, + (ut_strcmp(table2->name, table->name) == 0)); + ut_a(table2 == NULL); + } + + /* Look for a table with the same id: error if such exists */ + { + dict_table_t* table2; + HASH_SEARCH(id_hash, dict_sys->table_id_hash, id_fold, table2, + (ut_dulint_cmp(table2->id, table->id) == 0)); + ut_a(table2 == NULL); + } + + if (table->type == DICT_TABLE_CLUSTER_MEMBER) { + + table->mix_id_len = mach_dulint_get_compressed_size( + table->mix_id); + mach_dulint_write_compressed(table->mix_id_buf, table->mix_id); + } + + /* Add the columns to the column hash table */ + for (i = 0; i < table->n_cols; i++) { + dict_col_add_to_cache(table, dict_table_get_nth_col(table, i)); + } + + /* Add table to hash table of tables */ + HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold, table); + + /* Add table to hash table of tables based on table id */ + HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash, id_fold, + table); + /* Add table to LRU list of tables */ + UT_LIST_ADD_FIRST(table_LRU, dict_sys->table_LRU, table); + + /* If the dictionary cache grows too big, trim the table LRU list */ + + dict_sys->size += mem_heap_get_size(table->heap); + /* dict_table_LRU_trim(); */ +} + +/************************************************************************** +Renames a table object. */ + +ibool +dict_table_rename_in_cache( +/*=======================*/ + /* out: TRUE if success */ + dict_table_t* table, /* in: table */ + char* new_name) /* in: new name */ +{ + ulint fold; + ulint old_size; + char* name_buf; + ulint i; + + ut_ad(table); + ut_ad(mutex_own(&(dict_sys->mutex))); + + old_size = mem_heap_get_size(table->heap); + + fold = ut_fold_string(new_name); + + /* Look for a table with the same name: error if such exists */ + { + dict_table_t* table2; + HASH_SEARCH(name_hash, dict_sys->table_hash, fold, table2, + (ut_strcmp(table2->name, new_name) == 0)); + if (table2) { + return(FALSE); + } + } + + /* Reposition the columns in the column hash table; they are hashed + according to the pair (table name, column name) */ + + for (i = 0; i < table->n_cols; i++) { + dict_col_reposition_in_cache(table, + dict_table_get_nth_col(table, i), new_name); + } + + /* Remove table from the hash tables of tables */ + HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash, + ut_fold_string(table->name), table); + + name_buf = mem_heap_alloc(table->heap, ut_strlen(new_name) + 1); + + ut_memcpy(name_buf, new_name, ut_strlen(new_name) + 1); + + table->name = name_buf; + + /* Add table to hash table of tables */ + HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold, table); + + dict_sys->size += (mem_heap_get_size(table->heap) - old_size); + + return(TRUE); +} + +/************************************************************************** +Removes a table object from the dictionary cache. */ + +void +dict_table_remove_from_cache( +/*=========================*/ + dict_table_t* table) /* in, own: table */ +{ + dict_index_t* index; + ulint size; + ulint i; + + ut_ad(table); + ut_ad(mutex_own(&(dict_sys->mutex))); + ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); + + /* printf("Removing table %s from dictionary cache\n", table->name); */ + + /* Remove the indexes from the cache */ + index = UT_LIST_GET_LAST(table->indexes); + + while (index != NULL) { + dict_index_remove_from_cache(table, index); + index = UT_LIST_GET_LAST(table->indexes); + } + + /* Remove the columns of the table from the cache */ + for (i = 0; i < table->n_cols; i++) { + dict_col_remove_from_cache(table, + dict_table_get_nth_col(table, i)); + } + + /* Remove table from the hash tables of tables */ + HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash, + ut_fold_string(table->name), table); + HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash, + ut_fold_dulint(table->id), table); + + /* Remove table from LRU list of tables */ + UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table); + + size = mem_heap_get_size(table->heap); + + ut_ad(dict_sys->size >= size); + + dict_sys->size -= size; + + mem_heap_free(table->heap); +} + +/************************************************************************** +Frees tables from the end of table_LRU if the dictionary cache occupies +too much space. Currently not used! */ +static +void +dict_table_LRU_trim(void) +/*=====================*/ +{ + dict_table_t* table; + dict_table_t* prev_table; + + ut_a(0); + + ut_ad(mutex_own(&(dict_sys->mutex))); + + table = UT_LIST_GET_LAST(dict_sys->table_LRU); + + while (table && (dict_sys->size > + buf_pool_get_max_size() / DICT_POOL_PER_VARYING)) { + + prev_table = UT_LIST_GET_PREV(table_LRU, table); + + if (table->mem_fix == 0) { + dict_table_remove_from_cache(table); + } + + table = prev_table; + } +} + +/************************************************************************** +Adds a column to the data dictionary hash table. */ +static +void +dict_col_add_to_cache( +/*==================*/ + dict_table_t* table, /* in: table */ + dict_col_t* col) /* in: column */ +{ + ulint fold; + + ut_ad(table && col); + ut_ad(mutex_own(&(dict_sys->mutex))); + ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); + + fold = ut_fold_ulint_pair(ut_fold_string(table->name), + ut_fold_string(col->name)); + + /* Look for a column with same table name and column name: error */ + { + dict_col_t* col2; + HASH_SEARCH(hash, dict_sys->col_hash, fold, col2, + (ut_strcmp(col->name, col2->name) == 0) + && (ut_strcmp((col2->table)->name, table->name) + == 0)); + ut_a(col2 == NULL); + } + + HASH_INSERT(dict_col_t, hash, dict_sys->col_hash, fold, col); +} + +/************************************************************************** +Removes a column from the data dictionary hash table. */ +static +void +dict_col_remove_from_cache( +/*=======================*/ + dict_table_t* table, /* in: table */ + dict_col_t* col) /* in: column */ +{ + ulint fold; + + ut_ad(table && col); + ut_ad(mutex_own(&(dict_sys->mutex))); + ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); + + fold = ut_fold_ulint_pair(ut_fold_string(table->name), + ut_fold_string(col->name)); + + HASH_DELETE(dict_col_t, hash, dict_sys->col_hash, fold, col); +} + +/************************************************************************** +Repositions a column in the data dictionary hash table when the table name +changes. */ +static +void +dict_col_reposition_in_cache( +/*=========================*/ + dict_table_t* table, /* in: table */ + dict_col_t* col, /* in: column */ + char* new_name) /* in: new table name */ +{ + ulint fold; + + ut_ad(table && col); + ut_ad(mutex_own(&(dict_sys->mutex))); + ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); + + fold = ut_fold_ulint_pair(ut_fold_string(table->name), + ut_fold_string(col->name)); + + HASH_DELETE(dict_col_t, hash, dict_sys->col_hash, fold, col); + + fold = ut_fold_ulint_pair(ut_fold_string(new_name), + ut_fold_string(col->name)); + + HASH_INSERT(dict_col_t, hash, dict_sys->col_hash, fold, col); +} + +/************************************************************************** +Adds an index to the dictionary cache. */ + +ibool +dict_index_add_to_cache( +/*====================*/ + /* out: TRUE if success */ + dict_table_t* table, /* in: table on which the index is */ + dict_index_t* index) /* in, own: index; NOTE! The index memory + object is freed in this function! */ +{ + dict_index_t* new_index; + dict_tree_t* tree; + dict_table_t* cluster; + dict_field_t* field; + ulint n_ord; + ibool success; + ulint i; + + ut_ad(index); + ut_ad(mutex_own(&(dict_sys->mutex))); + ut_ad(index->n_def == index->n_fields); + ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); + + ut_ad(mem_heap_validate(index->heap)); + + { + dict_index_t* index2; + index2 = UT_LIST_GET_FIRST(table->indexes); + + while (index2 != NULL) { + ut_ad(ut_strcmp(index->name, index2->name) != 0); + + index2 = UT_LIST_GET_NEXT(indexes, index2); + } + + ut_a(UT_LIST_GET_LEN(table->indexes) == 0 + || (index->type & DICT_CLUSTERED) == 0); + } + + success = dict_index_find_cols(table, index); + + if (!success) { + dict_mem_index_free(index); + + return(FALSE); + } + + /* Build the cache internal representation of the index, + containing also the added system fields */ + + if (index->type & DICT_CLUSTERED) { + new_index = dict_index_build_internal_clust(table, index); + } else { + new_index = dict_index_build_internal_non_clust(table, index); + } + + new_index->search_info = btr_search_info_create(new_index->heap); + + /* Set the n_fields value in new_index to the actual defined + number of fields in the cache internal representation */ + + new_index->n_fields = new_index->n_def; + + /* Add the new index as the last index for the table */ + + UT_LIST_ADD_LAST(indexes, table->indexes, new_index); + new_index->table = table; + new_index->table_name = table->name; + + /* Increment the ord_part counts in columns which are ordering */ + + if (index->type & DICT_UNIVERSAL) { + n_ord = new_index->n_fields; + } else { + n_ord = dict_index_get_n_unique(new_index); + } + + for (i = 0; i < n_ord; i++) { + + field = dict_index_get_nth_field(new_index, i); + + dict_field_get_col(field)->ord_part++; + } + + if (table->type == DICT_TABLE_CLUSTER_MEMBER) { + /* The index tree is found from the cluster object */ + + cluster = dict_table_get_low(table->cluster_name); + + tree = dict_index_get_tree(UT_LIST_GET_FIRST(cluster->indexes)); + + new_index->tree = tree; + new_index->page_no = tree->page; + } else { + /* Create an index tree memory object for the index */ + tree = dict_tree_create(new_index); + ut_ad(tree); + + new_index->tree = tree; + } + + /* Add the index to the list of indexes stored in the tree */ + UT_LIST_ADD_LAST(tree_indexes, tree->tree_indexes, new_index); + + /* If the dictionary cache grows too big, trim the table LRU list */ + + dict_sys->size += mem_heap_get_size(new_index->heap); + /* dict_table_LRU_trim(); */ + + dict_mem_index_free(index); + + return(TRUE); +} + +/************************************************************************** +Removes an index from the dictionary cache. */ +static +void +dict_index_remove_from_cache( +/*=========================*/ + dict_table_t* table, /* in: table */ + dict_index_t* index) /* in, own: index */ +{ + dict_field_t* field; + ulint size; + ulint i; + + ut_ad(table && index); + ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); + ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); + ut_ad(mutex_own(&(dict_sys->mutex))); + + ut_ad(UT_LIST_GET_LEN((index->tree)->tree_indexes) == 1); + dict_tree_free(index->tree); + + /* Decrement the ord_part counts in columns which are ordering */ + for (i = 0; i < dict_index_get_n_unique(index); i++) { + + field = dict_index_get_nth_field(index, i); + + ut_ad(dict_field_get_col(field)->ord_part > 0); + (dict_field_get_col(field)->ord_part)--; + } + + /* Remove the index from the list of indexes of the table */ + UT_LIST_REMOVE(indexes, table->indexes, index); + + size = mem_heap_get_size(index->heap); + + ut_ad(dict_sys->size >= size); + + dict_sys->size -= size; + + mem_heap_free(index->heap); +} + +/*********************************************************************** +Tries to find column names for the index in the column hash table and +sets the col field of the index. */ +static +ibool +dict_index_find_cols( +/*=================*/ + /* out: TRUE if success */ + dict_table_t* table, /* in: table */ + dict_index_t* index) /* in: index */ +{ + dict_col_t* col; + dict_field_t* field; + ulint fold; + ulint i; + + ut_ad(table && index); + ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); + ut_ad(mutex_own(&(dict_sys->mutex))); + + for (i = 0; i < index->n_fields; i++) { + field = dict_index_get_nth_field(index, i); + + fold = ut_fold_ulint_pair(ut_fold_string(table->name), + ut_fold_string(field->name)); + + HASH_SEARCH(hash, dict_sys->col_hash, fold, col, + (ut_strcmp(col->name, field->name) == 0) + && (ut_strcmp((col->table)->name, table->name) + == 0)); + if (col == NULL) { + + return(FALSE); + } else { + field->col = col; + } + } + + return(TRUE); +} + +/*********************************************************************** +Adds a column to index. */ +UNIV_INLINE +void +dict_index_add_col( +/*===============*/ + dict_index_t* index, /* in: index */ + dict_col_t* col, /* in: column */ + ulint order) /* in: order criterion */ +{ + dict_field_t* field; + + dict_mem_index_add_field(index, col->name, order); + + field = dict_index_get_nth_field(index, index->n_def - 1); + + field->col = col; +} + +/*********************************************************************** +Copies fields contained in index2 to index1. */ +static +void +dict_index_copy( +/*============*/ + dict_index_t* index1, /* in: index to copy to */ + dict_index_t* index2, /* in: index to copy from */ + ulint start, /* in: first position to copy */ + ulint end) /* in: last position to copy */ +{ + dict_field_t* field; + ulint i; + + /* Copy fields contained in index2 */ + + for (i = start; i < end; i++) { + + field = dict_index_get_nth_field(index2, i); + dict_index_add_col(index1, field->col, field->order); + } +} + +/*********************************************************************** +Copies types of fields contained in index to tuple. */ + +void +dict_index_copy_types( +/*==================*/ + dtuple_t* tuple, /* in: data tuple */ + dict_index_t* index, /* in: index */ + ulint n_fields) /* in: number of field types to copy */ +{ + dtype_t* dfield_type; + dtype_t* type; + ulint i; + + if (index->type & DICT_UNIVERSAL) { + dtuple_set_types_binary(tuple, n_fields); + + return; + } + + for (i = 0; i < n_fields; i++) { + dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i)); + type = dict_col_get_type(dict_field_get_col( + dict_index_get_nth_field(index, i))); + *dfield_type = *type; + } +} + +/*********************************************************************** +Copies types of columns contained in table to tuple. */ + +void +dict_table_copy_types( +/*==================*/ + dtuple_t* tuple, /* in: data tuple */ + dict_table_t* table) /* in: index */ +{ + dtype_t* dfield_type; + dtype_t* type; + ulint i; + + ut_ad(!(table->type & DICT_UNIVERSAL)); + + for (i = 0; i < dtuple_get_n_fields(tuple); i++) { + + dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i)); + type = dict_col_get_type(dict_table_get_nth_col(table, i)); + + *dfield_type = *type; + } +} + +/*********************************************************************** +Builds the internal dictionary cache representation for a clustered +index, containing also system fields not defined by the user. */ +static +dict_index_t* +dict_index_build_internal_clust( +/*============================*/ + /* out, own: the internal representation + of the clustered index */ + dict_table_t* table, /* in: table */ + dict_index_t* index) /* in: user representation of a clustered + index */ +{ + dict_index_t* new_index; + dict_field_t* field; + dict_col_t* col; + ulint fixed_size; + ulint trx_id_pos; + ulint i; + + ut_ad(table && index); + ut_ad(index->type & DICT_CLUSTERED); + ut_ad(mutex_own(&(dict_sys->mutex))); + ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); + + /* Create a new index object with certainly enough fields */ + new_index = dict_mem_index_create(table->name, + index->name, + table->space, + index->type, + index->n_fields + table->n_cols); + + /* Copy other relevant data from the old index struct to the new + struct: it inherits the values */ + + new_index->n_user_defined_cols = index->n_fields; + + new_index->id = index->id; + new_index->page_no = index->page_no; + + if (table->type != DICT_TABLE_ORDINARY) { + /* The index is mixed: copy common key prefix fields */ + + dict_index_copy(new_index, index, 0, table->mix_len); + + /* Add the mix id column */ + dict_index_add_col(new_index, + dict_table_get_sys_col(table, DATA_MIX_ID), 0); + + /* Copy the rest of fields */ + dict_index_copy(new_index, index, table->mix_len, + index->n_fields); + } else { + /* Copy the fields of index */ + dict_index_copy(new_index, index, 0, index->n_fields); + } + + if (index->type & DICT_UNIVERSAL) { + /* No fixed number of fields determines an entry uniquely */ + + new_index->n_uniq = ULINT_MAX; + + } else if (index->type & DICT_UNIQUE) { + /* Only the fields defined so far are needed to identify + the index entry uniquely */ + + new_index->n_uniq = new_index->n_def; + } else { + /* Also the row id is needed to identify the entry */ + new_index->n_uniq = 1 + new_index->n_def; + } + + new_index->trx_id_offset = 0; + + if (!(index->type & DICT_IBUF)) { + /* Add system columns, trx id first */ + + trx_id_pos = new_index->n_def; + + ut_ad(DATA_ROW_ID == 0); + ut_ad(DATA_TRX_ID == 1); + ut_ad(DATA_ROLL_PTR == 2); + + if (!(index->type & DICT_UNIQUE)) { + dict_index_add_col(new_index, + dict_table_get_sys_col(table, DATA_ROW_ID), 0); + trx_id_pos++; + } + + dict_index_add_col(new_index, + dict_table_get_sys_col(table, DATA_TRX_ID), 0); + dict_index_add_col(new_index, + dict_table_get_sys_col(table, DATA_ROLL_PTR), 0); + + for (i = 0; i < trx_id_pos; i++) { + + fixed_size = dtype_get_fixed_size( + dict_index_get_nth_type(new_index, i)); + + if (fixed_size == 0) { + new_index->trx_id_offset = 0; + + break; + } + + new_index->trx_id_offset += fixed_size; + } + + } + + /* Set auxiliary variables in table columns as undefined */ + for (i = 0; i < table->n_cols; i++) { + + col = dict_table_get_nth_col(table, i); + col->aux = ULINT_UNDEFINED; + } + + /* Mark with 0 the table columns already contained in new_index */ + for (i = 0; i < new_index->n_def; i++) { + + field = dict_index_get_nth_field(new_index, i); + (field->col)->aux = 0; + } + + /* Add to new_index non-system columns of table not yet included + there */ + for (i = 0; i < table->n_cols - DATA_N_SYS_COLS; i++) { + + col = dict_table_get_nth_col(table, i); + ut_ad(col->type.mtype != DATA_SYS); + + if (col->aux == ULINT_UNDEFINED) { + dict_index_add_col(new_index, col, 0); + } + } + + ut_ad((index->type & DICT_IBUF) + || (UT_LIST_GET_LEN(table->indexes) == 0)); + + /* Store to the column structs the position of the table columns + in the clustered index */ + + for (i = 0; i < new_index->n_def; i++) { + field = dict_index_get_nth_field(new_index, i); + (field->col)->clust_pos = i; + } + + new_index->cached = TRUE; + + return(new_index); +} + +/*********************************************************************** +Builds the internal dictionary cache representation for a non-clustered +index, containing also system fields not defined by the user. */ +static +dict_index_t* +dict_index_build_internal_non_clust( +/*================================*/ + /* out, own: the internal representation + of the non-clustered index */ + dict_table_t* table, /* in: table */ + dict_index_t* index) /* in: user representation of a non-clustered + index */ +{ + dict_field_t* field; + dict_index_t* new_index; + dict_index_t* clust_index; + ulint i; + + ut_ad(table && index); + ut_ad(0 == (index->type & DICT_CLUSTERED)); + ut_ad(mutex_own(&(dict_sys->mutex))); + ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); + + /* The clustered index should be the first in the list of indexes */ + clust_index = UT_LIST_GET_FIRST(table->indexes); + + ut_ad(clust_index); + ut_ad(clust_index->type & DICT_CLUSTERED); + ut_ad(!(clust_index->type & DICT_UNIVERSAL)); + + /* Create a new index */ + new_index = dict_mem_index_create(table->name, + index->name, + index->space, + index->type, + index->n_fields + + 1 + clust_index->n_uniq); + + /* Copy other relevant data from the old index + struct to the new struct: it inherits the values */ + + new_index->n_user_defined_cols = index->n_fields; + + new_index->id = index->id; + new_index->page_no = index->page_no; + + /* Copy fields from index to new_index */ + dict_index_copy(new_index, index, 0, index->n_fields); + + /* Set the auxiliary variables in the clust_index unique columns + as undefined */ + for (i = 0; i < clust_index->n_uniq; i++) { + + field = dict_index_get_nth_field(clust_index, i); + (field->col)->aux = ULINT_UNDEFINED; + } + + /* Mark with 0 table columns already contained in new_index */ + for (i = 0; i < new_index->n_def; i++) { + + field = dict_index_get_nth_field(new_index, i); + (field->col)->aux = 0; + } + + /* Add to new_index columns necessary to determine the clustered + index entry uniquely */ + + for (i = 0; i < clust_index->n_uniq; i++) { + + field = dict_index_get_nth_field(clust_index, i); + + if ((field->col)->aux == ULINT_UNDEFINED) { + dict_index_add_col(new_index, field->col, 0); + } + } + + if ((index->type) & DICT_UNIQUE) { + new_index->n_uniq = index->n_fields; + } else { + new_index->n_uniq = new_index->n_def; + } + + /* Set the n_fields value in new_index to the actual defined + number of fields */ + + new_index->n_fields = new_index->n_def; + + new_index->cached = TRUE; + + return(new_index); +} + +/************************************************************************** +Adds a stored procedure object to the dictionary cache. */ + +void +dict_procedure_add_to_cache( +/*========================*/ + dict_proc_t* proc) /* in: procedure */ +{ + ulint fold; + + mutex_enter(&(dict_sys->mutex)); + + fold = ut_fold_string(proc->name); + + /* Look for a procedure with the same name: error if such exists */ + { + dict_proc_t* proc2; + + HASH_SEARCH(name_hash, dict_sys->procedure_hash, fold, proc2, + (ut_strcmp(proc2->name, proc->name) == 0)); + ut_a(proc2 == NULL); + } + + /* Add the procedure to the hash table */ + + HASH_INSERT(dict_proc_t, name_hash, dict_sys->procedure_hash, fold, + proc); + mutex_exit(&(dict_sys->mutex)); +} + +/************************************************************************** +Reserves a parsed copy of a stored procedure to execute. If there are no +free parsed copies left at the moment, parses a new copy. Takes the copy off +the list of copies: the copy must be returned there with +dict_procedure_release_parsed_copy. */ + +que_t* +dict_procedure_reserve_parsed_copy( +/*===============================*/ + /* out: the query graph */ + dict_proc_t* proc) /* in: dictionary procedure node */ +{ + que_t* graph; + proc_node_t* proc_node; + + ut_ad(!mutex_own(&kernel_mutex)); + + mutex_enter(&(dict_sys->mutex)); + +#ifdef UNIV_DEBUG + UT_LIST_VALIDATE(graphs, que_t, proc->graphs); +#endif + graph = UT_LIST_GET_FIRST(proc->graphs); + + if (graph) { + UT_LIST_REMOVE(graphs, proc->graphs, graph); + +/* printf("Graph removed, list length %lu\n", + UT_LIST_GET_LEN(proc->graphs)); */ +#ifdef UNIV_DEBUG + UT_LIST_VALIDATE(graphs, que_t, proc->graphs); +#endif + } + + mutex_exit(&(dict_sys->mutex)); + + if (graph == NULL) { + graph = pars_sql(proc->sql_string); + + proc_node = que_fork_get_child(graph); + + proc_node->dict_proc = proc; + + printf("Parsed a new copy of graph %s\n", + proc_node->proc_id->name); + } + +/* printf("Returning graph %lu\n", (ulint)graph); */ + + return(graph); +} + +/************************************************************************** +Releases a parsed copy of an executed stored procedure. Puts the copy to the +list of copies. */ + +void +dict_procedure_release_parsed_copy( +/*===============================*/ + que_t* graph) /* in: query graph of a stored procedure */ +{ + proc_node_t* proc_node; + + ut_ad(!mutex_own(&kernel_mutex)); + + mutex_enter(&(dict_sys->mutex)); + + proc_node = que_fork_get_child(graph); + + UT_LIST_ADD_FIRST(graphs, (proc_node->dict_proc)->graphs, graph); + + mutex_exit(&(dict_sys->mutex)); +} + +/************************************************************************** +Returns an index object if it is found in the dictionary cache. */ + +dict_index_t* +dict_index_get_if_in_cache( +/*=======================*/ + /* out: index, NULL if not found */ + dulint index_id) /* in: index id */ +{ + dict_table_t* table; + dict_index_t* index; + + if (dict_sys == NULL) { + return(NULL); + } + + mutex_enter(&(dict_sys->mutex)); + + table = UT_LIST_GET_FIRST(dict_sys->table_LRU); + + while (table) { + index = UT_LIST_GET_FIRST(table->indexes); + + while (index) { + if (0 == ut_dulint_cmp(index->id, index_id)) { + + goto found; + } + + index = UT_LIST_GET_NEXT(indexes, index); + } + + table = UT_LIST_GET_NEXT(table_LRU, table); + } + + index = NULL; +found: + mutex_exit(&(dict_sys->mutex)); + + return(index); +} + +/************************************************************************** +Creates an index tree struct. */ + +dict_tree_t* +dict_tree_create( +/*=============*/ + /* out, own: created tree */ + dict_index_t* index) /* in: the index for which to create: in the + case of a mixed tree, this should be the + index of the cluster object */ +{ + dict_tree_t* tree; + + tree = mem_alloc(sizeof(dict_tree_t)); + + /* Inherit info from the index */ + + tree->type = index->type; + tree->space = index->space; + tree->page = index->page_no; + + tree->id = index->id; + + UT_LIST_INIT(tree->tree_indexes); + + tree->magic_n = DICT_TREE_MAGIC_N; + + rw_lock_create(&(tree->lock)); + + rw_lock_set_level(&(tree->lock), SYNC_INDEX_TREE); + + return(tree); +} + +/************************************************************************** +Frees an index tree struct. */ + +void +dict_tree_free( +/*===========*/ + dict_tree_t* tree) /* in, own: index tree */ +{ + ut_ad(tree); + ut_ad(tree->magic_n == DICT_TREE_MAGIC_N); + + rw_lock_free(&(tree->lock)); + mem_free(tree); +} + +/************************************************************************** +In an index tree, finds the index corresponding to a record in the tree. */ +UNIV_INLINE +dict_index_t* +dict_tree_find_index_low( +/*=====================*/ + /* out: index */ + dict_tree_t* tree, /* in: index tree */ + rec_t* rec) /* in: record for which to find correct index */ +{ + dict_index_t* index; + dict_table_t* table; + dulint mix_id; + ulint len; + + index = UT_LIST_GET_FIRST(tree->tree_indexes); + ut_ad(index); + table = index->table; + + if ((index->type & DICT_CLUSTERED) + && (table->type != DICT_TABLE_ORDINARY)) { + + /* Get the mix id of the record */ + + mix_id = mach_dulint_read_compressed( + rec_get_nth_field(rec, table->mix_len, &len)); + + while (ut_dulint_cmp(table->mix_id, mix_id) != 0) { + + index = UT_LIST_GET_NEXT(tree_indexes, index); + table = index->table; + ut_ad(index); + } + } + + return(index); +} + +/************************************************************************** +In an index tree, finds the index corresponding to a record in the tree. */ + +dict_index_t* +dict_tree_find_index( +/*=================*/ + /* out: index */ + dict_tree_t* tree, /* in: index tree */ + rec_t* rec) /* in: record for which to find correct index */ +{ + dict_index_t* index; + + index = dict_tree_find_index_low(tree, rec); + + return(index); +} + +/************************************************************************** +In an index tree, finds the index corresponding to a dtuple which is used +in a search to a tree. */ + +dict_index_t* +dict_tree_find_index_for_tuple( +/*===========================*/ + /* out: index; NULL if the tuple does not + contain the mix id field in a mixed tree */ + dict_tree_t* tree, /* in: index tree */ + dtuple_t* tuple) /* in: tuple for which to find index */ +{ + dict_index_t* index; + dict_table_t* table; + dulint mix_id; + + ut_ad(dtuple_check_typed(tuple)); + + if (UT_LIST_GET_LEN(tree->tree_indexes) == 1) { + + return(UT_LIST_GET_FIRST(tree->tree_indexes)); + } + + index = UT_LIST_GET_FIRST(tree->tree_indexes); + ut_ad(index); + table = index->table; + + if (dtuple_get_n_fields(tuple) <= table->mix_len) { + + return(NULL); + } + + /* Get the mix id of the record */ + + mix_id = mach_dulint_read_compressed( + dfield_get_data( + dtuple_get_nth_field(tuple, table->mix_len))); + + while (ut_dulint_cmp(table->mix_id, mix_id) != 0) { + + index = UT_LIST_GET_NEXT(tree_indexes, index); + table = index->table; + ut_ad(index); + } + + return(index); +} + +/************************************************************************** +Checks that a tuple has n_fields_cmp value in a sensible range, so that +no comparison can occur with the page number field in a node pointer. */ + +ibool +dict_tree_check_search_tuple( +/*=========================*/ + /* out: TRUE if ok */ + dict_tree_t* tree, /* in: index tree */ + dtuple_t* tuple) /* in: tuple used in a search */ +{ + dict_index_t* index; + + index = dict_tree_find_index_for_tuple(tree, tuple); + + if (index == NULL) { + + return(TRUE); + } + + ut_a(dtuple_get_n_fields_cmp(tuple) + <= dict_index_get_n_unique_in_tree(index)); + return(TRUE); +} + +/************************************************************************** +Builds a node pointer out of a physical record and a page number. */ + +dtuple_t* +dict_tree_build_node_ptr( +/*=====================*/ + /* out, own: node pointer */ + dict_tree_t* tree, /* in: index tree */ + rec_t* rec, /* in: record for which to build node pointer */ + ulint page_no,/* in: page number to put in node pointer */ + mem_heap_t* heap) /* in: memory heap where pointer created */ +{ + dtuple_t* tuple; + dict_index_t* ind; + dfield_t* field; + byte* buf; + ulint n_unique; + + ind = dict_tree_find_index_low(tree, rec); + + if (tree->type & DICT_UNIVERSAL) { + /* In a universal index tree, we take the whole record as + the node pointer */ + + n_unique = rec_get_n_fields(rec); + } else { + n_unique = dict_index_get_n_unique_in_tree(ind); + } + + tuple = dtuple_create(heap, n_unique + 1); + + /* When searching in the tree for the node pointer, we must not do + comparison on the last field, the page number field, as on upper + levels in the tree there may be identical node pointers with a + different page number; therefore, we set the n_fields_cmp to one + less: */ + + dtuple_set_n_fields_cmp(tuple, n_unique); + + dict_index_copy_types(tuple, ind, n_unique); + + buf = mem_heap_alloc(heap, 4); + + mach_write_to_4(buf, page_no); + + field = dtuple_get_nth_field(tuple, n_unique); + dfield_set_data(field, buf, 4); + + dtype_set(dfield_get_type(field), DATA_SYS_CHILD, 0, 0, 0); + + rec_copy_prefix_to_dtuple(tuple, rec, n_unique, heap); + + ut_ad(dtuple_check_typed(tuple)); + + return(tuple); +} + +/************************************************************************** +Copies an initial segment of a physical record, long enough to specify an +index entry uniquely. */ + +rec_t* +dict_tree_copy_rec_order_prefix( +/*============================*/ + /* out: pointer to the prefix record */ + dict_tree_t* tree, /* in: index tree */ + rec_t* rec, /* in: record for which to copy prefix */ + byte** buf, /* in/out: memory buffer for the copied prefix, + or NULL */ + ulint* buf_size)/* in/out: buffer size */ +{ + dict_index_t* ind; + rec_t* order_rec; + ulint n_fields; + + ind = dict_tree_find_index_low(tree, rec); + + n_fields = dict_index_get_n_unique_in_tree(ind); + + if (tree->type & DICT_UNIVERSAL) { + + n_fields = rec_get_n_fields(rec); + } + + order_rec = rec_copy_prefix_to_buf(rec, n_fields, buf, buf_size); + + return(order_rec); +} + +/************************************************************************** +Builds a typed data tuple out of a physical record. */ + +dtuple_t* +dict_tree_build_data_tuple( +/*=======================*/ + /* out, own: data tuple */ + dict_tree_t* tree, /* in: index tree */ + rec_t* rec, /* in: record for which to build data tuple */ + mem_heap_t* heap) /* in: memory heap where tuple created */ +{ + dtuple_t* tuple; + dict_index_t* ind; + ulint n_fields; + + ind = dict_tree_find_index_low(tree, rec); + + n_fields = rec_get_n_fields(rec); + + tuple = dtuple_create(heap, n_fields); + + dict_index_copy_types(tuple, ind, n_fields); + + rec_copy_prefix_to_dtuple(tuple, rec, n_fields, heap); + + ut_ad(dtuple_check_typed(tuple)); + + return(tuple); +} + +/************************************************************************* +Calculates new estimates for table and index statistics. The statistics +are used in query optimization. */ + +void +dict_update_statistics( +/*===================*/ + dict_table_t* table) /* in: table */ +{ + mem_heap_t* heap; + dict_index_t* index; + dtuple_t* start; + dtuple_t* end; + ulint n_rows; + ulint n_vals; + ulint size; + ulint sum_of_index_sizes = 0; + + /* Estimate the number of records in the clustered index */ + index = dict_table_get_first_index(table); + + heap = mem_heap_create(500); + + start = dtuple_create(heap, 0); + end = dtuple_create(heap, 0); + + n_rows = btr_estimate_n_rows_in_range(index, start, PAGE_CUR_G, + end, PAGE_CUR_L); + mem_heap_free(heap); + + if (n_rows > 0) { + /* For small tables our estimate function tends to give + values 1 too big */ + n_rows--; + } + + mutex_enter(&(dict_sys->mutex)); + + table->stat_last_estimate_counter = table->stat_modif_counter; + table->stat_n_rows = n_rows; + + mutex_exit(&(dict_sys->mutex)); + + /* Find out the sizes of the indexes and how many different values + for the key they approximately have */ + + while (index) { + n_vals = btr_estimate_number_of_different_key_vals(index); + size = btr_get_size(index, BTR_TOTAL_SIZE); + + sum_of_index_sizes += size; + + mutex_enter(&(dict_sys->mutex)); + + index->stat_n_diff_key_vals = n_vals; + index->stat_index_size = size; + + mutex_exit(&(dict_sys->mutex)); + + index = dict_table_get_next_index(index); + } + + index = dict_table_get_first_index(table); + + table->stat_clustered_index_size = index->stat_index_size; + + table->stat_sum_of_other_index_sizes = sum_of_index_sizes + - index->stat_index_size; + + table->stat_last_estimate_counter = table->stat_modif_counter; +} + +/************************************************************************** +Prints a table data. */ + +void +dict_table_print( +/*=============*/ + dict_table_t* table) /* in: table */ +{ + mutex_enter(&(dict_sys->mutex)); + dict_table_print_low(table); + mutex_exit(&(dict_sys->mutex)); +} + +/************************************************************************** +Prints a table data when we know the table name. */ + +void +dict_table_print_by_name( +/*=====================*/ + char* name) +{ + dict_table_t* table; + + mutex_enter(&(dict_sys->mutex)); + + table = dict_table_get_low(name); + + ut_a(table); + + dict_table_print_low(table); + mutex_exit(&(dict_sys->mutex)); +} + +/************************************************************************** +Prints a table data. */ +static +void +dict_table_print_low( +/*=================*/ + dict_table_t* table) /* in: table */ +{ + ulint i; + dict_index_t* index; + + ut_ad(mutex_own(&(dict_sys->mutex))); + + printf("--------------------------------------\n"); + printf("TABLE INFO: name %s, columns %lu, indexes %lu\n", table->name, + table->n_cols, UT_LIST_GET_LEN(table->indexes)); + for (i = 0; i < table->n_cols; i++) { + printf(" "); + dict_col_print_low(dict_table_get_nth_col(table, i)); + } + + index = UT_LIST_GET_FIRST(table->indexes); + + while (index != NULL) { + dict_index_print_low(index); + index = UT_LIST_GET_NEXT(indexes, index); + } +} + +/************************************************************************** +Prints a column data. */ +static +void +dict_col_print_low( +/*===============*/ + dict_col_t* col) /* in: column */ +{ + dtype_t* type; + + ut_ad(mutex_own(&(dict_sys->mutex))); + + type = dict_col_get_type(col); + printf("COLUMN: name %s; ", col->name); + + dtype_print(type); +} + +/************************************************************************** +Prints an index data. */ +static +void +dict_index_print_low( +/*=================*/ + dict_index_t* index) /* in: index */ +{ + ulint i; + dict_tree_t* tree; + + ut_ad(mutex_own(&(dict_sys->mutex))); + + tree = index->tree; + + printf( + "INDEX INFO: name %s, table name %s, fields %lu, type %lu\n", + index->name, index->table_name, index->n_fields, + index->type); + printf(" root node: space %lu, page number %lu\n", + tree->space, tree->page); + + for (i = 0; i < index->n_fields; i++) { + printf(" "); + dict_field_print_low(dict_index_get_nth_field(index, i)); + } + + btr_print_size(tree); + + btr_print_tree(tree, 7); +} + +/************************************************************************** +Prints a field data. */ +static +void +dict_field_print_low( +/*=================*/ + dict_field_t* field) /* in: field */ +{ + ut_ad(mutex_own(&(dict_sys->mutex))); + + printf("FIELD: column name %s, order criterion %lu\n", field->name, + field->order); +} |