summaryrefslogtreecommitdiff
path: root/innobase/dict/dict0crea.c
diff options
context:
space:
mode:
Diffstat (limited to 'innobase/dict/dict0crea.c')
-rw-r--r--innobase/dict/dict0crea.c229
1 files changed, 229 insertions, 0 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;
+}