diff options
author | unknown <heikki@donna.mysql.fi> | 2001-10-10 22:47:08 +0300 |
---|---|---|
committer | unknown <heikki@donna.mysql.fi> | 2001-10-10 22:47:08 +0300 |
commit | 1904897be71cba7e6f2cf1192ba0cc2e8d907e00 (patch) | |
tree | fc361924d14a3d1727a8b88f61352ed039054720 /innobase/dict | |
parent | 151ffe886b4b21499471658fdf01ea8347287092 (diff) | |
download | mariadb-git-1904897be71cba7e6f2cf1192ba0cc2e8d907e00.tar.gz |
ut0mem.c Merge changes in InnoDB-3.23.43b
ut0ut.c Merge changes in InnoDB-3.23.43b
trx0purge.c Merge changes in InnoDB-3.23.43b
trx0rec.c Merge changes in InnoDB-3.23.43b
trx0trx.c Merge changes in InnoDB-3.23.43b
trx0undo.c Merge changes in InnoDB-3.23.43b
thr0loc.c Merge changes in InnoDB-3.23.43b
sync0arr.c Merge changes in InnoDB-3.23.43b
sync0rw.c Merge changes in InnoDB-3.23.43b
sync0sync.c Merge changes in InnoDB-3.23.43b
srv0srv.c Merge changes in InnoDB-3.23.43b
srv0start.c Merge changes in InnoDB-3.23.43b
row0ins.c Merge changes in InnoDB-3.23.43b
row0mysql.c Merge changes in InnoDB-3.23.43b
row0purge.c Merge changes in InnoDB-3.23.43b
row0sel.c Merge changes in InnoDB-3.23.43b
row0umod.c Merge changes in InnoDB-3.23.43b
row0upd.c Merge changes in InnoDB-3.23.43b
row0vers.c Merge changes in InnoDB-3.23.43b
rem0cmp.c Merge changes in InnoDB-3.23.43b
que0que.c Merge changes in InnoDB-3.23.43b
pars0opt.c Merge changes in InnoDB-3.23.43b
pars0pars.c Merge changes in InnoDB-3.23.43b
lexyy.c Merge changes in InnoDB-3.23.43b
pars0grm.c Merge changes in InnoDB-3.23.43b
page0page.c Merge changes in InnoDB-3.23.43b
os0file.c Merge changes in InnoDB-3.23.43b
mtr0log.c Merge changes in InnoDB-3.23.43b
mem0pool.c Merge changes in InnoDB-3.23.43b
log0log.c Merge changes in InnoDB-3.23.43b
log0recv.c Merge changes in InnoDB-3.23.43b
lock0lock.c Merge changes in InnoDB-3.23.43b
ibuf0ibuf.c Merge changes in InnoDB-3.23.43b
fil0fil.c Merge changes in InnoDB-3.23.43b
dict0crea.c Merge changes in InnoDB-3.23.43b
dict0dict.c Merge changes in InnoDB-3.23.43b
dict0load.c Merge changes in InnoDB-3.23.43b
dict0mem.c Merge changes in InnoDB-3.23.43b
data0data.c Merge changes in InnoDB-3.23.43b
data0type.c Merge changes in InnoDB-3.23.43b
buf0buf.c Merge changes in InnoDB-3.23.43b
buf0lru.c Merge changes in InnoDB-3.23.43b
btr0btr.c Merge changes in InnoDB-3.23.43b
btr0cur.c Merge changes in InnoDB-3.23.43b
btr0pcur.c Merge changes in InnoDB-3.23.43b
btr0sea.c Merge changes in InnoDB-3.23.43b
data0type.ic Merge changes in InnoDB-3.23.43b
dict0dict.ic Merge changes in InnoDB-3.23.43b
mtr0mtr.ic Merge changes in InnoDB-3.23.43b
row0upd.ic Merge changes in InnoDB-3.23.43b
sync0ipm.ic Merge changes in InnoDB-3.23.43b
sync0rw.ic Merge changes in InnoDB-3.23.43b
sync0sync.ic Merge changes in InnoDB-3.23.43b
trx0rseg.ic Merge changes in InnoDB-3.23.43b
btr0pcur.ic Merge changes in InnoDB-3.23.43b
buf0buf.ic Merge changes in InnoDB-3.23.43b
data0data.ic Merge changes in InnoDB-3.23.43b
row0upd.h Merge changes in InnoDB-3.23.43b
srv0srv.h Merge changes in InnoDB-3.23.43b
sync0arr.h Merge changes in InnoDB-3.23.43b
sync0rw.h Merge changes in InnoDB-3.23.43b
sync0sync.h Merge changes in InnoDB-3.23.43b
trx0trx.h Merge changes in InnoDB-3.23.43b
ut0mem.h Merge changes in InnoDB-3.23.43b
data0data.h Merge changes in InnoDB-3.23.43b
data0type.h Merge changes in InnoDB-3.23.43b
db0err.h Merge changes in InnoDB-3.23.43b
dict0crea.h Merge changes in InnoDB-3.23.43b
dict0dict.h Merge changes in InnoDB-3.23.43b
dict0load.h Merge changes in InnoDB-3.23.43b
dict0mem.h Merge changes in InnoDB-3.23.43b
dict0types.h Merge changes in InnoDB-3.23.43b
fil0fil.h Merge changes in InnoDB-3.23.43b
ibuf0ibuf.h Merge changes in InnoDB-3.23.43b
lock0lock.h Merge changes in InnoDB-3.23.43b
log0log.h Merge changes in InnoDB-3.23.43b
mtr0mtr.h Merge changes in InnoDB-3.23.43b
rem0cmp.h Merge changes in InnoDB-3.23.43b
row0ins.h Merge changes in InnoDB-3.23.43b
row0mysql.h Merge changes in InnoDB-3.23.43b
btr0cur.h Merge changes in InnoDB-3.23.43b
btr0pcur.h Merge changes in InnoDB-3.23.43b
btr0sea.h Merge changes in InnoDB-3.23.43b
buf0buf.h Merge changes in InnoDB-3.23.43b
sql_table.cc Merge changes in InnoDB-3.23.43b
sql_db.cc Merge changes in InnoDB-3.23.43b
ha_innobase.cc Merge changes in InnoDB-3.23.43b
handler.cc Merge changes in InnoDB-3.23.43b
ha_innobase.h Merge changes in InnoDB-3.23.43b
handler.h Merge changes in InnoDB-3.23.43b
sql/ha_innobase.h:
Merge changes in InnoDB-3.23.43b
sql/handler.h:
Merge changes in InnoDB-3.23.43b
sql/ha_innobase.cc:
Merge changes in InnoDB-3.23.43b
sql/handler.cc:
Merge changes in InnoDB-3.23.43b
sql/sql_db.cc:
Merge changes in InnoDB-3.23.43b
sql/sql_table.cc:
Merge changes in InnoDB-3.23.43b
innobase/include/btr0cur.h:
Merge changes in InnoDB-3.23.43b
innobase/include/btr0pcur.h:
Merge changes in InnoDB-3.23.43b
innobase/include/btr0sea.h:
Merge changes in InnoDB-3.23.43b
innobase/include/buf0buf.h:
Merge changes in InnoDB-3.23.43b
innobase/include/data0data.h:
Merge changes in InnoDB-3.23.43b
innobase/include/data0type.h:
Merge changes in InnoDB-3.23.43b
innobase/include/db0err.h:
Merge changes in InnoDB-3.23.43b
innobase/include/dict0crea.h:
Merge changes in InnoDB-3.23.43b
innobase/include/dict0dict.h:
Merge changes in InnoDB-3.23.43b
innobase/include/dict0load.h:
Merge changes in InnoDB-3.23.43b
innobase/include/dict0mem.h:
Merge changes in InnoDB-3.23.43b
innobase/include/dict0types.h:
Merge changes in InnoDB-3.23.43b
innobase/include/fil0fil.h:
Merge changes in InnoDB-3.23.43b
innobase/include/ibuf0ibuf.h:
Merge changes in InnoDB-3.23.43b
innobase/include/lock0lock.h:
Merge changes in InnoDB-3.23.43b
innobase/include/log0log.h:
Merge changes in InnoDB-3.23.43b
innobase/include/mtr0mtr.h:
Merge changes in InnoDB-3.23.43b
innobase/include/rem0cmp.h:
Merge changes in InnoDB-3.23.43b
innobase/include/row0ins.h:
Merge changes in InnoDB-3.23.43b
innobase/include/row0mysql.h:
Merge changes in InnoDB-3.23.43b
innobase/include/row0upd.h:
Merge changes in InnoDB-3.23.43b
innobase/include/srv0srv.h:
Merge changes in InnoDB-3.23.43b
innobase/include/sync0arr.h:
Merge changes in InnoDB-3.23.43b
innobase/include/sync0rw.h:
Merge changes in InnoDB-3.23.43b
innobase/include/sync0sync.h:
Merge changes in InnoDB-3.23.43b
innobase/include/trx0trx.h:
Merge changes in InnoDB-3.23.43b
innobase/include/ut0mem.h:
Merge changes in InnoDB-3.23.43b
innobase/include/btr0pcur.ic:
Merge changes in InnoDB-3.23.43b
innobase/include/buf0buf.ic:
Merge changes in InnoDB-3.23.43b
innobase/include/data0data.ic:
Merge changes in InnoDB-3.23.43b
innobase/include/data0type.ic:
Merge changes in InnoDB-3.23.43b
innobase/include/dict0dict.ic:
Merge changes in InnoDB-3.23.43b
innobase/include/mtr0mtr.ic:
Merge changes in InnoDB-3.23.43b
innobase/include/row0upd.ic:
Merge changes in InnoDB-3.23.43b
innobase/include/sync0ipm.ic:
Merge changes in InnoDB-3.23.43b
innobase/include/sync0rw.ic:
Merge changes in InnoDB-3.23.43b
innobase/include/sync0sync.ic:
Merge changes in InnoDB-3.23.43b
innobase/include/trx0rseg.ic:
Merge changes in InnoDB-3.23.43b
innobase/btr/btr0btr.c:
Merge changes in InnoDB-3.23.43b
innobase/btr/btr0cur.c:
Merge changes in InnoDB-3.23.43b
innobase/btr/btr0pcur.c:
Merge changes in InnoDB-3.23.43b
innobase/btr/btr0sea.c:
Merge changes in InnoDB-3.23.43b
innobase/buf/buf0buf.c:
Merge changes in InnoDB-3.23.43b
innobase/buf/buf0lru.c:
Merge changes in InnoDB-3.23.43b
innobase/data/data0data.c:
Merge changes in InnoDB-3.23.43b
innobase/data/data0type.c:
Merge changes in InnoDB-3.23.43b
innobase/dict/dict0crea.c:
Merge changes in InnoDB-3.23.43b
innobase/dict/dict0dict.c:
Merge changes in InnoDB-3.23.43b
innobase/dict/dict0load.c:
Merge changes in InnoDB-3.23.43b
innobase/dict/dict0mem.c:
Merge changes in InnoDB-3.23.43b
innobase/fil/fil0fil.c:
Merge changes in InnoDB-3.23.43b
innobase/ibuf/ibuf0ibuf.c:
Merge changes in InnoDB-3.23.43b
innobase/lock/lock0lock.c:
Merge changes in InnoDB-3.23.43b
innobase/log/log0log.c:
Merge changes in InnoDB-3.23.43b
innobase/log/log0recv.c:
Merge changes in InnoDB-3.23.43b
innobase/mem/mem0pool.c:
Merge changes in InnoDB-3.23.43b
innobase/mtr/mtr0log.c:
Merge changes in InnoDB-3.23.43b
innobase/os/os0file.c:
Merge changes in InnoDB-3.23.43b
innobase/page/page0page.c:
Merge changes in InnoDB-3.23.43b
innobase/pars/lexyy.c:
Merge changes in InnoDB-3.23.43b
innobase/pars/pars0grm.c:
Merge changes in InnoDB-3.23.43b
innobase/pars/pars0opt.c:
Merge changes in InnoDB-3.23.43b
innobase/pars/pars0pars.c:
Merge changes in InnoDB-3.23.43b
innobase/que/que0que.c:
Merge changes in InnoDB-3.23.43b
innobase/rem/rem0cmp.c:
Merge changes in InnoDB-3.23.43b
innobase/row/row0ins.c:
Merge changes in InnoDB-3.23.43b
innobase/row/row0mysql.c:
Merge changes in InnoDB-3.23.43b
innobase/row/row0purge.c:
Merge changes in InnoDB-3.23.43b
innobase/row/row0sel.c:
Merge changes in InnoDB-3.23.43b
innobase/row/row0umod.c:
Merge changes in InnoDB-3.23.43b
innobase/row/row0upd.c:
Merge changes in InnoDB-3.23.43b
innobase/row/row0vers.c:
Merge changes in InnoDB-3.23.43b
innobase/srv/srv0srv.c:
Merge changes in InnoDB-3.23.43b
innobase/srv/srv0start.c:
Merge changes in InnoDB-3.23.43b
innobase/sync/sync0arr.c:
Merge changes in InnoDB-3.23.43b
innobase/sync/sync0rw.c:
Merge changes in InnoDB-3.23.43b
innobase/sync/sync0sync.c:
Merge changes in InnoDB-3.23.43b
innobase/thr/thr0loc.c:
Merge changes in InnoDB-3.23.43b
innobase/trx/trx0purge.c:
Merge changes in InnoDB-3.23.43b
innobase/trx/trx0rec.c:
Merge changes in InnoDB-3.23.43b
innobase/trx/trx0trx.c:
Merge changes in InnoDB-3.23.43b
innobase/trx/trx0undo.c:
Merge changes in InnoDB-3.23.43b
innobase/ut/ut0mem.c:
Merge changes in InnoDB-3.23.43b
innobase/ut/ut0ut.c:
Merge changes in InnoDB-3.23.43b
BitKeeper/etc/logging_ok:
Logging to logging@openlogging.org accepted
Diffstat (limited to 'innobase/dict')
-rw-r--r-- | innobase/dict/dict0crea.c | 229 | ||||
-rw-r--r-- | innobase/dict/dict0dict.c | 1020 | ||||
-rw-r--r-- | innobase/dict/dict0load.c | 606 | ||||
-rw-r--r-- | innobase/dict/dict0mem.c | 43 |
4 files changed, 1772 insertions, 126 deletions
diff --git a/innobase/dict/dict0crea.c b/innobase/dict/dict0crea.c index 478364fba8a..9d79983c9e5 100644 --- a/innobase/dict/dict0crea.c +++ b/innobase/dict/dict0crea.c @@ -17,9 +17,13 @@ Created 1/8/1996 Heikki Tuuri #include "page0page.h" #include "mach0data.h" #include "dict0boot.h" +#include "dict0dict.h" #include "que0que.h" #include "row0ins.h" +#include "row0mysql.h" #include "pars0pars.h" +#include "trx0roll.h" +#include "usr0sess.h" /********************************************************************* Based on a table object, this function builds the entry to be inserted @@ -1019,3 +1023,228 @@ function_exit: return(thr); } + +/******************************************************************** +Creates the foreign key constraints system tables inside InnoDB +at database creation or database start if they are not found or are +not of the right form. */ + +ulint +dict_create_or_check_foreign_constraint_tables(void) +/*================================================*/ + /* out: DB_SUCCESS or error code */ +{ + dict_table_t* table1; + dict_table_t* table2; + que_thr_t* thr; + que_t* graph; + ulint error; + trx_t* trx; + char* str; + + mutex_enter(&(dict_sys->mutex)); + + table1 = dict_table_get_low("SYS_FOREIGN"); + table2 = dict_table_get_low("SYS_FOREIGN_COLS"); + + if (table1 && table2 + && UT_LIST_GET_LEN(table1->indexes) == 3 + && UT_LIST_GET_LEN(table2->indexes) == 1) { + + /* Foreign constraint system tables have already been + created, and they are ok */ + + mutex_exit(&(dict_sys->mutex)); + + return(DB_SUCCESS); + } + + trx = trx_allocate_for_mysql(); + + trx->op_info = "creating foreign key sys tables"; + + if (table1) { + fprintf(stderr, + "InnoDB: dropping incompletely created SYS_FOREIGN table\n"); + row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE); + } + + if (table2) { + fprintf(stderr, + "InnoDB: dropping incompletely created SYS_FOREIGN_COLS table\n"); + row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE); + } + + fprintf(stderr, + "InnoDB: creating foreign key constraint system tables\n"); + + /* NOTE: in dict_load_foreigns we use the fact that + there are 2 secondary indexes on SYS_FOREIGN, and they + are defined just like below */ + + str = + "PROCEDURE CREATE_FOREIGN_SYS_TABLES_PROC () IS\n" + "BEGIN\n" + "CREATE TABLE\n" + "SYS_FOREIGN(ID CHAR, FOR_NAME CHAR, REF_NAME CHAR, N_COLS INT);\n" + "CREATE UNIQUE CLUSTERED INDEX ID_IND ON SYS_FOREIGN (ID);\n" + "CREATE INDEX FOR_IND ON SYS_FOREIGN (FOR_NAME);\n" + "CREATE INDEX REF_IND ON SYS_FOREIGN (REF_NAME);\n" + "CREATE TABLE\n" + "SYS_FOREIGN_COLS(ID CHAR, POS INT, FOR_COL_NAME CHAR, REF_COL_NAME CHAR);\n" + "CREATE UNIQUE CLUSTERED INDEX ID_IND ON SYS_FOREIGN_COLS (ID, POS);\n" + "COMMIT WORK;\n" + "END;\n"; + + graph = pars_sql(str); + + ut_a(graph); + + graph->trx = trx; + trx->graph = NULL; + + graph->fork_type = QUE_FORK_MYSQL_INTERFACE; + + ut_a(thr = que_fork_start_command(graph, SESS_COMM_EXECUTE, 0)); + + que_run_threads(thr); + + error = trx->error_state; + + if (error != DB_SUCCESS) { + ut_a(error == DB_OUT_OF_FILE_SPACE); + + fprintf(stderr, "InnoDB: creation failed\n"); + fprintf(stderr, "InnoDB: tablespace is full\n"); + fprintf(stderr, + "InnoDB: dropping incompletely created SYS_FOREIGN tables\n"); + + row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE); + row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE); + + error = DB_MUST_GET_MORE_FILE_SPACE; + } + + que_graph_free(graph); + + trx->op_info = ""; + + trx_free_for_mysql(trx); + + if (error == DB_SUCCESS) { + fprintf(stderr, + "InnoDB: foreign key constraint system tables created\n"); + } + + mutex_exit(&(dict_sys->mutex)); + + return(error); +} + +/************************************************************************ +Adds foreign key definitions to data dictionary tables in the database. */ + +ulint +dict_create_add_foreigns_to_dictionary( +/*===================================*/ + /* out: error code or DB_SUCCESS */ + dict_table_t* table, /* in: table */ + trx_t* trx) /* in: transaction */ +{ + dict_foreign_t* foreign; + que_thr_t* thr; + que_t* graph; + dulint id; + ulint len; + ulint error; + ulint i; + char buf2[50]; + char buf[10000]; + + ut_ad(mutex_own(&(dict_sys->mutex))); + + if (NULL == dict_table_get_low("SYS_FOREIGN")) { + fprintf(stderr, + "InnoDB: table SYS_FOREIGN not found from internal data dictionary\n"); + return(DB_ERROR); + } + + foreign = UT_LIST_GET_FIRST(table->foreign_list); +loop: + if (foreign == NULL) { + + return(DB_SUCCESS); + } + + /* Build an InnoDB stored procedure which will insert the necessary + rows to SYS_FOREIGN and SYS_FOREIGN_COLS */ + + len = 0; + + len += sprintf(buf, + "PROCEDURE ADD_FOREIGN_DEFS_PROC () IS\n" + "BEGIN\n"); + + /* We allocate the new id from the sequence of table id's */ + id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID); + + sprintf(buf2, "%lu_%lu", ut_dulint_get_high(id), + ut_dulint_get_low(id)); + foreign->id = mem_heap_alloc(foreign->heap, ut_strlen(buf2) + 1); + ut_memcpy(foreign->id, buf2, ut_strlen(buf2) + 1); + + len += sprintf(buf + len, + "INSERT INTO SYS_FOREIGN VALUES('%lu_%lu', '%s', '%s', %lu);\n", + ut_dulint_get_high(id), + ut_dulint_get_low(id), + table->name, + foreign->referenced_table_name, + foreign->n_fields); + + for (i = 0; i < foreign->n_fields; i++) { + + len += sprintf(buf + len, + "INSERT INTO SYS_FOREIGN_COLS VALUES('%lu_%lu', %lu, '%s', '%s');\n", + ut_dulint_get_high(id), + ut_dulint_get_low(id), + i, + foreign->foreign_col_names[i], + foreign->referenced_col_names[i]); + } + + len += sprintf(buf + len,"COMMIT WORK;\nEND;\n"); + + graph = pars_sql(buf); + + ut_a(graph); + + graph->trx = trx; + trx->graph = NULL; + + graph->fork_type = QUE_FORK_MYSQL_INTERFACE; + + ut_a(thr = que_fork_start_command(graph, SESS_COMM_EXECUTE, 0)); + + que_run_threads(thr); + + error = trx->error_state; + + que_graph_free(graph); + + if (error != DB_SUCCESS) { + ut_a(error == DB_OUT_OF_FILE_SPACE); + + fprintf(stderr, "InnoDB: foreign constraint creation failed\n"); + fprintf(stderr, "InnoDB: tablespace is full\n"); + + trx_general_rollback_for_mysql(trx, FALSE, NULL); + + error = DB_MUST_GET_MORE_FILE_SPACE; + + return(error); + } + + foreign = UT_LIST_GET_NEXT(foreign_list, foreign); + + goto loop; +} diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c index 10d93fc6ecf..e0a7fd327a5 100644 --- a/innobase/dict/dict0dict.c +++ b/innobase/dict/dict0dict.c @@ -17,6 +17,7 @@ Created 1/8/1996 Heikki Tuuri #include "mach0data.h" #include "dict0boot.h" #include "dict0mem.h" +#include "dict0crea.h" #include "trx0undo.h" #include "btr0btr.h" #include "btr0cur.h" @@ -24,10 +25,12 @@ Created 1/8/1996 Heikki Tuuri #include "pars0pars.h" #include "pars0sym.h" #include "que0que.h" - +#include "rem0cmp.h" dict_sys_t* dict_sys = NULL; /* the dictionary system */ +rw_lock_t dict_foreign_key_check_lock; + #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 @@ -137,12 +140,12 @@ dict_tree_find_index_low( dict_tree_t* tree, /* in: index tree */ rec_t* rec); /* in: record for which to find correct index */ /************************************************************************** -Prints a table data. */ +Removes a foreign constraint struct from the dictionet cache. */ static void -dict_table_print_low( -/*=================*/ - dict_table_t* table); /* in: table */ +dict_foreign_remove_from_cache( +/*===========================*/ + dict_foreign_t* foreign); /* in, own: foreign constraint */ /************************************************************************** Prints a column data. */ static @@ -164,6 +167,13 @@ void dict_field_print_low( /*=================*/ dict_field_t* field); /* in: field */ +/************************************************************************* +Frees a foreign key struct. */ +static +void +dict_foreign_free( +/*==============*/ + dict_foreign_t* foreign); /* in, own: foreign key struct */ /************************************************************************ Reserves the dictionary system mutex for MySQL. */ @@ -353,7 +363,8 @@ dict_table_get_on_id( { dict_table_t* table; - if (ut_dulint_cmp(table_id, DICT_FIELDS_ID) <= 0) { + if (ut_dulint_cmp(table_id, DICT_FIELDS_ID) <= 0 + || trx->dict_operation) { /* 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 @@ -415,6 +426,10 @@ dict_init(void) dict_sys->size = 0; UT_LIST_INIT(dict_sys->table_LRU); + + rw_lock_create(&dict_foreign_key_check_lock); + rw_lock_set_level(&dict_foreign_key_check_lock, + SYNC_FOREIGN_KEY_CHECK); } /************************************************************************** @@ -535,6 +550,41 @@ dict_table_add_to_cache( } /************************************************************************** +Looks for an index with the given id. NOTE that we do not reserve +the dictionary mutex: this function is for emergency purposes like +printing info of a corrupt database page! */ + +dict_index_t* +dict_index_find_on_id_low( +/*======================*/ + /* out: index or NULL if not found from cache */ + dulint id) /* in: index id */ +{ + dict_table_t* table; + dict_index_t* index; + + table = UT_LIST_GET_FIRST(dict_sys->table_LRU); + + while (table) { + index = dict_table_get_first_index(table); + + while (index) { + if (0 == ut_dulint_cmp(id, index->tree->id)) { + /* Found */ + + return(index); + } + + index = dict_table_get_next_index(index); + } + + table = UT_LIST_GET_NEXT(table_LRU, table); + } + + return(NULL); +} + +/************************************************************************** Renames a table object. */ ibool @@ -544,10 +594,12 @@ dict_table_rename_in_cache( dict_table_t* table, /* in: table */ char* new_name) /* in: new name */ { - ulint fold; - ulint old_size; - char* name_buf; - ulint i; + dict_foreign_t* foreign; + dict_index_t* index; + ulint fold; + ulint old_size; + char* name_buf; + ulint i; ut_ad(table); ut_ad(mutex_own(&(dict_sys->mutex))); @@ -589,6 +641,55 @@ dict_table_rename_in_cache( dict_sys->size += (mem_heap_get_size(table->heap) - old_size); + /* Update the table_name field in indexes */ + index = dict_table_get_first_index(table); + + while (index != NULL) { + index->table_name = table->name; + + index = dict_table_get_next_index(index); + } + + /* Update the table name fields in foreign constraints */ + + foreign = UT_LIST_GET_FIRST(table->foreign_list); + + while (foreign != NULL) { + if (ut_strlen(foreign->foreign_table_name) < + ut_strlen(table->name)) { + /* Allocate a longer name buffer; + TODO: store buf len to save memory */ + foreign->foreign_table_name = mem_heap_alloc( + foreign->heap, + ut_strlen(table->name) + 1); + } + + ut_memcpy(foreign->foreign_table_name, table->name, + ut_strlen(table->name) + 1); + foreign->foreign_table_name[ut_strlen(table->name)] = '\0'; + + foreign = UT_LIST_GET_NEXT(foreign_list, foreign); + } + + foreign = UT_LIST_GET_FIRST(table->referenced_list); + + while (foreign != NULL) { + if (ut_strlen(foreign->referenced_table_name) < + ut_strlen(table->name)) { + /* Allocate a longer name buffer; + TODO: store buf len to save memory */ + foreign->referenced_table_name = mem_heap_alloc( + foreign->heap, + ut_strlen(table->name) + 1); + } + + ut_memcpy(foreign->referenced_table_name, table->name, + ut_strlen(table->name) + 1); + foreign->referenced_table_name[ut_strlen(table->name)] = '\0'; + + foreign = UT_LIST_GET_NEXT(referenced_list, foreign); + } + return(TRUE); } @@ -600,6 +701,7 @@ dict_table_remove_from_cache( /*=========================*/ dict_table_t* table) /* in, own: table */ { + dict_foreign_t* foreign; dict_index_t* index; ulint size; ulint i; @@ -610,6 +712,29 @@ dict_table_remove_from_cache( /* printf("Removing table %s from dictionary cache\n", table->name); */ + /* Remove the foreign constraints from the cache */ + foreign = UT_LIST_GET_LAST(table->foreign_list); + + while (foreign != NULL) { + ut_a(0 == ut_strcmp(foreign->foreign_table_name, table->name)); + + dict_foreign_remove_from_cache(foreign); + foreign = UT_LIST_GET_LAST(table->foreign_list); + } + + /* Reset table field in referencing constraints */ + + foreign = UT_LIST_GET_FIRST(table->referenced_list); + + while (foreign != NULL) { + ut_a(0 == ut_strcmp(foreign->referenced_table_name, + table->name)); + foreign->referenced_table = NULL; + foreign->referenced_index = NULL; + + foreign = UT_LIST_GET_NEXT(referenced_list, foreign); + } + /* Remove the indexes from the cache */ index = UT_LIST_GET_LAST(table->indexes); @@ -856,6 +981,21 @@ dict_index_add_to_cache( new_index->tree = tree; } + if (!(new_index->type & DICT_UNIVERSAL)) { + + new_index->stat_n_diff_key_vals = + mem_heap_alloc(new_index->heap, + (1 + dict_index_get_n_unique(new_index)) + * sizeof(ib_longlong)); + /* Give some sensible values to stat_n_... in case we do + not calculate statistics quickly enough */ + + for (i = 0; i <= dict_index_get_n_unique(new_index); i++) { + + new_index->stat_n_diff_key_vals[i] = 100; + } + } + /* Add the index to the list of indexes stored in the tree */ UT_LIST_ADD_LAST(tree_indexes, tree->tree_indexes, new_index); @@ -1290,6 +1430,654 @@ dict_index_build_internal_non_clust( return(new_index); } +/*====================== FOREIGN KEY PROCESSING ========================*/ + +/************************************************************************* +Frees a foreign key struct. */ +static +void +dict_foreign_free( +/*==============*/ + dict_foreign_t* foreign) /* in, own: foreign key struct */ +{ + mem_heap_free(foreign->heap); +} + +/************************************************************************** +Removes a foreign constraint struct from the dictionary cache. */ +static +void +dict_foreign_remove_from_cache( +/*===========================*/ + dict_foreign_t* foreign) /* in, own: foreign constraint */ +{ + ut_ad(mutex_own(&(dict_sys->mutex))); + ut_a(foreign); + + if (foreign->referenced_table) { + UT_LIST_REMOVE(referenced_list, + foreign->referenced_table->referenced_list, foreign); + } + + if (foreign->foreign_table) { + UT_LIST_REMOVE(foreign_list, + foreign->foreign_table->foreign_list, foreign); + } + + dict_foreign_free(foreign); +} + +/************************************************************************** +Looks for the foreign constraint from the foreign and referenced lists +of a table. */ +static +dict_foreign_t* +dict_foreign_find( +/*==============*/ + /* out: foreign constraint */ + dict_table_t* table, /* in: table object */ + char* id) /* in: foreign constraint id */ +{ + dict_foreign_t* foreign; + + ut_ad(mutex_own(&(dict_sys->mutex))); + + foreign = UT_LIST_GET_FIRST(table->foreign_list); + + while (foreign) { + if (ut_strcmp(id, foreign->id) == 0) { + + return(foreign); + } + + foreign = UT_LIST_GET_NEXT(foreign_list, foreign); + } + + foreign = UT_LIST_GET_FIRST(table->referenced_list); + + while (foreign) { + if (ut_strcmp(id, foreign->id) == 0) { + + return(foreign); + } + + foreign = UT_LIST_GET_NEXT(referenced_list, foreign); + } + + return(NULL); +} + +/************************************************************************* +Tries to find an index whose first fields are the columns in the array, +in the same order. */ +static +dict_index_t* +dict_foreign_find_index( +/*====================*/ + /* out: matching index, NULL if not found */ + dict_table_t* table, /* in: table */ + char** columns,/* in: array of column names */ + ulint n_cols, /* in: number of columns */ + dict_index_t* types_idx)/* in: NULL or an index to whose types the + column types must match */ +{ + dict_index_t* index; + char* col_name; + ulint i; + + index = dict_table_get_first_index(table); + + while (index != NULL) { + if (dict_index_get_n_fields(index) >= n_cols) { + + for (i = 0; i < n_cols; i++) { + col_name = dict_index_get_nth_field(index, i) + ->col->name; + if (ut_strlen(columns[i]) != + ut_strlen(col_name) + || 0 != ut_memcmp(columns[i], + col_name, + ut_strlen(col_name))) { + break; + } + + if (types_idx && !cmp_types_are_equal( + dict_index_get_nth_type(index, i), + dict_index_get_nth_type(types_idx, i))) { + + break; + } + } + + if (i == n_cols) { + /* We found a matching index */ + + return(index); + } + } + + index = dict_table_get_next_index(index); + } + + return(NULL); +} + +/************************************************************************** +Adds a foreign key constraint object to the dictionary cache. May free +the object if there already is an object with the same identifier in. +At least one of the foreign table and the referenced table must already +be in the dictionary cache! */ + +ulint +dict_foreign_add_to_cache( +/*======================*/ + /* out: DB_SUCCESS or error code */ + dict_foreign_t* foreign) /* in, own: foreign key constraint */ +{ + dict_table_t* for_table; + dict_table_t* ref_table; + dict_foreign_t* for_in_cache = NULL; + dict_index_t* index; + + ut_ad(mutex_own(&(dict_sys->mutex))); + + for_table = dict_table_check_if_in_cache_low( + foreign->foreign_table_name); + + ref_table = dict_table_check_if_in_cache_low( + foreign->referenced_table_name); + ut_a(for_table || ref_table); + + if (for_table) { + for_in_cache = dict_foreign_find(for_table, foreign->id); + } + + if (!for_in_cache && ref_table) { + for_in_cache = dict_foreign_find(ref_table, foreign->id); + } + + if (for_in_cache) { + /* Free the foreign object */ + mem_heap_free(foreign->heap); + } else { + for_in_cache = foreign; + } + + if (for_in_cache->referenced_table == NULL && ref_table) { + index = dict_foreign_find_index(ref_table, + for_in_cache->referenced_col_names, + for_in_cache->n_fields, + for_in_cache->foreign_index); + + if (index == NULL) { + if (for_in_cache == foreign) { + mem_heap_free(foreign->heap); + } + return(DB_CANNOT_ADD_CONSTRAINT); + } + + for_in_cache->referenced_table = ref_table; + for_in_cache->referenced_index = index; + UT_LIST_ADD_LAST(referenced_list, + ref_table->referenced_list, + for_in_cache); + } + + if (for_in_cache->foreign_table == NULL && for_table) { + index = dict_foreign_find_index(for_table, + for_in_cache->foreign_col_names, + for_in_cache->n_fields, + for_in_cache->referenced_index); + + if (index == NULL) { + if (for_in_cache == foreign) { + mem_heap_free(foreign->heap); + } + + return(DB_CANNOT_ADD_CONSTRAINT); + } + + for_in_cache->foreign_table = for_table; + for_in_cache->foreign_index = index; + UT_LIST_ADD_LAST(foreign_list, + for_table->foreign_list, + for_in_cache); + } + + return(DB_SUCCESS); +} + +/************************************************************************* +Scans from pointer onwards. Stops if is at the start of a copy of +'string' where characters are compared without case sensitivity. Stops +also at '\0'. */ +static +char* +dict_scan_to( +/*=========*/ + + char* ptr, /* in: scan from */ + char* string) /* in: look for this */ +{ + ibool success; + ulint i; +loop: + if (*ptr == '\0') { + return(ptr); + } + + success = TRUE; + + for (i = 0; i < ut_strlen(string); i++) { + if (toupper((ulint)(ptr[i])) != toupper((ulint)(string[i]))) { + success = FALSE; + + break; + } + } + + if (success) { + + return(ptr); + } + + ptr++; + + goto loop; +} + +/************************************************************************* +Accepts a specified string. Comparisons are case-insensitive. */ +static +char* +dict_accept( +/*========*/ + /* out: if string was accepted, the pointer + is moved after that, else ptr is returned */ + char* ptr, /* in: scan from this */ + char* string, /* in: accept only this string as the next + non-whitespace string */ + ibool* success)/* out: TRUE if accepted */ +{ + char* old_ptr = ptr; + char* old_ptr2; + + *success = FALSE; + + while (isspace(*ptr)) { + ptr++; + } + + old_ptr2 = ptr; + + ptr = dict_scan_to(ptr, string); + + if (*ptr == '\0' || old_ptr2 != ptr) { + return(old_ptr); + } + + *success = TRUE; + + return(ptr + ut_strlen(string)); +} + +/************************************************************************* +Tries to scan a column name. */ +static +char* +dict_scan_col( +/*==========*/ + /* out: scanned to */ + char* ptr, /* in: scanned to */ + ibool* success,/* out: TRUE if success */ + dict_table_t* table, /* in: table in which the column is */ + dict_col_t** column, /* out: pointer to column if success */ + char** column_name)/* out: pointer to column->name if + success */ +{ + dict_col_t* col; + char* old_ptr; + ulint i; + + *success = FALSE; + + while (isspace(*ptr)) { + ptr++; + } + + if (*ptr == '\0') { + + return(ptr); + } + + old_ptr = ptr; + + while (!isspace(*ptr) && *ptr != ',' && *ptr != ')') { + ptr++; + } + + for (i = 0; i < dict_table_get_n_cols(table); i++) { + + col = dict_table_get_nth_col(table, i); + + if (ut_strlen(col->name) == (ulint)(ptr - old_ptr) + && 0 == ut_memcmp(col->name, old_ptr, + (ulint)(ptr - old_ptr))) { + + /* Found */ + + *success = TRUE; + *column = col; + *column_name = col->name; + + break; + } + } + + return(ptr); +} + +/************************************************************************* +Scans the referenced table name from an SQL string. */ +static +char* +dict_scan_table_name( +/*=================*/ + /* out: scanned to */ + char* ptr, /* in: scanned to */ + dict_table_t** table, /* out: table object or NULL if error */ + char* name) /* in: foreign key table name */ +{ + char* dot_ptr = NULL; + char* old_ptr; + ulint i; + char second_table_name[10000]; + + *table = NULL; + + while (isspace(*ptr)) { + ptr++; + } + + if (*ptr == '\0') { + + return(ptr); + } + + old_ptr = ptr; + + while (!isspace(*ptr) && *ptr != '(') { + if (*ptr == '.') { + dot_ptr = ptr; + } + + ptr++; + } + + if (ptr - old_ptr > 9000) { + return(old_ptr); + } + + if (dot_ptr == NULL) { + /* Copy the database name from 'name' to the start */ + for (i = 0;; i++) { + second_table_name[i] = name[i]; + if (name[i] == '/') { + i++; + break; + } + } + + ut_memcpy(second_table_name + i, old_ptr, ptr - old_ptr); + second_table_name[i + (ptr - old_ptr)] = '\0'; + } else { + ut_memcpy(second_table_name, old_ptr, ptr - old_ptr); + second_table_name[dot_ptr - old_ptr] = '/'; + second_table_name[ptr - old_ptr] = '\0'; + } + + *table = dict_table_get_low(second_table_name); + + return(ptr); +} + +/************************************************************************* +Returns the number of opening brackets '(' subtracted by the number +of closing brackets ')' between string and ptr. */ +static +int +dict_bracket_count( +/*===============*/ + /* out: bracket count */ + char* string, /* in: start of string */ + char* ptr) /* in: end of string */ +{ + int count = 0; + + while (string != ptr) { + if (*string == '(') { + count++; + } + if (*string == ')') { + count--; + } + + string++; + } + + return(count); +} + +/************************************************************************* +Scans a table create SQL string and adds to the data dictionary the foreign +key constraints declared in the string. This function should be called after +the indexes for a table have been created. Each foreign key constraint must +be accompanied with indexes in both participating tables. The indexes are +allowed to contain more fields than mentioned in the constraint. */ + +ulint +dict_create_foreign_constraints( +/*============================*/ + /* out: error code or DB_SUCCESS */ + trx_t* trx, /* in: transaction */ + char* sql_string, /* in: table create statement where + foreign keys are declared like: + FOREIGN KEY (a, b) REFERENCES table2(c, d), + table2 can be written also with the database + name before it: test.table2; the default + database id the database of parameter name */ + char* name) /* in: table full name in the normalized form + database_name/table_name */ +{ + dict_table_t* table; + dict_table_t* referenced_table; + dict_index_t* index; + dict_foreign_t* foreign; + char* ptr = sql_string; + ibool success; + ulint error; + ulint i; + dict_col_t* columns[1000]; + char* column_names[1000]; + + ut_ad(mutex_own(&(dict_sys->mutex))); + + table = dict_table_get_low(name); + + if (table == NULL) { + return(DB_ERROR); + } +loop: + ptr = dict_scan_to(ptr, "FOREIGN"); + + if (*ptr == '\0' || dict_bracket_count(sql_string, ptr) != 1) { + + /* The following call adds the foreign key constraints + to the data dictionary system tables on disk */ + + error = dict_create_add_foreigns_to_dictionary(table, trx); + + return(error); + } + + ptr = dict_accept(ptr, "FOREIGN", &success); + + if (!isspace(*ptr)) { + return(DB_CANNOT_ADD_CONSTRAINT); + } + + ptr = dict_accept(ptr, "KEY", &success); + + if (!success) { + goto loop; + } + + ptr = dict_accept(ptr, "(", &success); + + if (!success) { + goto loop; + } + + i = 0; + + /* Scan the columns in the first list */ +col_loop1: + ptr = dict_scan_col(ptr, &success, table, columns + i, + column_names + i); + if (!success) { + return(DB_CANNOT_ADD_CONSTRAINT); + } + + i++; + + ptr = dict_accept(ptr, ",", &success); + + if (success) { + goto col_loop1; + } + + ptr = dict_accept(ptr, ")", &success); + + if (!success) { + return(DB_CANNOT_ADD_CONSTRAINT); + } + + /* Try to find an index which contains the columns + as the first fields and in the right order */ + + index = dict_foreign_find_index(table, column_names, i, NULL); + + if (!index) { + return(DB_CANNOT_ADD_CONSTRAINT); + } + + ptr = dict_accept(ptr, "REFERENCES", &success); + + if (!success || !isspace(*ptr)) { + return(DB_CANNOT_ADD_CONSTRAINT); + } + + /* Let us create a constraint struct */ + + foreign = dict_mem_foreign_create(); + + foreign->foreign_table = table; + foreign->foreign_table_name = table->name; + foreign->foreign_index = index; + foreign->n_fields = i; + foreign->foreign_col_names = mem_heap_alloc(foreign->heap, + i * sizeof(void*)); + for (i = 0; i < foreign->n_fields; i++) { + foreign->foreign_col_names[i] = mem_heap_alloc(foreign->heap, + 1 + ut_strlen(columns[i]->name)); + ut_memcpy(foreign->foreign_col_names[i], columns[i]->name, + 1 + ut_strlen(columns[i]->name)); + } + + ptr = dict_scan_table_name(ptr, &referenced_table, name); + + if (!referenced_table) { + dict_foreign_free(foreign); + + return(DB_CANNOT_ADD_CONSTRAINT); + } + + ptr = dict_accept(ptr, "(", &success); + + if (!success) { + dict_foreign_free(foreign); + return(DB_CANNOT_ADD_CONSTRAINT); + } + + /* Scan the columns in the second list */ + i = 0; + +col_loop2: + ptr = dict_scan_col(ptr, &success, referenced_table, columns + i, + column_names + i); + i++; + + if (!success) { + dict_foreign_free(foreign); + return(DB_CANNOT_ADD_CONSTRAINT); + } + + ptr = dict_accept(ptr, ",", &success); + + if (success) { + goto col_loop2; + } + + ptr = dict_accept(ptr, ")", &success); + + if (!success || foreign->n_fields != i) { + dict_foreign_free(foreign); + + return(DB_CANNOT_ADD_CONSTRAINT); + } + + /* Try to find an index which contains the columns as the first fields + and in the right order, and the types are the same as in + foreign->foreign_index */ + + index = dict_foreign_find_index(referenced_table, column_names, i, + foreign->foreign_index); + + if (!index) { + dict_foreign_free(foreign); + return(DB_CANNOT_ADD_CONSTRAINT); + } + + foreign->referenced_index = index; + foreign->referenced_table = referenced_table; + + foreign->referenced_table_name = mem_heap_alloc(foreign->heap, + 1 + ut_strlen(referenced_table->name)); + + ut_memcpy(foreign->referenced_table_name, referenced_table->name, + 1 + ut_strlen(referenced_table->name)); + + foreign->referenced_col_names = mem_heap_alloc(foreign->heap, + i * sizeof(void*)); + for (i = 0; i < foreign->n_fields; i++) { + foreign->referenced_col_names[i] + = mem_heap_alloc(foreign->heap, + 1 + ut_strlen(columns[i]->name)); + ut_memcpy( + foreign->referenced_col_names[i], columns[i]->name, + 1 + ut_strlen(columns[i]->name)); + } + + /* We found an ok constraint definition: add to the lists */ + + UT_LIST_ADD_LAST(foreign_list, table->foreign_list, foreign); + UT_LIST_ADD_LAST(referenced_list, referenced_table->referenced_list, + foreign); + goto loop; +} + +/*==================== END OF FOREIGN KEY PROCESSING ====================*/ + /************************************************************************** Adds a stored procedure object to the dictionary cache. */ @@ -1733,77 +2521,127 @@ dict_tree_build_data_tuple( } /************************************************************************* -Calculates new estimates for table and index statistics. The statistics -are used in query optimization. */ +Calculates the minimum record length in an index. */ -void -dict_update_statistics( -/*===================*/ - dict_table_t* table) /* in: table */ +ulint +dict_index_calc_min_rec_len( +/*========================*/ + dict_index_t* index) /* in: index */ { - 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); + ulint sum = 0; + ulint i; - n_rows = btr_estimate_n_rows_in_range(index, start, PAGE_CUR_G, - end, PAGE_CUR_L); - mem_heap_free(heap); + for (i = 0; i < dict_index_get_n_fields(index); i++) { + sum += dtype_get_fixed_size(dict_index_get_nth_type(index, i)); + } - if (n_rows > 0) { - /* For small tables our estimate function tends to give - values 1 too big */ - n_rows--; + if (sum > 127) { + sum += 2 * dict_index_get_n_fields(index); + } else { + sum += dict_index_get_n_fields(index); } - mutex_enter(&(dict_sys->mutex)); + sum += REC_N_EXTRA_BYTES; - table->stat_last_estimate_counter = table->stat_modif_counter; - table->stat_n_rows = n_rows; + return(sum); +} - mutex_exit(&(dict_sys->mutex)); +/************************************************************************* +Calculates new estimates for table and index statistics. The statistics +are used in query optimization. */ + +void +dict_update_statistics_low( +/*=======================*/ + dict_table_t* table, /* in: table */ + ibool has_dict_mutex) /* in: TRUE if the caller has the + dictionary mutex */ +{ + dict_index_t* index; + ulint size; + ulint sum_of_index_sizes = 0; /* Find out the sizes of the indexes and how many different values for the key they approximately have */ - + + index = dict_table_get_first_index(table); + while (index) { - n_vals = btr_estimate_number_of_different_key_vals(index); size = btr_get_size(index, BTR_TOTAL_SIZE); + index->stat_index_size = size; + sum_of_index_sizes += size; - mutex_enter(&(dict_sys->mutex)); + size = btr_get_size(index, BTR_N_LEAF_PAGES); - index->stat_n_diff_key_vals = n_vals; - index->stat_index_size = size; + if (size == 0) { + /* The root node of the tree is a leaf */ + size = 1; + } - mutex_exit(&(dict_sys->mutex)); + index->stat_n_leaf_pages = size; + + btr_estimate_number_of_different_key_vals(index); index = dict_table_get_next_index(index); } index = dict_table_get_first_index(table); + table->stat_n_rows = index->stat_n_diff_key_vals[ + dict_index_get_n_unique(index)]; + table->stat_clustered_index_size = index->stat_index_size; table->stat_sum_of_other_index_sizes = sum_of_index_sizes - - index->stat_index_size; + - index->stat_index_size; table->stat_last_estimate_counter = table->stat_modif_counter; } +/************************************************************************* +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 */ +{ + dict_update_statistics_low(table, FALSE); +} + +/************************************************************************** +Prints info of a foreign key constraint. */ +static +void +dict_foreign_print_low( +/*===================*/ + dict_foreign_t* foreign) /* in: foreign key constraint */ +{ + ulint i; + + ut_ad(mutex_own(&(dict_sys->mutex))); + + printf(" FOREIGN KEY CONSTRAINT %s: %s (", foreign->id, + foreign->foreign_table_name); + + for (i = 0; i < foreign->n_fields; i++) { + printf(" %s", foreign->foreign_col_names[i]); + } + + printf(" )\n"); + + printf(" REFERENCES %s (", foreign->referenced_table_name); + + for (i = 0; i < foreign->n_fields; i++) { + printf(" %s", foreign->referenced_col_names[i]); + } + + printf(" )\n"); +} + /************************************************************************** Prints a table data. */ @@ -1839,31 +2677,57 @@ dict_table_print_by_name( /************************************************************************** Prints a table data. */ -static + void dict_table_print_low( /*=================*/ dict_table_t* table) /* in: table */ { - ulint i; dict_index_t* index; + dict_foreign_t* foreign; + ulint i; ut_ad(mutex_own(&(dict_sys->mutex))); + dict_update_statistics_low(table, TRUE); + 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(" "); + printf( + "TABLE: name %s, id %lu %lu, columns %lu, indexes %lu, appr.rows %lu\n", + table->name, + ut_dulint_get_high(table->id), + ut_dulint_get_low(table->id), + table->n_cols, UT_LIST_GET_LEN(table->indexes), + (ulint)table->stat_n_rows); + printf(" COLUMNS: "); + + for (i = 0; i < table->n_cols - 1; i++) { dict_col_print_low(dict_table_get_nth_col(table, i)); + printf("; "); } + printf("\n"); + index = UT_LIST_GET_FIRST(table->indexes); while (index != NULL) { dict_index_print_low(index); index = UT_LIST_GET_NEXT(indexes, index); } + + foreign = UT_LIST_GET_FIRST(table->foreign_list); + + while (foreign != NULL) { + dict_foreign_print_low(foreign); + foreign = UT_LIST_GET_NEXT(foreign_list, foreign); + } + + foreign = UT_LIST_GET_FIRST(table->referenced_list); + + while (foreign != NULL) { + dict_foreign_print_low(foreign); + foreign = UT_LIST_GET_NEXT(referenced_list, foreign); + } } /************************************************************************** @@ -1879,7 +2743,7 @@ dict_col_print_low( ut_ad(mutex_own(&(dict_sys->mutex))); type = dict_col_get_type(col); - printf("COLUMN: name %s; ", col->name); + printf("%s: ", col->name); dtype_print(type); } @@ -1892,28 +2756,47 @@ dict_index_print_low( /*=================*/ dict_index_t* index) /* in: index */ { - ulint i; dict_tree_t* tree; + ib_longlong n_vals; + ulint i; ut_ad(mutex_own(&(dict_sys->mutex))); tree = index->tree; - + + if (index->n_user_defined_cols > 0) { + n_vals = index->stat_n_diff_key_vals[ + index->n_user_defined_cols]; + } else { + n_vals = index->stat_n_diff_key_vals[1]; + } + + 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); + " INDEX: name %s, table name %s, id %lu %lu, fields %lu/%lu, type %lu\n", + index->name, index->table_name, + ut_dulint_get_high(tree->id), + ut_dulint_get_low(tree->id), + index->n_user_defined_cols, + index->n_fields, index->type); + printf( + " root page %lu, appr.key vals %lu, leaf pages %lu, size pages %lu\n", + tree->page, + (ulint)n_vals, + index->stat_n_leaf_pages, + index->stat_index_size); + printf(" FIELDS: "); + for (i = 0; i < index->n_fields; i++) { - printf(" "); dict_field_print_low(dict_index_get_nth_field(index, i)); } - btr_print_size(tree); + printf("\n"); + +/* btr_print_size(tree); */ - btr_print_tree(tree, 7); +/* btr_print_tree(tree, 7); */ } /************************************************************************** @@ -1926,6 +2809,5 @@ dict_field_print_low( { ut_ad(mutex_own(&(dict_sys->mutex))); - printf("FIELD: column name %s, order criterion %lu\n", field->name, - field->order); + printf(" %s", field->name); } diff --git a/innobase/dict/dict0load.c b/innobase/dict/dict0load.c index be16988086a..dcdc9ee01cd 100644 --- a/innobase/dict/dict0load.c +++ b/innobase/dict/dict0load.c @@ -48,8 +48,171 @@ dict_load_fields( /************************************************************************ +Finds the first table name in the given database. */ + +char* +dict_get_first_table_name_in_db( +/*============================*/ + /* out, own: table name, NULL if does not exist; + the caller must free the memory in the string! */ + char* name) /* in: database name which ends to '/' */ +{ + dict_table_t* sys_tables; + btr_pcur_t pcur; + dict_index_t* sys_index; + dtuple_t* tuple; + mem_heap_t* heap; + dfield_t* dfield; + rec_t* rec; + byte* field; + ulint len; + char* table_name; + mtr_t mtr; + + ut_ad(mutex_own(&(dict_sys->mutex))); + + heap = mem_heap_create(1000); + + mtr_start(&mtr); + + sys_tables = dict_table_get_low("SYS_TABLES"); + sys_index = UT_LIST_GET_FIRST(sys_tables->indexes); + + tuple = dtuple_create(heap, 1); + dfield = dtuple_get_nth_field(tuple, 0); + + dfield_set_data(dfield, name, ut_strlen(name)); + dict_index_copy_types(tuple, sys_index, 1); + + btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, + BTR_SEARCH_LEAF, &pcur, &mtr); +loop: + rec = btr_pcur_get_rec(&pcur); + + if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) { + /* Not found */ + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + mem_heap_free(heap); + + return(NULL); + } + + field = rec_get_nth_field(rec, 0, &len); + + if (len < strlen(name) + || ut_memcmp(name, field, strlen(name)) != 0) { + /* Not found */ + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + mem_heap_free(heap); + + return(NULL); + } + + if (!rec_get_deleted_flag(rec)) { + + /* We found one */ + + table_name = mem_alloc(len + 1); + ut_memcpy(table_name, field, len); + table_name[len] = '\0'; + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + mem_heap_free(heap); + + return(table_name); + } + + btr_pcur_move_to_next_user_rec(&pcur, &mtr); + + goto loop; +} + +/************************************************************************ +Prints to the standard output information on all tables found in the data +dictionary system table. */ + +void +dict_print(void) +/*============*/ +{ + dict_table_t* sys_tables; + dict_index_t* sys_index; + dict_table_t* table; + btr_pcur_t pcur; + rec_t* rec; + byte* field; + ulint len; + char table_name[10000]; + mtr_t mtr; + + mutex_enter(&(dict_sys->mutex)); + + mtr_start(&mtr); + + sys_tables = dict_table_get_low("SYS_TABLES"); + sys_index = UT_LIST_GET_FIRST(sys_tables->indexes); + + btr_pcur_open_at_index_side(TRUE, sys_index, BTR_SEARCH_LEAF, &pcur, + TRUE, &mtr); +loop: + btr_pcur_move_to_next_user_rec(&pcur, &mtr); + + rec = btr_pcur_get_rec(&pcur); + + if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) { + /* end of index */ + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + + mutex_exit(&(dict_sys->mutex)); + + return; + } + + field = rec_get_nth_field(rec, 0, &len); + + if (!rec_get_deleted_flag(rec)) { + + /* We found one */ + + ut_memcpy(table_name, field, len); + table_name[len] = '\0'; + + btr_pcur_store_position(&pcur, &mtr); + + mtr_commit(&mtr); + + table = dict_table_get_low(table_name); + + if (table == NULL) { + fprintf(stderr, "InnoDB: Failed to load table %s\n", + table_name); + } else { + dict_update_statistics_low(table, TRUE); + + dict_table_print_low(table); + } + + mtr_start(&mtr); + + btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr); + } + + goto loop; +} + +/************************************************************************ Loads a table definition and also all its index definitions, and also -the cluster definition if the table is a member in a cluster. */ +the cluster definition if the table is a member in a cluster. Also loads +all foreign key constraints where the foreign key is in the table or where +a foreign key references columns in this table. Adds all these to the data +dictionary cache. */ dict_table_t* dict_load_table( @@ -59,7 +222,6 @@ dict_load_table( { dict_table_t* table; dict_table_t* sys_tables; - mtr_t mtr; btr_pcur_t pcur; dict_index_t* sys_index; dtuple_t* tuple; @@ -71,6 +233,7 @@ dict_load_table( char* buf; ulint space; ulint n_cols; + mtr_t mtr; ut_ad(mutex_own(&(dict_sys->mutex))); @@ -178,6 +341,106 @@ dict_load_table( dict_load_indexes(table, heap); + ut_a(DB_SUCCESS == dict_load_foreigns(table->name)); + + mem_heap_free(heap); + + return(table); +} + +/*************************************************************************** +Loads a table object based on the table id. */ + +dict_table_t* +dict_load_table_on_id( +/*==================*/ + /* out: table; NULL if table does not exist */ + dulint table_id) /* in: table id */ +{ + byte id_buf[8]; + btr_pcur_t pcur; + mem_heap_t* heap; + dtuple_t* tuple; + dfield_t* dfield; + dict_index_t* sys_table_ids; + dict_table_t* sys_tables; + rec_t* rec; + byte* field; + ulint len; + dict_table_t* table; + char* name; + mtr_t mtr; + + ut_ad(mutex_own(&(dict_sys->mutex))); + + /* NOTE that the operation of this function is protected by + the dictionary mutex, and therefore no deadlocks can occur + with other dictionary operations. */ + + mtr_start(&mtr); + /*---------------------------------------------------*/ + /* Get the secondary index based on ID for table SYS_TABLES */ + sys_tables = dict_sys->sys_tables; + sys_table_ids = dict_table_get_next_index( + dict_table_get_first_index(sys_tables)); + heap = mem_heap_create(256); + + tuple = dtuple_create(heap, 1); + dfield = dtuple_get_nth_field(tuple, 0); + + /* Write the table id in byte format to id_buf */ + mach_write_to_8(id_buf, table_id); + + dfield_set_data(dfield, id_buf, 8); + dict_index_copy_types(tuple, sys_table_ids, 1); + + btr_pcur_open_on_user_rec(sys_table_ids, tuple, PAGE_CUR_GE, + BTR_SEARCH_LEAF, &pcur, &mtr); + rec = btr_pcur_get_rec(&pcur); + + if (!btr_pcur_is_on_user_rec(&pcur, &mtr) + || rec_get_deleted_flag(rec)) { + /* Not found */ + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + mem_heap_free(heap); + + return(NULL); + } + + /*---------------------------------------------------*/ + /* Now we have the record in the secondary index containing the + table ID and NAME */ + + rec = btr_pcur_get_rec(&pcur); + field = rec_get_nth_field(rec, 0, &len); + ut_ad(len == 8); + + /* Check if the table id in record is the one searched for */ + if (ut_dulint_cmp(table_id, mach_read_from_8(field)) != 0) { + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + mem_heap_free(heap); + + return(NULL); + } + + /* Now we get the table name from the record */ + field = rec_get_nth_field(rec, 1, &len); + + name = mem_heap_alloc(heap, len + 1); + ut_memcpy(name, field, len); + name[len] = '\0'; + + /* Load the table definition to memory */ + table = dict_load_table(name); + + ut_a(table); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); mem_heap_free(heap); return(table); @@ -305,7 +568,8 @@ dict_load_columns( } /************************************************************************ -Loads definitions for table indexes. */ +Loads definitions for table indexes. Adds them to the data dictionary cache. +*/ static void dict_load_indexes( @@ -446,7 +710,6 @@ dict_load_fields( { dict_table_t* sys_fields; dict_index_t* sys_index; - mtr_t mtr; btr_pcur_t pcur; dtuple_t* tuple; dfield_t* dfield; @@ -456,6 +719,7 @@ dict_load_fields( ulint len; byte* buf; ulint i; + mtr_t mtr; ut_ad(mutex_own(&(dict_sys->mutex))); @@ -512,100 +776,328 @@ dict_load_fields( mtr_commit(&mtr); } +/************************************************************************ +Loads foreign key constraint col names (also for the referenced table). */ +static +void +dict_load_foreign_cols( +/*===================*/ + char* id, /* in: foreign constraint id as a null- + terminated string */ + dict_foreign_t* foreign)/* in: foreign constraint object */ +{ + dict_table_t* sys_foreign_cols; + dict_index_t* sys_index; + btr_pcur_t pcur; + dtuple_t* tuple; + dfield_t* dfield; + char* col_name; + rec_t* rec; + byte* field; + ulint len; + ulint i; + mtr_t mtr; + + ut_ad(mutex_own(&(dict_sys->mutex))); + + foreign->foreign_col_names = mem_heap_alloc(foreign->heap, + foreign->n_fields * sizeof(void*)); + + foreign->referenced_col_names = mem_heap_alloc(foreign->heap, + foreign->n_fields * sizeof(void*)); + mtr_start(&mtr); + + sys_foreign_cols = dict_table_get_low("SYS_FOREIGN_COLS"); + sys_index = UT_LIST_GET_FIRST(sys_foreign_cols->indexes); + + tuple = dtuple_create(foreign->heap, 1); + dfield = dtuple_get_nth_field(tuple, 0); + + dfield_set_data(dfield, id, ut_strlen(id)); + dict_index_copy_types(tuple, sys_index, 1); + + btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, + BTR_SEARCH_LEAF, &pcur, &mtr); + for (i = 0; i < foreign->n_fields; i++) { + + rec = btr_pcur_get_rec(&pcur); + + ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr)); + ut_a(!rec_get_deleted_flag(rec)); + + field = rec_get_nth_field(rec, 0, &len); + ut_a(len == ut_strlen(id)); + ut_a(ut_memcmp(id, field, len) == 0); + + field = rec_get_nth_field(rec, 1, &len); + ut_a(len == 4); + ut_a(i == mach_read_from_4(field)); + + field = rec_get_nth_field(rec, 4, &len); + + col_name = mem_heap_alloc(foreign->heap, len + 1); + ut_memcpy(col_name, field, len); + col_name[len] = '\0'; + + foreign->foreign_col_names[i] = col_name; + + field = rec_get_nth_field(rec, 5, &len); + + col_name = mem_heap_alloc(foreign->heap, len + 1); + ut_memcpy(col_name, field, len); + col_name[len] = '\0'; + + foreign->referenced_col_names[i] = col_name; + + btr_pcur_move_to_next_user_rec(&pcur, &mtr); + } + + btr_pcur_close(&pcur); + mtr_commit(&mtr); +} + /*************************************************************************** -Loads a table object based on the table id. */ +Loads a foreign key constraint to the dictionary cache. */ +static +ulint +dict_load_foreign( +/*==============*/ + /* out: DB_SUCCESS or error code */ + char* id) /* in: foreign constraint id as a null-terminated + string */ +{ + dict_foreign_t* foreign; + dict_table_t* sys_foreign; + btr_pcur_t pcur; + dict_index_t* sys_index; + dtuple_t* tuple; + mem_heap_t* heap2; + dfield_t* dfield; + rec_t* rec; + byte* field; + ulint len; + ulint err; + mtr_t mtr; + + ut_ad(mutex_own(&(dict_sys->mutex))); -dict_table_t* -dict_load_table_on_id( -/*==================*/ - /* out: table; NULL if table does not exist */ - dulint table_id) /* in: table id */ + heap2 = mem_heap_create(1000); + + mtr_start(&mtr); + + sys_foreign = dict_table_get_low("SYS_FOREIGN"); + sys_index = UT_LIST_GET_FIRST(sys_foreign->indexes); + + tuple = dtuple_create(heap2, 1); + dfield = dtuple_get_nth_field(tuple, 0); + + dfield_set_data(dfield, id, ut_strlen(id)); + dict_index_copy_types(tuple, sys_index, 1); + + btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, + BTR_SEARCH_LEAF, &pcur, &mtr); + rec = btr_pcur_get_rec(&pcur); + + if (!btr_pcur_is_on_user_rec(&pcur, &mtr) + || rec_get_deleted_flag(rec)) { + /* Not found */ + + fprintf(stderr, + "InnoDB: Error A: cannot load foreign constraint %s\n", id); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + mem_heap_free(heap2); + + return(DB_ERROR); + } + + field = rec_get_nth_field(rec, 0, &len); + + /* Check if the id in record is the searched one */ + if (len != ut_strlen(id) || ut_memcmp(id, field, len) != 0) { + + fprintf(stderr, + "InnoDB: Error B: cannot load foreign constraint %s\n", id); + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + mem_heap_free(heap2); + + return(DB_ERROR); + } + + /* Read the table names and the number of columns associated + with the constraint */ + + mem_heap_free(heap2); + + foreign = dict_mem_foreign_create(); + + foreign->n_fields = mach_read_from_4(rec_get_nth_field(rec, 5, &len)); + + ut_a(len == 4); + + foreign->id = mem_heap_alloc(foreign->heap, ut_strlen(id) + 1); + + ut_memcpy(foreign->id, id, ut_strlen(id) + 1); + + field = rec_get_nth_field(rec, 3, &len); + + foreign->foreign_table_name = mem_heap_alloc(foreign->heap, 1 + len); + + ut_memcpy(foreign->foreign_table_name, field, len); + foreign->foreign_table_name[len] = '\0'; + + field = rec_get_nth_field(rec, 4, &len); + + foreign->referenced_table_name = mem_heap_alloc(foreign->heap, 1 + len); + + ut_memcpy(foreign->referenced_table_name, field, len); + foreign->referenced_table_name[len] = '\0'; + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + + dict_load_foreign_cols(id, foreign); + + /* Note that there may already be a foreign constraint object in + the dictionary cache for this constraint: then the following + call only sets the pointers in it to point to the appropriate table + and index objects and frees the newly created object foreign. */ + + err = dict_foreign_add_to_cache(foreign); + + return(err); +} + +/*************************************************************************** +Loads foreign key constraints where the table is either the foreign key +holder or where the table is referenced by a foreign key. Adds these +constraints to the data dictionary. Note that we know that the dictionary +cache already contains all constraints where the other relevant table is +already in the dictionary cache. */ + +ulint +dict_load_foreigns( +/*===============*/ + /* out: DB_SUCCESS or error code */ + char* table_name) /* in: table name */ { - mtr_t mtr; - byte id_buf[8]; btr_pcur_t pcur; mem_heap_t* heap; dtuple_t* tuple; dfield_t* dfield; - dict_index_t* sys_table_ids; - dict_table_t* sys_tables; + dict_index_t* sec_index; + dict_table_t* sys_foreign; rec_t* rec; byte* field; ulint len; - dict_table_t* table; - char* name; + char* id ; + ulint err; + mtr_t mtr; ut_ad(mutex_own(&(dict_sys->mutex))); - /* NOTE that the operation of this function is protected by - the dictionary mutex, and therefore no deadlocks can occur - with other dictionary operations. */ + sys_foreign = dict_table_get_low("SYS_FOREIGN"); + + if (sys_foreign == NULL) { + /* No foreign keys defined yet in this database */ + + fprintf(stderr, + "InnoDB: Error: no foreign key system tables in the database\n"); + + return(DB_ERROR); + } mtr_start(&mtr); - /*---------------------------------------------------*/ - /* Get the secondary index based on ID for table SYS_TABLES */ - sys_tables = dict_sys->sys_tables; - sys_table_ids = dict_table_get_next_index( - dict_table_get_first_index(sys_tables)); + + /* Get the secondary index based on FOR_NAME from table + SYS_FOREIGN */ + + sec_index = dict_table_get_next_index( + dict_table_get_first_index(sys_foreign)); +start_load: heap = mem_heap_create(256); tuple = dtuple_create(heap, 1); dfield = dtuple_get_nth_field(tuple, 0); - /* Write the table id in byte format to id_buf */ - mach_write_to_8(id_buf, table_id); - - dfield_set_data(dfield, id_buf, 8); - dict_index_copy_types(tuple, sys_table_ids, 1); + dfield_set_data(dfield, table_name, ut_strlen(table_name)); + dict_index_copy_types(tuple, sec_index, 1); - btr_pcur_open_on_user_rec(sys_table_ids, tuple, PAGE_CUR_GE, + btr_pcur_open_on_user_rec(sec_index, tuple, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, &mtr); +loop: rec = btr_pcur_get_rec(&pcur); - if (!btr_pcur_is_on_user_rec(&pcur, &mtr) - || rec_get_deleted_flag(rec)) { - /* Not found */ + if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) { + /* End of index */ - btr_pcur_close(&pcur); - mtr_commit(&mtr); - mem_heap_free(heap); - - return(NULL); + goto load_next_index; } - /*---------------------------------------------------*/ - /* Now we have the record in the secondary index containing the - table ID and NAME */ + /* Now we have the record in the secondary index containing a table + name and a foreign constraint ID */ rec = btr_pcur_get_rec(&pcur); field = rec_get_nth_field(rec, 0, &len); - ut_ad(len == 8); - /* Check if the table id in record is the one searched for */ - if (ut_dulint_cmp(table_id, mach_read_from_8(field)) != 0) { + /* Check if the table name in record is the one searched for */ + if (len != ut_strlen(table_name) + || 0 != ut_memcmp(field, table_name, len)) { - btr_pcur_close(&pcur); - mtr_commit(&mtr); - mem_heap_free(heap); - - return(NULL); + goto load_next_index; } - /* Now we get the table name from the record */ + if (rec_get_deleted_flag(rec)) { + + goto next_rec; + } + + /* Now we get a foreign key constraint id */ field = rec_get_nth_field(rec, 1, &len); - name = mem_heap_alloc(heap, len + 1); - ut_memcpy(name, field, len); - name[len] = '\0'; + id = mem_heap_alloc(heap, len + 1); + ut_memcpy(id, field, len); + id[len] = '\0'; - /* Load the table definition to memory */ - table = dict_load_table(name); + btr_pcur_store_position(&pcur, &mtr); - ut_a(table); + mtr_commit(&mtr); + + /* Load the foreign constraint definition to the dictionary cache */ + err = dict_load_foreign(id); + + if (err != DB_SUCCESS) { + btr_pcur_close(&pcur); + mem_heap_free(heap); + + return(err); + } + + mtr_start(&mtr); + + btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr); +next_rec: + btr_pcur_move_to_next_user_rec(&pcur, &mtr); + + goto loop; + +load_next_index: btr_pcur_close(&pcur); mtr_commit(&mtr); mem_heap_free(heap); + + sec_index = dict_table_get_next_index(sec_index); - return(table); + if (sec_index != NULL) { + + mtr_start(&mtr); + + goto start_load; + } + + return(DB_SUCCESS); } diff --git a/innobase/dict/dict0mem.c b/innobase/dict/dict0mem.c index 6947db11aea..57926ab9d2f 100644 --- a/innobase/dict/dict0mem.c +++ b/innobase/dict/dict0mem.c @@ -18,6 +18,7 @@ Created 1/8/1996 Heikki Tuuri #include "dict0dict.h" #include "que0que.h" #include "pars0pars.h" +#include "lock0lock.h" #define DICT_HEAP_SIZE 100 /* initial memory heap size when creating a table or index object */ @@ -63,7 +64,12 @@ dict_mem_table_create( table->cols = mem_heap_alloc(heap, (n_cols + DATA_N_SYS_COLS) * sizeof(dict_col_t)); UT_LIST_INIT(table->indexes); + + table->auto_inc_lock = mem_heap_alloc(heap, lock_get_size()); + UT_LIST_INIT(table->locks); + UT_LIST_INIT(table->foreign_list); + UT_LIST_INIT(table->referenced_list); table->does_not_fit_in_memory = FALSE; @@ -199,6 +205,8 @@ dict_mem_index_create( * sizeof(dict_field_t)); /* The '1 +' above prevents allocation of an empty mem block */ + index->stat_n_diff_key_vals = NULL; + index->cached = FALSE; index->magic_n = DICT_INDEX_MAGIC_N; @@ -206,6 +214,41 @@ dict_mem_index_create( } /************************************************************************** +Creates and initializes a foreign constraint memory object. */ + +dict_foreign_t* +dict_mem_foreign_create(void) +/*=========================*/ + /* out, own: foreign constraint struct */ +{ + dict_foreign_t* foreign; + mem_heap_t* heap; + + heap = mem_heap_create(100); + + foreign = mem_heap_alloc(heap, sizeof(dict_foreign_t)); + + foreign->heap = heap; + + foreign->id = NULL; + + foreign->foreign_table_name = NULL; + foreign->foreign_table = NULL; + foreign->foreign_col_names = NULL; + + foreign->referenced_table_name = NULL; + foreign->referenced_table = NULL; + foreign->referenced_col_names = NULL; + + foreign->n_fields = 0; + + foreign->foreign_index = NULL; + foreign->referenced_index = NULL; + + return(foreign); +} + +/************************************************************************** Adds a field definition to an index. NOTE: does not take a copy of the column name if the field is a column. The memory occupied by the column name may be released only after publishing the index. */ |