/************************************************************************ Add a single foreign key definition to the data dictionary tables in the database. We also generate names to constraints that were not named by the user. A generated constraint has a name of the format databasename/tablename_ibfk_<number>, where the numbers start from 1, and are given locally for this table, that is, the number is not global, as in the old format constraints < 4.0.18 it used to be. */ static ulint dict_create_add_foreign_to_dictionary( /*==================================*/ /* out: error code or DB_SUCCESS */ ulint* id_nr, /* in/out: number to use in id generation; incremented if used */ dict_table_t* table, /* in: table */ dict_foreign_t* foreign,/* in: foreign */ trx_t* trx) /* in: transaction */ { ulint error; ulint i; pars_info_t* info = pars_info_create(); if (foreign->id == NULL) { /* Generate a new constraint id */ ulint namelen = strlen(table->name); char* id = mem_heap_alloc(foreign->heap, namelen + 20); /* no overflow if number < 1e13 */ sprintf(id, "%s_ibfk_%lu", table->name, (ulong) (*id_nr)++); foreign->id = id; } pars_info_add_str_literal(info, "id", foreign->id); pars_info_add_str_literal(info, "for_name", table->name); pars_info_add_str_literal(info, "ref_name", foreign->referenced_table_name); pars_info_add_int4_literal(info, "n_cols", foreign->n_fields + (foreign->type << 24)); error = dict_foreign_eval_sql(info, "PROCEDURE P () IS\n" "BEGIN\n" "INSERT INTO SYS_FOREIGN VALUES" "(:id, :for_name, :ref_name, :n_cols);\n" "END;\n" , table, foreign, trx); if (error != DB_SUCCESS) { return(error); } for (i = 0; i < foreign->n_fields; i++) { error = dict_create_add_foreign_field_to_dictionary( i, table, foreign, trx); if (error != DB_SUCCESS) { return(error); } } error = dict_foreign_eval_sql(NULL, "PROCEDURE P () IS\n" "BEGIN\n" "COMMIT WORK;\n" "END;\n" , table, foreign, trx); return(error); }
/********************************************************************//** Add a single foreign key definition to the data dictionary tables in the database. We also generate names to constraints that were not named by the user. A generated constraint has a name of the format databasename/tablename_ibfk_NUMBER, where the numbers start from 1, and are given locally for this table, that is, the number is not global, as in the old format constraints < 4.0.18 it used to be. @return error code or DB_SUCCESS */ static ulint dict_create_add_foreign_to_dictionary( /*==================================*/ ulint* id_nr, /*!< in/out: number to use in id generation; incremented if used */ dict_table_t* table, /*!< in: table */ dict_foreign_t* foreign,/*!< in: foreign */ trx_t* trx) /*!< in: transaction */ { ulint error; ulint i; pars_info_t* info; ut_ad(mutex_own(&(dict_sys->mutex))); if (foreign->id == NULL) { /* Generate a new constraint id */ ulint namelen = strlen(table->name); char* id = mem_heap_alloc(foreign->heap, namelen + 20); if (row_is_mysql_tmp_table_name(table->name)) { sprintf(id, "%s_ibfk_%lu", table->name, (ulong) (*id_nr)++); } else { char table_name[MAX_TABLE_NAME_LEN + 20] = ""; uint errors = 0; strncpy(table_name, table->name, MAX_TABLE_NAME_LEN + 20); innobase_convert_to_system_charset( strchr(table_name, '/') + 1, strchr(table->name, '/') + 1, MAX_TABLE_NAME_LEN, &errors); if (errors) { strncpy(table_name, table->name, MAX_TABLE_NAME_LEN + 20); } sprintf(id, "%s_ibfk_%lu", table_name, (ulong) (*id_nr)++); if (innobase_check_identifier_length( strchr(id,'/') + 1)) { return(DB_IDENTIFIER_TOO_LONG); } } foreign->id = id; } info = pars_info_create(); pars_info_add_str_literal(info, "id", foreign->id); pars_info_add_str_literal(info, "for_name", table->name); pars_info_add_str_literal(info, "ref_name", foreign->referenced_table_name); pars_info_add_int4_literal(info, "n_cols", foreign->n_fields + (foreign->type << 24)); error = dict_foreign_eval_sql(info, "PROCEDURE P () IS\n" "BEGIN\n" "INSERT INTO SYS_FOREIGN VALUES" "(:id, :for_name, :ref_name, :n_cols);\n" "END;\n" , table, foreign, trx); if (error != DB_SUCCESS) { return(error); } for (i = 0; i < foreign->n_fields; i++) { error = dict_create_add_foreign_field_to_dictionary( i, table, foreign, trx); if (error != DB_SUCCESS) { return(error); } } error = dict_foreign_eval_sql(NULL, "PROCEDURE P () IS\n" "BEGIN\n" "COMMIT WORK;\n" "END;\n" , table, foreign, trx); if (error == DB_SUCCESS) { if (foreign->foreign_table != NULL) { ib_rbt_t* rbt = foreign->foreign_table->foreign_rbt; if (rbt == NULL) { rbt = dict_table_init_foreign_rbt( foreign->foreign_table); } else { rbt_delete(rbt, foreign->id); } rbt_insert(rbt, foreign->id, &foreign); } if (foreign->referenced_table != NULL) { ib_rbt_t* rbt = foreign->referenced_table->referenced_rbt; if (rbt == NULL) { rbt = dict_table_init_referenced_rbt( foreign->referenced_table); } else { rbt_delete(rbt, foreign->id); } rbt_insert(rbt, foreign->id, &foreign); } } return(error); }