📄 dict0dict.c
字号:
return(FALSE);}/*************************************************************************Frees a foreign key struct. */staticvoiddict_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. */staticvoiddict_foreign_remove_from_cache(/*===========================*/ dict_foreign_t* foreign) /* in, own: foreign constraint */{#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(dict_sys->mutex)));#endif /* UNIV_SYNC_DEBUG */ 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 listsof a table. */staticdict_foreign_t*dict_foreign_find(/*==============*/ /* out: foreign constraint */ dict_table_t* table, /* in: table object */ const char* id) /* in: foreign constraint id */{ dict_foreign_t* foreign;#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(dict_sys->mutex)));#endif /* UNIV_SYNC_DEBUG */ 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. */staticdict_index_t*dict_foreign_find_index(/*====================*/ /* out: matching index, NULL if not found */ dict_table_t* table, /* in: table */ const 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 */ ibool check_charsets) /* in: whether to check charsets. only has an effect if types_idx != NULL. */{#ifndef UNIV_HOTBACKUP dict_index_t* index; const 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 (dict_index_get_nth_field(index, i) ->prefix_len != 0) { /* We do not accept column prefix indexes here */ break; } if (0 != innobase_strcasecmp(columns[i], 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), check_charsets)) { break; } } if (i == n_cols) { /* We found a matching index */ return(index); } } index = dict_table_get_next_index(index); } return(NULL);#else /* UNIV_HOTBACKUP */ /* This function depends on MySQL code that is not included in InnoDB Hot Backup builds. Besides, this function should never be called in InnoDB Hot Backup. */ ut_error;#endif /* UNIV_HOTBACKUP */}/**************************************************************************Report an error in a foreign key definition. */staticvoiddict_foreign_error_report_low(/*==========================*/ FILE* file, /* in: output stream */ const char* name) /* in: table name */{ rewind(file); ut_print_timestamp(file); fprintf(file, " Error in foreign key constraint of table %s:\n", name);}/**************************************************************************Report an error in a foreign key definition. */staticvoiddict_foreign_error_report(/*======================*/ FILE* file, /* in: output stream */ dict_foreign_t* fk, /* in: foreign key constraint */ const char* msg) /* in: the error message */{ mutex_enter(&dict_foreign_err_mutex); dict_foreign_error_report_low(file, fk->foreign_table_name); fputs(msg, file); fputs(" Constraint:\n", file); dict_print_info_on_foreign_key_in_create_format(file, NULL, fk, TRUE); putc('\n', file); if (fk->foreign_index) { fputs("The index in the foreign key in table is ", file); ut_print_name(file, NULL, fk->foreign_index->name); fputs("\nSee http://dev.mysql.com/doc/mysql/en/InnoDB_foreign_key_constraints.html\n""for correct foreign key definition.\n", file); } mutex_exit(&dict_foreign_err_mutex);}/**************************************************************************Adds a foreign key constraint object to the dictionary cache. May freethe object if there already is an object with the same identifier in.At least one of the foreign table and the referenced table must alreadybe in the dictionary cache! */ulintdict_foreign_add_to_cache(/*======================*/ /* out: DB_SUCCESS or error code */ dict_foreign_t* foreign, /* in, own: foreign key constraint */ ibool check_charsets) /* in: TRUE=check charset compatibility */{ dict_table_t* for_table; dict_table_t* ref_table; dict_foreign_t* for_in_cache = NULL; dict_index_t* index; ibool added_to_referenced_list= FALSE; FILE* ef = dict_foreign_err_file;#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(dict_sys->mutex)));#endif /* UNIV_SYNC_DEBUG */ 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, (const char**) for_in_cache->referenced_col_names, for_in_cache->n_fields, for_in_cache->foreign_index, check_charsets); if (index == NULL) { dict_foreign_error_report(ef, for_in_cache,"there is no index in referenced table which would contain\n""the columns as the first columns, or the data types in the\n""referenced table do not match to the ones in table."); 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); added_to_referenced_list = TRUE; } if (for_in_cache->foreign_table == NULL && for_table) { index = dict_foreign_find_index(for_table, (const char**) for_in_cache->foreign_col_names, for_in_cache->n_fields, for_in_cache->referenced_index, check_charsets); if (index == NULL) { dict_foreign_error_report(ef, for_in_cache,"there is no index in the table which would contain\n""the columns as the first columns, or the data types in the\n""table do not match to the ones in the referenced table."); if (for_in_cache == foreign) { if (added_to_referenced_list) { UT_LIST_REMOVE(referenced_list, ref_table->referenced_list, for_in_cache); } 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, andonly outside `` or "" quotes. Stops also at '\0'. */const char*dict_scan_to(/*=========*/ /* out: scanned up to this */ const char* ptr, /* in: scan from */ const char* string) /* in: look for this */{ char quote = '\0'; for (; *ptr; ptr++) { if (*ptr == quote) { /* Closing quote character: do not look for starting quote or the keyword. */ quote = '\0'; } else if (quote) { /* Within quotes: do nothing. */ } else if (*ptr == '`' || *ptr == '"') { /* Starting quote: remember the quote character. */ quote = *ptr; } else { /* Outside quotes: look for the keyword. */ ulint i; for (i = 0; string[i]; i++) { if (toupper((int)(unsigned char)(ptr[i])) != toupper((int)(unsigned char) (string[i]))) { goto nomatch; } } break; nomatch: ; } } return(ptr);}/*************************************************************************Accepts a specified string. Comparisons are case-insensitive. */const char*dict_accept(/*========*/ /* out: if string was accepted, the pointer is moved after that, else ptr is returned */ const char* ptr, /* in: scan from this */ const char* string, /* in: accept only this string as the next non-whitespace string */ ibool* success)/* out: TRUE if accepted */{ const char* old_ptr = ptr; const 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));}/*************************************************************************Scans an id. For the lexical definition of an 'id', see the code below.Strips backquotes or double quotes from around the id. */staticconst char*dict_scan_id(/*=========*/ /* out: scanned to */ const char* ptr, /* in: scanned to */ mem_heap_t* heap, /* in: heap where to allocate the id (NULL=id will not be allocated, but it will point to string near ptr) */ const char** id, /* out,own: the id; NULL if no id was scannable */ ibool accept_also_dot) /* in: TRUE if also a dot can appear in a non-quoted id; in a quoted id it can appear always */{ char quote = '\0'; ulint len = 0; const char* s; char* d; ulint id_len; byte* b; *id = NULL; while (isspace(*ptr)) { ptr++; } if (*ptr == '\0') { return(ptr); } if (*ptr == '`' || *ptr == '"') { quote = *ptr++; } s = ptr; if (quote) { for (;;) { if (!*ptr) { /* Syntax error */ return(ptr); } if (*ptr == quote) { ptr++; if (*ptr != quote) { break; } } ptr++; len++; } } else { while (!isspace(*ptr) && *ptr != '(' && *ptr != ')' && (accept_also_dot || *ptr != '.') && *ptr != ',' && *ptr != '\0') { ptr++; } len = ptr - s; } if (quote && heap) { *id = d = mem_heap_alloc(heap, len + 1); while (len--) { if ((*d++ = *s++) == quote) { s++; } } *d++ = 0; ut_a(*s == quote); ut_a(s + 1 == ptr); } else if (heap) { *id = mem_heap_strdupl(heap, s, len); } else { /* no heap given: id will point to source string */ *id = s; } if (heap && !quote) { /* EMS MySQL Manager sometimes adds characters 0xA0 (in latin1, a 'non-breakable space') to the end of a table name. But isspace(0xA0) is not true, which confuses our foreign key parser. After the UTF-8 conversion in ha_innodb.cc, bytes 0xC2 and 0xA0 are at the end of the string. TODO: we should lex the string using thd->charset_info, and my_isspace(). Only after that, convert id names to UTF-8. */ b = (byte*)(*id); id_len = strlen((char*) b); if (id_len >= 3 && b[id_len - 1] == 0xA0 && b[id_len - 2] == 0xC2) { /* Strip the 2 last bytes */ b[id_len - 2] = '\0'; } } return(ptr);}/*************************************************************************Tries to scan a column name. */staticconst char*dict_scan_col(/*==========*/ /* out: scanned to */ const char* ptr, /* in: scanned t
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -