diff options
Diffstat (limited to 'storage/xtradb')
34 files changed, 1245 insertions, 350 deletions
diff --git a/storage/xtradb/api/api0api.cc b/storage/xtradb/api/api0api.cc index 8769fc47166..0fe21423232 100644 --- a/storage/xtradb/api/api0api.cc +++ b/storage/xtradb/api/api0api.cc @@ -595,6 +595,21 @@ ib_trx_begin( return(static_cast<ib_trx_t>(trx)); } + +/*****************************************************************//** +Check if transaction is read_only +@return transaction read_only status */ +UNIV_INTERN +ib_u32_t +ib_trx_read_only( +/*=============*/ + ib_trx_t ib_trx) /*!< in: trx handle */ +{ + trx_t* trx = (trx_t*) ib_trx; + + return(trx->read_only); +} + /*****************************************************************//** Get the transaction's state. @return transaction state */ diff --git a/storage/xtradb/buf/buf0buf.cc b/storage/xtradb/buf/buf0buf.cc index 361b0783482..cf63bab0d5f 100644 --- a/storage/xtradb/buf/buf0buf.cc +++ b/storage/xtradb/buf/buf0buf.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. Copyright (c) 2013, 2015, MariaDB Corporation. All Rights Reserved. @@ -564,6 +564,79 @@ buf_page_is_zeroes( return(true); } +/** Checks if the page is in crc32 checksum format. +@param[in] read_buf database page +@param[in] checksum_field1 new checksum field +@param[in] checksum_field2 old checksum field +@return true if the page is in crc32 checksum format */ +UNIV_INLINE +bool +buf_page_is_checksum_valid_crc32( + const byte* read_buf, + ulint checksum_field1, + ulint checksum_field2) +{ + ib_uint32_t crc32 = buf_calc_page_crc32(read_buf); + + return(checksum_field1 == crc32 && checksum_field2 == crc32); +} + +/** Checks if the page is in innodb checksum format. +@param[in] read_buf database page +@param[in] checksum_field1 new checksum field +@param[in] checksum_field2 old checksum field +@return true if the page is in innodb checksum format */ +UNIV_INLINE +bool +buf_page_is_checksum_valid_innodb( + const byte* read_buf, + ulint checksum_field1, + ulint checksum_field2) +{ + /* There are 2 valid formulas for + checksum_field2 (old checksum field) which algo=innodb could have + written to the page: + + 1. Very old versions of InnoDB only stored 8 byte lsn to the + start and the end of the page. + + 2. Newer InnoDB versions store the old formula checksum + (buf_calc_page_old_checksum()). */ + + if (checksum_field2 != mach_read_from_4(read_buf + FIL_PAGE_LSN) + && checksum_field2 != buf_calc_page_old_checksum(read_buf)) { + return(false); + } + + /* old field is fine, check the new field */ + + /* InnoDB versions < 4.0.14 and < 4.1.1 stored the space id + (always equal to 0), to FIL_PAGE_SPACE_OR_CHKSUM */ + + if (checksum_field1 != 0 + && checksum_field1 != buf_calc_page_new_checksum(read_buf)) { + return(false); + } + + return(true); +} + +/** Checks if the page is in none checksum format. +@param[in] read_buf database page +@param[in] checksum_field1 new checksum field +@param[in] checksum_field2 old checksum field +@return true if the page is in none checksum format */ +UNIV_INLINE +bool +buf_page_is_checksum_valid_none( + const byte* read_buf, + ulint checksum_field1, + ulint checksum_field2) +{ + return(checksum_field1 == checksum_field2 + && checksum_field1 == BUF_NO_CHECKSUM_MAGIC); +} + /********************************************************************//** Checks if a page is corrupt. @return TRUE if corrupted */ @@ -580,8 +653,6 @@ buf_page_is_corrupted( ulint page_encrypted = fil_page_is_encrypted(read_buf); ulint checksum_field1; ulint checksum_field2; - ibool crc32_inited = FALSE; - ib_uint32_t crc32 = ULINT32_UNDEFINED; if (!page_encrypted && !zip_size && memcmp(read_buf + FIL_PAGE_LSN + 4, @@ -664,148 +735,121 @@ buf_page_is_corrupted( return(FALSE); } - switch ((srv_checksum_algorithm_t) srv_checksum_algorithm) { - case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32: - - crc32 = buf_calc_page_crc32(read_buf); - - return(checksum_field1 != crc32 || checksum_field2 != crc32); - - case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB: - - return(checksum_field1 - != buf_calc_page_new_checksum(read_buf) - || checksum_field2 - != buf_calc_page_old_checksum(read_buf)); - - case SRV_CHECKSUM_ALGORITHM_STRICT_NONE: + DBUG_EXECUTE_IF("buf_page_is_corrupt_failure", return(TRUE); ); - return(checksum_field1 != BUF_NO_CHECKSUM_MAGIC - || checksum_field2 != BUF_NO_CHECKSUM_MAGIC); + ulint page_no = mach_read_from_4(read_buf + FIL_PAGE_OFFSET); + ulint space_id = mach_read_from_4(read_buf + FIL_PAGE_SPACE_ID); + const srv_checksum_algorithm_t curr_algo = + static_cast<srv_checksum_algorithm_t>(srv_checksum_algorithm); + switch (curr_algo) { case SRV_CHECKSUM_ALGORITHM_CRC32: - case SRV_CHECKSUM_ALGORITHM_INNODB: - /* There are 3 valid formulas for - checksum_field2 (old checksum field): - - 1. Very old versions of InnoDB only stored 8 byte lsn to the - start and the end of the page. - - 2. InnoDB versions before MySQL 5.6.3 store the old formula - checksum (buf_calc_page_old_checksum()). - - 3. InnoDB versions 5.6.3 and newer with - innodb_checksum_algorithm=strict_crc32|crc32 store CRC32. */ - - /* since innodb_checksum_algorithm is not strict_* allow - any of the algos to match for the old field */ - - if (checksum_field2 - != mach_read_from_4(read_buf + FIL_PAGE_LSN) - && checksum_field2 != BUF_NO_CHECKSUM_MAGIC) { - - /* The checksum does not match any of the - fast to check. First check the selected algorithm - for writing checksums because we assume that the - chance of it matching is higher. */ - - if (srv_checksum_algorithm - == SRV_CHECKSUM_ALGORITHM_CRC32) { - - crc32 = buf_calc_page_crc32(read_buf); - crc32_inited = TRUE; - - if (checksum_field2 != crc32 - && checksum_field2 - != buf_calc_page_old_checksum(read_buf)) { + case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32: - return(TRUE); - } - } else { - ut_ad(srv_checksum_algorithm - == SRV_CHECKSUM_ALGORITHM_INNODB); + if (buf_page_is_checksum_valid_crc32(read_buf, + checksum_field1, checksum_field2)) { + return(FALSE); + } - if (checksum_field2 - != buf_calc_page_old_checksum(read_buf)) { + if (buf_page_is_checksum_valid_none(read_buf, + checksum_field1, checksum_field2)) { + if (curr_algo + == SRV_CHECKSUM_ALGORITHM_STRICT_CRC32) { + page_warn_strict_checksum( + curr_algo, + SRV_CHECKSUM_ALGORITHM_NONE, + space_id, page_no); + } - crc32 = buf_calc_page_crc32(read_buf); - crc32_inited = TRUE; + return(FALSE); + } - if (checksum_field2 != crc32) { - return(TRUE); - } - } + if (buf_page_is_checksum_valid_innodb(read_buf, + checksum_field1, checksum_field2)) { + if (curr_algo + == SRV_CHECKSUM_ALGORITHM_STRICT_CRC32) { + page_warn_strict_checksum( + curr_algo, + SRV_CHECKSUM_ALGORITHM_INNODB, + space_id, page_no); } - } - /* old field is fine, check the new field */ + return(FALSE); + } - /* InnoDB versions < 4.0.14 and < 4.1.1 stored the space id - (always equal to 0), to FIL_PAGE_SPACE_OR_CHKSUM */ + return(TRUE); - if (checksum_field1 != 0 - && checksum_field1 != BUF_NO_CHECKSUM_MAGIC) { + case SRV_CHECKSUM_ALGORITHM_INNODB: + case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB: - /* The checksum does not match any of the - fast to check. First check the selected algorithm - for writing checksums because we assume that the - chance of it matching is higher. */ + if (buf_page_is_checksum_valid_innodb(read_buf, + checksum_field1, checksum_field2)) { + return(FALSE); + } - if (srv_checksum_algorithm - == SRV_CHECKSUM_ALGORITHM_CRC32) { + if (buf_page_is_checksum_valid_none(read_buf, + checksum_field1, checksum_field2)) { + if (curr_algo + == SRV_CHECKSUM_ALGORITHM_STRICT_INNODB) { + page_warn_strict_checksum( + curr_algo, + SRV_CHECKSUM_ALGORITHM_NONE, + space_id, page_no); + } - if (!crc32_inited) { - crc32 = buf_calc_page_crc32(read_buf); - crc32_inited = TRUE; - } + return(FALSE); + } - if (checksum_field1 != crc32 - && checksum_field1 - != buf_calc_page_new_checksum(read_buf)) { + if (buf_page_is_checksum_valid_crc32(read_buf, + checksum_field1, checksum_field2)) { + if (curr_algo + == SRV_CHECKSUM_ALGORITHM_STRICT_INNODB) { + page_warn_strict_checksum( + curr_algo, + SRV_CHECKSUM_ALGORITHM_CRC32, + space_id, page_no); + } - return(TRUE); - } - } else { - ut_ad(srv_checksum_algorithm - == SRV_CHECKSUM_ALGORITHM_INNODB); + return(FALSE); + } - if (checksum_field1 - != buf_calc_page_new_checksum(read_buf)) { + return(TRUE); - if (!crc32_inited) { - crc32 = buf_calc_page_crc32( - read_buf); - crc32_inited = TRUE; - } + case SRV_CHECKSUM_ALGORITHM_STRICT_NONE: - if (checksum_field1 != crc32) { - return(TRUE); - } - } - } + if (buf_page_is_checksum_valid_none(read_buf, + checksum_field1, checksum_field2)) { + return(FALSE); } - /* If CRC32 is stored in at least one of the fields, then the - other field must also be CRC32 */ - if (crc32_inited - && ((checksum_field1 == crc32 - && checksum_field2 != crc32) - || (checksum_field1 != crc32 - && checksum_field2 == crc32))) { + if (buf_page_is_checksum_valid_crc32(read_buf, + checksum_field1, checksum_field2)) { + page_warn_strict_checksum( + curr_algo, + SRV_CHECKSUM_ALGORITHM_CRC32, + space_id, page_no); + return(FALSE); + } - return(TRUE); + if (buf_page_is_checksum_valid_innodb(read_buf, + checksum_field1, checksum_field2)) { + page_warn_strict_checksum( + curr_algo, + SRV_CHECKSUM_ALGORITHM_INNODB, + space_id, page_no); + return(FALSE); } - break; + return(TRUE); + case SRV_CHECKSUM_ALGORITHM_NONE: /* should have returned FALSE earlier */ - ut_error; + break; /* no default so the compiler will emit a warning if new enum is added and not handled here */ } - DBUG_EXECUTE_IF("buf_page_is_corrupt_failure", return(TRUE); ); - + ut_error; return(FALSE); } @@ -1817,6 +1861,9 @@ page_found: goto page_found; } + /* The maximum number of purge threads should never exceed + BUF_POOL_WATCH_SIZE. So there is no way for purge thread + instance to hold a watch when setting another watch. */ for (i = 0; i < BUF_POOL_WATCH_SIZE; i++) { bpage = &buf_pool->watch[i]; diff --git a/storage/xtradb/buf/buf0checksum.cc b/storage/xtradb/buf/buf0checksum.cc index 451fef2f82e..01b646a78e0 100644 --- a/storage/xtradb/buf/buf0checksum.cc +++ b/storage/xtradb/buf/buf0checksum.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -27,11 +27,13 @@ Created Aug 11, 2011 Vasil Dimov #include "fil0fil.h" /* FIL_* */ #include "ut0crc32.h" /* ut_crc32() */ #include "ut0rnd.h" /* ut_fold_binary() */ +#include "buf0types.h" #ifndef UNIV_INNOCHECKSUM #include "srv0srv.h" /* SRV_CHECKSUM_* */ -#include "buf0types.h" + +#endif /* !UNIV_INNOCHECKSUM */ /** the macro MYSQL_SYSVAR_ENUM() requires "long unsigned int" and if we use srv_checksum_algorithm_t here then we get a compiler error: @@ -39,8 +41,6 @@ ha_innodb.cc:12251: error: cannot convert 'srv_checksum_algorithm_t*' to 'long unsigned int*' in initialization */ UNIV_INTERN ulong srv_checksum_algorithm = SRV_CHECKSUM_ALGORITHM_INNODB; -#endif /* !UNIV_INNOCHECKSUM */ - /********************************************************************//** Calculates a page CRC32 which is stored to the page when it is written to a file. Note that we must be careful to calculate the same value on @@ -127,8 +127,6 @@ buf_calc_page_old_checksum( return(checksum); } -#ifndef UNIV_INNOCHECKSUM - /********************************************************************//** Return a printable string describing the checksum algorithm. @return algorithm name */ @@ -140,18 +138,19 @@ buf_checksum_algorithm_name( { switch (algo) { case SRV_CHECKSUM_ALGORITHM_CRC32: - case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32: return("crc32"); + case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32: + return("strict_crc32"); case SRV_CHECKSUM_ALGORITHM_INNODB: - case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB: return("innodb"); + case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB: + return("strict_innodb"); case SRV_CHECKSUM_ALGORITHM_NONE: - case SRV_CHECKSUM_ALGORITHM_STRICT_NONE: return("none"); + case SRV_CHECKSUM_ALGORITHM_STRICT_NONE: + return("strict_none"); } ut_error; return(NULL); } - -#endif /* !UNIV_INNOCHECKSUM */ diff --git a/storage/xtradb/buf/buf0flu.cc b/storage/xtradb/buf/buf0flu.cc index 6443043310b..c891e53381a 100644 --- a/storage/xtradb/buf/buf0flu.cc +++ b/storage/xtradb/buf/buf0flu.cc @@ -1,8 +1,8 @@ /***************************************************************************** -Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2013, 2014, SkySQL Ab. All Rights Reserved. -Copyright (c) 2013, 2014, Fusion-io. All Rights Reserved. +Copyright (c) 1995, 2013, Oracle and/or its affiliates +Copyright (c) 2013, 2015, SkySQL Ab +Copyright (c) 2013, 2014, Fusion-io This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -932,11 +932,11 @@ buf_flush_write_block_low( case BUF_BLOCK_ZIP_DIRTY: frame = bpage->zip.data; - ut_a(page_zip_verify_checksum(frame, zip_size)); - mach_write_to_8(frame + FIL_PAGE_LSN, bpage->newest_modification); memset(frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, 0, 8); + + ut_a(page_zip_verify_checksum(frame, zip_size)); break; case BUF_BLOCK_FILE_PAGE: frame = bpage->zip.data; diff --git a/storage/xtradb/dict/dict0crea.cc b/storage/xtradb/dict/dict0crea.cc index 36a30cb75b7..fec4e27f058 100644 --- a/storage/xtradb/dict/dict0crea.cc +++ b/storage/xtradb/dict/dict0crea.cc @@ -1566,12 +1566,111 @@ dict_create_add_foreign_field_to_dictionary( } /********************************************************************//** +Construct foreign key constraint defintion from data dictionary information. +*/ +UNIV_INTERN +char* +dict_foreign_def_get( +/*=================*/ + dict_foreign_t* foreign,/*!< in: foreign */ + trx_t* trx) /*!< in: trx */ +{ + char* fk_def = (char *)mem_heap_alloc(foreign->heap, 4*1024); + const char* tbname; + char tablebuf[MAX_TABLE_NAME_LEN + 1] = ""; + int i; + char* bufend; + + tbname = dict_remove_db_name(foreign->id); + bufend = innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN, + tbname, strlen(tbname), trx->mysql_thd, FALSE); + tablebuf[bufend - tablebuf] = '\0'; + + sprintf(fk_def, + (char *)"CONSTRAINT %s FOREIGN KEY (", (char *)tablebuf); + + for(i = 0; i < foreign->n_fields; i++) { + char buf[MAX_TABLE_NAME_LEN + 1] = ""; + innobase_convert_name(buf, MAX_TABLE_NAME_LEN, + foreign->foreign_col_names[i], + strlen(foreign->foreign_col_names[i]), + trx->mysql_thd, FALSE); + strcat(fk_def, buf); + if (i < foreign->n_fields-1) { + strcat(fk_def, (char *)","); + } + } + + strcat(fk_def,(char *)") REFERENCES "); + + bufend = innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN, + foreign->referenced_table_name, + strlen(foreign->referenced_table_name), + trx->mysql_thd, TRUE); + tablebuf[bufend - tablebuf] = '\0'; + + strcat(fk_def, tablebuf); + strcat(fk_def, " ("); + + for(i = 0; i < foreign->n_fields; i++) { + char buf[MAX_TABLE_NAME_LEN + 1] = ""; + bufend = innobase_convert_name(buf, MAX_TABLE_NAME_LEN, + foreign->referenced_col_names[i], + strlen(foreign->referenced_col_names[i]), + trx->mysql_thd, FALSE); + buf[bufend - buf] = '\0'; + strcat(fk_def, buf); + if (i < foreign->n_fields-1) { + strcat(fk_def, (char *)","); + } + } + strcat(fk_def, (char *)")"); + + return fk_def; +} + +/********************************************************************//** +Convert foreign key column names from data dictionary to SQL-layer. +*/ +static +void +dict_foreign_def_get_fields( +/*========================*/ + dict_foreign_t* foreign,/*!< in: foreign */ + trx_t* trx, /*!< in: trx */ + char** field, /*!< out: foreign column */ + char** field2, /*!< out: referenced column */ + int col_no) /*!< in: column number */ +{ + char* bufend; + char* fieldbuf = (char *)mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1); + char* fieldbuf2 = (char *)mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1); + + bufend = innobase_convert_name(fieldbuf, MAX_TABLE_NAME_LEN, + foreign->foreign_col_names[col_no], + strlen(foreign->foreign_col_names[col_no]), + trx->mysql_thd, FALSE); + + fieldbuf[bufend - fieldbuf] = '\0'; + + bufend = innobase_convert_name(fieldbuf2, MAX_TABLE_NAME_LEN, + foreign->referenced_col_names[col_no], + strlen(foreign->referenced_col_names[col_no]), + trx->mysql_thd, FALSE); + + fieldbuf2[bufend - fieldbuf2] = '\0'; + *field = fieldbuf; + *field2 = fieldbuf2; +} + +/********************************************************************//** Add a foreign key definition to the data dictionary tables. @return error code or DB_SUCCESS */ UNIV_INTERN dberr_t dict_create_add_foreign_to_dictionary( /*==================================*/ + dict_table_t* table, const char* name, /*!< in: table name */ const dict_foreign_t* foreign,/*!< in: foreign key */ trx_t* trx) /*!< in/out: dictionary transaction */ @@ -1598,6 +1697,28 @@ dict_create_add_foreign_to_dictionary( , name, foreign->id, trx); if (error != DB_SUCCESS) { + if (error == DB_DUPLICATE_KEY) { + char buf[MAX_TABLE_NAME_LEN + 1] = ""; + char tablename[MAX_TABLE_NAME_LEN + 1] = ""; + char* fk_def; + + innobase_convert_name(tablename, MAX_TABLE_NAME_LEN, + table->name, strlen(table->name), + trx->mysql_thd, TRUE); + + innobase_convert_name(buf, MAX_TABLE_NAME_LEN, + foreign->id, strlen(foreign->id), trx->mysql_thd, FALSE); + + fk_def = dict_foreign_def_get((dict_foreign_t*)foreign, trx); + + ib_push_warning(trx, error, + "Create or Alter table %s with foreign key constraint" + " failed. Foreign key constraint %s" + " already exists on data dictionary." + " Foreign key constraint names need to be unique in database." + " Error in foreign key definition: %s.", + tablename, buf, fk_def); + } return(error); } @@ -1607,6 +1728,26 @@ dict_create_add_foreign_to_dictionary( i, name, foreign, trx); if (error != DB_SUCCESS) { + char buf[MAX_TABLE_NAME_LEN + 1] = ""; + char tablename[MAX_TABLE_NAME_LEN + 1] = ""; + char* field=NULL; + char* field2=NULL; + char* fk_def; + + innobase_convert_name(tablename, MAX_TABLE_NAME_LEN, + table->name, strlen(table->name), + trx->mysql_thd, TRUE); + innobase_convert_name(buf, MAX_TABLE_NAME_LEN, + foreign->id, strlen(foreign->id), trx->mysql_thd, FALSE); + fk_def = dict_foreign_def_get((dict_foreign_t*)foreign, trx); + dict_foreign_def_get_fields((dict_foreign_t*)foreign, trx, &field, &field2, i); + + ib_push_warning(trx, error, + "Create or Alter table %s with foreign key constraint" + " failed. Error adding foreign key constraint name %s" + " fields %s or %s to the dictionary." + " Error in foreign key definition: %s.", + tablename, buf, i+1, fk_def); return(error); } @@ -1653,7 +1794,7 @@ dict_create_add_foreigns_to_dictionary( foreign = *it; ut_ad(foreign->id != NULL); - error = dict_create_add_foreign_to_dictionary(table->name, + error = dict_create_add_foreign_to_dictionary((dict_table_t*)table, table->name, foreign, trx); if (error != DB_SUCCESS) { diff --git a/storage/xtradb/dict/dict0dict.cc b/storage/xtradb/dict/dict0dict.cc index 811d737e6bf..0e1906a1827 100644 --- a/storage/xtradb/dict/dict0dict.cc +++ b/storage/xtradb/dict/dict0dict.cc @@ -3280,6 +3280,11 @@ dict_index_build_internal_fts( } /*====================== FOREIGN KEY PROCESSING ========================*/ +#define DB_FOREIGN_KEY_IS_PREFIX_INDEX 200 +#define DB_FOREIGN_KEY_COL_NOT_NULL 201 +#define DB_FOREIGN_KEY_COLS_NOT_EQUAL 202 +#define DB_FOREIGN_KEY_INDEX_NOT_FOUND 203 + /*********************************************************************//** Checks if a table is referenced by foreign keys. @return TRUE if table is referenced by a foreign key */ @@ -3434,15 +3439,26 @@ dict_foreign_find_index( /*!< in: whether to check charsets. only has an effect if types_idx != NULL */ - ulint check_null) + ulint check_null, /*!< in: nonzero if none of the columns must be declared NOT NULL */ + ulint* error, /*!< out: error code */ + ulint* err_col_no, + /*!< out: column number where + error happened */ + dict_index_t** err_index) + /*!< out: index where error + happened */ { dict_index_t* index; ut_ad(mutex_own(&dict_sys->mutex)); + if (error) { + *error = DB_FOREIGN_KEY_INDEX_NOT_FOUND; + } + index = dict_table_get_first_index(table); while (index != NULL) { @@ -3452,7 +3468,12 @@ dict_foreign_find_index( && dict_foreign_qualify_index( table, col_names, columns, n_cols, index, types_idx, - check_charsets, check_null)) { + check_charsets, check_null, + error, err_col_no,err_index)) { + if (error) { + *error = DB_SUCCESS; + } + return(index); } @@ -3481,7 +3502,7 @@ wsrep_dict_foreign_find_index( { return dict_foreign_find_index( table, col_names, columns, n_cols, types_idx, check_charsets, - check_null); + check_null, NULL, NULL, NULL); } #endif /* WITH_WSREP */ /**********************************************************************//** @@ -3583,7 +3604,7 @@ dict_foreign_add_to_cache( ref_table, NULL, for_in_cache->referenced_col_names, for_in_cache->n_fields, for_in_cache->foreign_index, - check_charsets, false); + check_charsets, false, NULL, NULL, NULL); if (index == NULL && !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) { @@ -3615,6 +3636,10 @@ dict_foreign_add_to_cache( } if (for_table && !for_in_cache->foreign_table) { + ulint index_error; + ulint err_col; + dict_index_t *err_index=NULL; + index = dict_foreign_find_index( for_table, col_names, for_in_cache->foreign_col_names, @@ -3622,7 +3647,8 @@ dict_foreign_add_to_cache( for_in_cache->referenced_index, check_charsets, for_in_cache->type & (DICT_FOREIGN_ON_DELETE_SET_NULL - | DICT_FOREIGN_ON_UPDATE_SET_NULL)); + | DICT_FOREIGN_ON_UPDATE_SET_NULL), + &index_error, &err_col, &err_index); if (index == NULL && !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) { @@ -4282,6 +4308,8 @@ static void dict_foreign_report_syntax_err( /*===========================*/ + const char* fmt, /*!< in: syntax err msg */ + const char* oper, /*!< in: operation */ const char* name, /*!< in: table name */ const char* start_of_latest_foreign, /*!< in: start of the foreign key clause @@ -4294,12 +4322,102 @@ dict_foreign_report_syntax_err( mutex_enter(&dict_foreign_err_mutex); dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\nSyntax error close to:\n%s\n", - start_of_latest_foreign, ptr); + fprintf(ef, fmt, oper, name, start_of_latest_foreign, ptr); mutex_exit(&dict_foreign_err_mutex); } /*********************************************************************//** +Push warning message to SQL-layer based on foreign key constraint +index match error. */ +static +void +dict_foreign_push_index_error( +/*==========================*/ + trx_t* trx, /*!< in: trx */ + const char* operation, /*!< in: operation create or alter + */ + const char* create_name, /*!< in: table name in create or + alter table */ + const char* latest_foreign, /*!< in: start of latest foreign key + constraint name */ + const char** columns, /*!< in: foreign key columns */ + ulint index_error, /*!< in: error code */ + ulint err_col, /*!< in: column where error happened + */ + dict_index_t* err_index, /*!< in: index where error happened + */ + dict_table_t* table, /*!< in: table */ + FILE* ef) /*!< in: output stream */ +{ + switch (index_error) { + case DB_FOREIGN_KEY_INDEX_NOT_FOUND: { + fprintf(ef, + "%s table '%s' with foreign key constraint" + " failed. There is no index in the referenced" + " table where the referenced columns appear" + " as the first columns. Error close to %s.\n", + operation, create_name, latest_foreign); + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table '%s' with foreign key constraint" + " failed. There is no index in the referenced" + " table where the referenced columns appear" + " as the first columns. Error close to %s.", + operation, create_name, latest_foreign); + break; + } + case DB_FOREIGN_KEY_IS_PREFIX_INDEX: { + fprintf(ef, + "%s table '%s' with foreign key constraint" + " failed. There is only prefix index in the referenced" + " table where the referenced columns appear" + " as the first columns. Error close to %s.\n", + operation, create_name, latest_foreign); + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table '%s' with foreign key constraint" + " failed. There is only prefix index in the referenced" + " table where the referenced columns appear" + " as the first columns. Error close to %s.", + operation, create_name, latest_foreign); + break; + } + case DB_FOREIGN_KEY_COL_NOT_NULL: { + fprintf(ef, + "%s table %s with foreign key constraint" + " failed. You have defined a SET NULL condition but " + "field %s on index is defined as NOT NULL close to %s\n", + operation, create_name, columns[err_col], latest_foreign); + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. You have defined a SET NULL condition but " + "field %s on index is defined as NOT NULL close to %s", + operation, create_name, columns[err_col], latest_foreign); + break; + } + case DB_FOREIGN_KEY_COLS_NOT_EQUAL: { + dict_field_t* field; + const char* col_name; + field = dict_index_get_nth_field(err_index, err_col); + + col_name = dict_table_get_col_name( + table, dict_col_get_no(field->col)); + fprintf(ef, + "%s table %s with foreign key constraint" + " failed. Field type or character set for column %s " + "does not mach referenced column %s close to %s\n", + operation, create_name, columns[err_col], col_name, latest_foreign); + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Field type or character set for column %s " + "does not mach referenced column %s close to %s", + operation, create_name, columns[err_col], col_name, latest_foreign); + break; + } + default: + ut_error; + } +} + +/*********************************************************************//** 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 @@ -4327,16 +4445,21 @@ dict_create_foreign_constraints_low( DB_CANNOT_ADD_CONSTRAINT if any foreign keys are found. */ { - dict_table_t* table; - dict_table_t* referenced_table; - dict_table_t* table_to_alter; + dict_table_t* table = NULL; + dict_table_t* referenced_table = NULL; + dict_table_t* table_to_alter = NULL; + dict_table_t* table_to_create = NULL; ulint highest_id_so_far = 0; ulint number = 1; - dict_index_t* index; - dict_foreign_t* foreign; + dict_index_t* index = NULL; + dict_foreign_t* foreign = NULL; const char* ptr = sql_string; const char* start_of_latest_foreign = sql_string; + const char* start_of_latest_set = NULL; FILE* ef = dict_foreign_err_file; + ulint index_error = DB_SUCCESS; + dict_index_t* err_index = NULL; + ulint err_col; const char* constraint_name; ibool success; dberr_t error; @@ -4349,37 +4472,80 @@ dict_create_foreign_constraints_low( ulint n_on_updates; const dict_col_t*columns[500]; const char* column_names[500]; + const char* ref_column_names[500]; const char* referenced_table_name; dict_foreign_set local_fk_set; dict_foreign_set_free local_fk_set_free(local_fk_set); + const char* create_table_name; + const char* orig; + char create_name[MAX_TABLE_NAME_LEN + 1]; + char operation[8]; ut_ad(!srv_read_only_mode); ut_ad(mutex_own(&(dict_sys->mutex))); table = dict_table_get_low(name); + /* First check if we are actually doing an ALTER TABLE, and in that + case look for the table being altered */ + orig = ptr; + ptr = dict_accept(cs, ptr, "ALTER", &success); + + strcpy((char *)operation, success ? "Alter " : "Create "); + + if (!success) { + orig = ptr; + ptr = dict_scan_to(ptr, "CREATE"); + ptr = dict_scan_to(ptr, "TABLE"); + ptr = dict_accept(cs, ptr, "TABLE", &success); + + if (success) { + ptr = dict_scan_table_name(cs, ptr, &table_to_create, name, + &success, heap, &create_table_name); + } + + if (success) { + char *bufend; + bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN, + create_table_name, strlen(create_table_name), + trx->mysql_thd, TRUE); + create_name[bufend-create_name]='\0'; + ptr = orig; + } else { + char *bufend; + ptr = orig; + bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN, + name, strlen(name), trx->mysql_thd, TRUE); + create_name[bufend-create_name]='\0'; + } + + goto loop; + } if (table == NULL) { mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, - "Cannot find the table in the internal" - " data dictionary of InnoDB.\n" - "Create table statement:\n%s\n", sql_string); + dict_foreign_error_report_low(ef, create_name); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, "%s table %s with foreign key constraint" + " failed. Table %s not found from data dictionary." + " Error close to %s.\n", + operation, create_name, create_name, start_of_latest_foreign); mutex_exit(&dict_foreign_err_mutex); + ib_push_warning(trx, DB_ERROR, + "%s table %s with foreign key constraint" + " failed. Table %s not found from data dictionary." + " Error close to %s.", + operation, create_name, create_name, start_of_latest_foreign); return(DB_ERROR); } - /* First check if we are actually doing an ALTER TABLE, and in that - case look for the table being altered */ - - ptr = dict_accept(cs, ptr, "ALTER", &success); - + /* If not alter table jump to loop */ if (!success) { goto loop; } + orig = ptr; ptr = dict_accept(cs, ptr, "TABLE", &success); if (!success) { @@ -4389,13 +4555,40 @@ dict_create_foreign_constraints_low( /* We are doing an ALTER TABLE: scan the table name we are altering */ + orig = ptr; ptr = dict_scan_table_name(cs, ptr, &table_to_alter, name, &success, heap, &referenced_table_name); + + if (table_to_alter) { + char *bufend; + bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN, + table_to_alter->name, strlen(table_to_alter->name), + trx->mysql_thd, TRUE); + create_name[bufend-create_name]='\0'; + } else { + char *bufend; + bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN, + referenced_table_name, strlen(referenced_table_name), + trx->mysql_thd, TRUE); + create_name[bufend-create_name]='\0'; + + } + if (!success) { - fprintf(stderr, - "InnoDB: Error: could not find" - " the table being ALTERED in:\n%s\n", - sql_string); + mutex_enter(&dict_foreign_err_mutex); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%s table %s with foreign key constraint" + " failed. Table %s not found from data dictionary." + " Error close to %s.\n", + operation, create_name, create_name, orig); + mutex_exit(&dict_foreign_err_mutex); + + ib_push_warning(trx, DB_ERROR, + "%s table %s with foreign key constraint" + " failed. Table %s not found from data dictionary." + " Error close to %s.", + operation, create_name, create_name, orig); return(DB_ERROR); } @@ -4432,6 +4625,7 @@ loop: of the constraint to system tables. */ ptr = ptr1; + orig = ptr; ptr = dict_accept(cs, ptr, "CONSTRAINT", &success); ut_a(success); @@ -4462,6 +4656,19 @@ loop: if so, immediately reject the command if the table is a temporary one. For now, this kludge will work. */ if (reject_fks && !local_fk_set.empty()) { + mutex_enter(&dict_foreign_err_mutex); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, "%s table %s with foreign key constraint" + " failed. Temporary tables can't have foreign key constraints." + " Error close to %s.\n", + operation, create_name, start_of_latest_foreign); + mutex_exit(&dict_foreign_err_mutex); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Temporary tables can't have foreign key constraints." + " Error close to %s.", + operation, create_name, start_of_latest_foreign); return(DB_CANNOT_ADD_CONSTRAINT); } @@ -4487,6 +4694,7 @@ loop: start_of_latest_foreign = ptr; + orig = ptr; ptr = dict_accept(cs, ptr, "FOREIGN", &success); if (!success) { @@ -4497,6 +4705,7 @@ loop: goto loop; } + orig = ptr; ptr = dict_accept(cs, ptr, "KEY", &success); if (!success) { @@ -4522,6 +4731,7 @@ loop: } } + orig = ptr; ptr = dict_accept(cs, ptr, "(", &success); if (!success) { @@ -4531,8 +4741,17 @@ loop: ptr = dict_skip_word(cs, ptr, &success); if (!success) { dict_foreign_report_syntax_err( - name, start_of_latest_foreign, ptr); - return(DB_CANNOT_ADD_CONSTRAINT); + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, orig); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, orig); + return(DB_CANNOT_ADD_CONSTRAINT); } } else { @@ -4559,15 +4778,26 @@ loop: /* Scan the columns in the first list */ col_loop1: ut_a(i < (sizeof column_names) / sizeof *column_names); + orig = ptr; ptr = dict_scan_col(cs, ptr, &success, table, columns + i, heap, column_names + i); if (!success) { mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\nCannot resolve column name close to:\n%s\n", - start_of_latest_foreign, ptr); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, orig); + mutex_exit(&dict_foreign_err_mutex); + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, orig); + return(DB_CANNOT_ADD_CONSTRAINT); } @@ -4579,11 +4809,22 @@ col_loop1: goto col_loop1; } + orig = ptr; ptr = dict_accept(cs, ptr, ")", &success); if (!success) { dict_foreign_report_syntax_err( - name, start_of_latest_foreign, ptr); + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, orig); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, orig); + return(DB_CANNOT_ADD_CONSTRAINT); } @@ -4594,27 +4835,41 @@ col_loop1: set to 0 */ index = dict_foreign_find_index( - table, NULL, column_names, i, NULL, TRUE, FALSE); + table, NULL, column_names, i, + NULL, TRUE, FALSE, &index_error, &err_col, &err_index); if (!index) { mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); + dict_foreign_error_report_low(ef, create_name); fputs("There is no index in table ", ef); - ut_print_name(ef, NULL, TRUE, name); + ut_print_name(ef, NULL, TRUE, create_name); fprintf(ef, " where the columns appear\n" "as the first columns. Constraint:\n%s\n" "See " REFMAN "innodb-foreign-key-constraints.html\n" "for correct foreign key definition.\n", start_of_latest_foreign); - mutex_exit(&dict_foreign_err_mutex); + dict_foreign_push_index_error(trx, operation, create_name, start_of_latest_foreign, + column_names, index_error, err_col, err_index, table, ef); - return(DB_CHILD_NO_INDEX); + mutex_exit(&dict_foreign_err_mutex); + return(DB_CANNOT_ADD_CONSTRAINT); } + + orig = ptr; ptr = dict_accept(cs, ptr, "REFERENCES", &success); if (!success || !my_isspace(cs, *ptr)) { dict_foreign_report_syntax_err( - name, start_of_latest_foreign, ptr); + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, orig); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, orig); return(DB_CANNOT_ADD_CONSTRAINT); } @@ -4683,21 +4938,46 @@ col_loop1: checking of foreign key constraints! */ if (!success || (!referenced_table && trx->check_foreigns)) { + char buf[MAX_TABLE_NAME_LEN + 1] = ""; + char* bufend; + + bufend = innobase_convert_name(buf, MAX_TABLE_NAME_LEN, + referenced_table_name, strlen(referenced_table_name), + trx->mysql_thd, TRUE); + buf[bufend - buf] = '\0'; + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint failed. Referenced table %s not found in the data dictionary " + "close to %s.", + operation, create_name, buf, start_of_latest_foreign); mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\nCannot resolve table name close to:\n" - "%s\n", - start_of_latest_foreign, ptr); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%s table %s with foreign key constraint failed. Referenced table %s not found in the data dictionary " + "close to %s.\n", + operation, create_name, buf, start_of_latest_foreign); + mutex_exit(&dict_foreign_err_mutex); return(DB_CANNOT_ADD_CONSTRAINT); } + orig = ptr; ptr = dict_accept(cs, ptr, "(", &success); if (!success) { - dict_foreign_report_syntax_err(name, start_of_latest_foreign, - ptr); + dict_foreign_report_syntax_err( + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, orig); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, orig); + return(DB_CANNOT_ADD_CONSTRAINT); } @@ -4705,34 +4985,54 @@ col_loop1: i = 0; col_loop2: + orig = ptr; ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i, - heap, column_names + i); + heap, ref_column_names + i); i++; if (!success) { mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\nCannot resolve column name close to:\n" - "%s\n", - start_of_latest_foreign, ptr); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, orig); mutex_exit(&dict_foreign_err_mutex); + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, orig); return(DB_CANNOT_ADD_CONSTRAINT); } + orig = ptr; ptr = dict_accept(cs, ptr, ",", &success); if (success) { goto col_loop2; } + orig = ptr; ptr = dict_accept(cs, ptr, ")", &success); if (!success || foreign->n_fields != i) { - dict_foreign_report_syntax_err(name, start_of_latest_foreign, - ptr); + dict_foreign_report_syntax_err( + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s. Too few referenced columns.\n", + operation, create_name, start_of_latest_foreign, orig); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s. Too few referenced columns, you have %d when you should have %d.", + operation, create_name, start_of_latest_foreign, orig, i, foreign->n_fields); + return(DB_CANNOT_ADD_CONSTRAINT); } @@ -4742,6 +5042,7 @@ col_loop2: scan_on_conditions: /* Loop here as long as we can find ON ... conditions */ + start_of_latest_set = ptr; ptr = dict_accept(cs, ptr, "ON", &success); if (!success) { @@ -4749,15 +5050,27 @@ scan_on_conditions: goto try_find_index; } + orig = ptr; ptr = dict_accept(cs, ptr, "DELETE", &success); if (!success) { + orig = ptr; ptr = dict_accept(cs, ptr, "UPDATE", &success); if (!success) { dict_foreign_report_syntax_err( - name, start_of_latest_foreign, ptr); + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, start_of_latest_set); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, start_of_latest_set); + return(DB_CANNOT_ADD_CONSTRAINT); } @@ -4768,12 +5081,14 @@ scan_on_conditions: n_on_deletes++; } + orig = ptr; ptr = dict_accept(cs, ptr, "RESTRICT", &success); if (success) { goto scan_on_conditions; } + orig = ptr; ptr = dict_accept(cs, ptr, "CASCADE", &success); if (success) { @@ -4786,14 +5101,25 @@ scan_on_conditions: goto scan_on_conditions; } + orig = ptr; ptr = dict_accept(cs, ptr, "NO", &success); if (success) { + orig = ptr; ptr = dict_accept(cs, ptr, "ACTION", &success); if (!success) { dict_foreign_report_syntax_err( - name, start_of_latest_foreign, ptr); + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, start_of_latest_set); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, start_of_latest_set); return(DB_CANNOT_ADD_CONSTRAINT); } @@ -4807,38 +5133,69 @@ scan_on_conditions: goto scan_on_conditions; } + orig = ptr; ptr = dict_accept(cs, ptr, "SET", &success); if (!success) { - dict_foreign_report_syntax_err(name, start_of_latest_foreign, - ptr); + dict_foreign_report_syntax_err( + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, start_of_latest_set); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, start_of_latest_set); return(DB_CANNOT_ADD_CONSTRAINT); } + orig = ptr; ptr = dict_accept(cs, ptr, "NULL", &success); if (!success) { - dict_foreign_report_syntax_err(name, start_of_latest_foreign, - ptr); + dict_foreign_report_syntax_err( + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.\n", + operation, create_name, start_of_latest_foreign, start_of_latest_set); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. Foreign key constraint parse error in %s" + " close to %s.", + operation, create_name, start_of_latest_foreign, start_of_latest_set); + return(DB_CANNOT_ADD_CONSTRAINT); } for (j = 0; j < foreign->n_fields; j++) { if ((dict_index_get_nth_col(foreign->foreign_index, j)->prtype) & DATA_NOT_NULL) { + const dict_col_t* col + = dict_index_get_nth_col(foreign->foreign_index, j); + const char* col_name = dict_table_get_col_name(foreign->foreign_index->table, + dict_col_get_no(col)); /* It is not sensible to define SET NULL if the column is not allowed to be NULL! */ mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\n" - "You have defined a SET NULL condition" - " though some of the\n" - "columns are defined as NOT NULL.\n", - start_of_latest_foreign); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%s table %s with foreign key constraint" + " failed. You have defined a SET NULL condition but column %s is defined as NOT NULL" + " in %s close to %s.\n", + operation, create_name, col_name, start_of_latest_foreign, start_of_latest_set); mutex_exit(&dict_foreign_err_mutex); + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. You have defined a SET NULL condition but column %s is defined as NOT NULL" + " in %s close to %s.", + operation, create_name, col_name, start_of_latest_foreign, start_of_latest_set); + return(DB_CANNOT_ADD_CONSTRAINT); } } @@ -4856,11 +5213,20 @@ try_find_index: /* It is an error to define more than 1 action */ mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); - fprintf(ef, "%s:\n" - "You have twice an ON DELETE clause" - " or twice an ON UPDATE clause.\n", - start_of_latest_foreign); + dict_foreign_error_report_low(ef, create_name); + fprintf(ef, + "%s table %s with foreign key constraint" + " failed. You have more than one on delete or on update clause" + " in %s close to %s.\n", + operation, create_name, start_of_latest_foreign, start_of_latest_set); + + ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT, + "%s table %s with foreign key constraint" + " failed. You have more than one on delete or on update clause" + " in %s close to %s.", + operation, create_name, start_of_latest_foreign, start_of_latest_set); + + dict_foreign_free(foreign); mutex_exit(&dict_foreign_err_mutex); return(DB_CANNOT_ADD_CONSTRAINT); @@ -4872,12 +5238,12 @@ try_find_index: if (referenced_table) { index = dict_foreign_find_index(referenced_table, NULL, - column_names, i, + ref_column_names, i, foreign->foreign_index, - TRUE, FALSE); + TRUE, FALSE, &index_error, &err_col, &err_index); if (!index) { mutex_enter(&dict_foreign_err_mutex); - dict_foreign_error_report_low(ef, name); + dict_foreign_error_report_low(ef, create_name); fprintf(ef, "%s:\n" "Cannot find an index in the" " referenced table where the\n" @@ -4895,9 +5261,13 @@ try_find_index: "innodb-foreign-key-constraints.html\n" "for correct foreign key definition.\n", start_of_latest_foreign); + + dict_foreign_push_index_error(trx, operation, create_name, start_of_latest_foreign, + column_names, index_error, err_col, err_index, referenced_table, ef); + mutex_exit(&dict_foreign_err_mutex); - return(DB_PARENT_NO_INDEX); + return(DB_CANNOT_ADD_CONSTRAINT); } } else { ut_a(trx->check_foreigns == FALSE); @@ -4916,11 +5286,12 @@ try_find_index: for (i = 0; i < foreign->n_fields; i++) { foreign->referenced_col_names[i] - = mem_heap_strdup(foreign->heap, column_names[i]); + = mem_heap_strdup(foreign->heap, ref_column_names[i]); } goto loop; } + /************************************************************************** Determines whether a string starts with the specified keyword. @return TRUE if str starts with keyword */ @@ -6110,7 +6481,8 @@ dict_foreign_replace_index( foreign->foreign_table, col_names, foreign->foreign_col_names, foreign->n_fields, index, - /*check_charsets=*/TRUE, /*check_null=*/FALSE); + /*check_charsets=*/TRUE, /*check_null=*/FALSE, + NULL, NULL, NULL); if (new_index) { ut_ad(new_index->table == index->table); ut_ad(!new_index->to_be_dropped); @@ -6134,7 +6506,8 @@ dict_foreign_replace_index( foreign->referenced_table, NULL, foreign->referenced_col_names, foreign->n_fields, index, - /*check_charsets=*/TRUE, /*check_null=*/FALSE); + /*check_charsets=*/TRUE, /*check_null=*/FALSE, + NULL, NULL, NULL); /* There must exist an alternative index, since this must have been checked earlier. */ if (new_index) { @@ -6695,10 +7068,15 @@ dict_foreign_qualify_index( /*!< in: whether to check charsets. only has an effect if types_idx != NULL */ - ulint check_null) + ulint check_null, /*!< in: nonzero if none of the columns must be declared NOT NULL */ + ulint* error, /*!< out: error code */ + ulint* err_col_no, + /*!< out: column number where error happened */ + dict_index_t** err_index) + /*!< out: index where error happened */ { if (dict_index_get_n_fields(index) < n_cols) { return(false); @@ -6715,11 +7093,21 @@ dict_foreign_qualify_index( if (field->prefix_len != 0) { /* We do not accept column prefix indexes here */ + if (error && err_col_no && err_index) { + *error = DB_FOREIGN_KEY_IS_PREFIX_INDEX; + *err_col_no = i; + *err_index = (dict_index_t*)index; + } return(false); } if (check_null && (field->col->prtype & DATA_NOT_NULL)) { + if (error && err_col_no && err_index) { + *error = DB_FOREIGN_KEY_COL_NOT_NULL; + *err_col_no = i; + *err_index = (dict_index_t*)index; + } return(false); } @@ -6735,6 +7123,12 @@ dict_foreign_qualify_index( dict_index_get_nth_col(index, i), dict_index_get_nth_col(types_idx, i), check_charsets)) { + if (error && err_col_no && err_index) { + *error = DB_FOREIGN_KEY_COLS_NOT_EQUAL; + *err_col_no = i; + *err_index = (dict_index_t*)index; + } + return(false); } } diff --git a/storage/xtradb/dict/dict0mem.cc b/storage/xtradb/dict/dict0mem.cc index ffdc5100558..a4f6cd6c91f 100644 --- a/storage/xtradb/dict/dict0mem.cc +++ b/storage/xtradb/dict/dict0mem.cc @@ -420,7 +420,8 @@ dict_mem_table_col_rename_low( dict_index_t* new_index = dict_foreign_find_index( foreign->foreign_table, NULL, foreign->foreign_col_names, - foreign->n_fields, NULL, true, false); + foreign->n_fields, NULL, true, false, + NULL, NULL, NULL); /* There must be an equivalent index in this case. */ ut_ad(new_index != NULL); diff --git a/storage/xtradb/fil/fil0fil.cc b/storage/xtradb/fil/fil0fil.cc index 3fc9506a15a..d309026e6cc 100644 --- a/storage/xtradb/fil/fil0fil.cc +++ b/storage/xtradb/fil/fil0fil.cc @@ -5928,9 +5928,9 @@ _fil_io( if (!ret) { return(DB_OUT_OF_FILE_SPACE); - } else { - return(DB_SUCCESS); } + + return(DB_SUCCESS); } #ifndef UNIV_HOTBACKUP diff --git a/storage/xtradb/fsp/fsp0fsp.cc b/storage/xtradb/fsp/fsp0fsp.cc index 363a46d7fdf..1358fab90ea 100644 --- a/storage/xtradb/fsp/fsp0fsp.cc +++ b/storage/xtradb/fsp/fsp0fsp.cc @@ -2730,6 +2730,8 @@ fsp_reserve_free_extents( ulint reserve; ibool success; ulint n_pages_added; + size_t total_reserved = 0; + ulint rounds = 0; ut_ad(mtr); *n_reserved = n_ext; @@ -2743,7 +2745,7 @@ fsp_reserve_free_extents( try_again: size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, mtr); - if (size < FSP_EXTENT_SIZE) { + if (size < FSP_EXTENT_SIZE / 2) { /* Use different rules for small single-table tablespaces */ *n_reserved = 0; return(fsp_reserve_free_pages(space, space_header, size, mtr)); @@ -2758,7 +2760,6 @@ try_again: some of them will contain extent descriptor pages, and therefore will not be free extents */ - ut_ad(size >= free_limit); n_free_up = (size - free_limit) / FSP_EXTENT_SIZE; if (n_free_up > 0) { @@ -2799,6 +2800,7 @@ try_again: } success = fil_space_reserve_free_extents(space, n_free, n_ext); + *n_reserved = n_ext; if (success) { return(TRUE); @@ -2808,6 +2810,16 @@ try_to_extend: space_header, mtr); if (success && n_pages_added > 0) { + rounds++; + total_reserved += n_pages_added; + + if (rounds > 50) { + ib_logf(IB_LOG_LEVEL_INFO, + "Space id %lu trying to reserve %lu extents actually reserved %lu " + " reserve %lu free %lu size %lu rounds %lu total_reserved %lu", + space, n_ext, n_pages_added, reserve, n_free, size, rounds, total_reserved); + } + goto try_again; } diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index a7f5653c389..a80c74cd1fd 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -1,10 +1,10 @@ /***************************************************************************** -Copyright (c) 2000, 2015, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2000, 2015, Oracle and/or its affiliates. +Copyright (c) 2013, 2015, MariaDB Corporation. Copyright (c) 2008, 2009 Google Inc. Copyright (c) 2009, Percona Inc. Copyright (c) 2012, Facebook Inc. -Copyright (c) 2013, 2015, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -607,7 +607,8 @@ ib_cb_t innodb_api_cb[] = { (ib_cb_t) ib_get_idx_field_name, (ib_cb_t) ib_trx_get_start_time, (ib_cb_t) ib_cfg_bk_commit_interval, - (ib_cb_t) ib_cursor_stmt_begin + (ib_cb_t) ib_cursor_stmt_begin, + (ib_cb_t) ib_trx_read_only }; @@ -2636,6 +2637,7 @@ check_trx_exists( if (trx == NULL) { trx = innobase_trx_allocate(thd); + thd_set_ha_data(thd, innodb_hton_ptr, trx); } else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) { mem_analyze_corruption(trx); ut_error; @@ -13135,6 +13137,13 @@ ha_innobase::estimate_rows_upper_bound() prebuilt->trx->op_info = ""; + /* Set num_rows less than MERGEBUFF to simulate the case where we do + not have enough space to merge the externally sorted file blocks. */ + DBUG_EXECUTE_IF("set_num_rows_lt_MERGEBUFF", + estimate = 2; + DBUG_SET("-d,set_num_rows_lt_MERGEBUFF"); + ); + DBUG_RETURN((ha_rows) estimate); } @@ -13400,7 +13409,6 @@ ha_innobase::info_low( dict_table_t* ib_table; ha_rows rec_per_key; ib_uint64_t n_rows; - char path[FN_REFLEN]; os_file_stat_t stat_info; DBUG_ENTER("info"); @@ -13457,6 +13465,7 @@ ha_innobase::info_low( prebuilt->trx->op_info = "returning various info to MySQL"; } + } if (flag & HA_STATUS_VARIABLE) { @@ -13588,6 +13597,7 @@ ha_innobase::info_low( if (flag & HA_STATUS_CONST) { ulong i; + char path[FN_REFLEN]; /* Verify the number of index in InnoDB and MySQL matches up. If prebuilt->clust_index_was_generated holds, InnoDB defines GEN_CLUST_INDEX internally */ @@ -21229,6 +21239,32 @@ ib_warn_row_too_big(const dict_table_t* table) , prefix ? DICT_MAX_FIXED_COL_LEN : 0); } +/********************************************************************//** +Helper function to push warnings from InnoDB internals to SQL-layer. */ +UNIV_INTERN +void +ib_push_warning( + trx_t* trx, /*!< in: trx */ + ulint error, /*!< in: error code to push as warning */ + const char *format,/*!< in: warning message */ + ...) +{ + va_list args; + THD *thd = (THD *)trx->mysql_thd; + char *buf; +#define MAX_BUF_SIZE 4*1024 + + va_start(args, format); + buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME)); + vsprintf(buf,format, args); + + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + convert_error_code_to_mysql((dberr_t)error, 0, thd), + buf); + my_free(buf); + va_end(args); +} + /*************************************************************//** Check for a valid value of innobase_compression_algorithm. @return 0 for valid innodb_compression_algorithm. */ diff --git a/storage/xtradb/handler/handler0alter.cc b/storage/xtradb/handler/handler0alter.cc index 7f5ee15049e..168921ae20b 100644 --- a/storage/xtradb/handler/handler0alter.cc +++ b/storage/xtradb/handler/handler0alter.cc @@ -400,6 +400,35 @@ ha_innobase::check_if_supported_inplace_alter( } } + /* If we have column that has changed from NULL -> NOT NULL + and column default has changed we need to do additional + check. */ + if ((ha_alter_info->handler_flags + & Alter_inplace_info::ALTER_COLUMN_NOT_NULLABLE) && + (ha_alter_info->handler_flags + & Alter_inplace_info::ALTER_COLUMN_DEFAULT)) { + Alter_info *alter_info = ha_alter_info->alter_info; + List_iterator<Create_field> def_it(alter_info->create_list); + Create_field *def; + while ((def=def_it++)) { + + /* If this is first column definition whose SQL type + is TIMESTAMP and it is defined as NOT NULL and + it has either constant default or function default + we must use "Copy" method. */ + if (is_timestamp_type(def->sql_type)) { + if ((def->flags & NOT_NULL_FLAG) != 0 && // NOT NULL + (def->def != NULL || // constant default ? + def->unireg_check != Field::NONE)) { // function default + ha_alter_info->unsupported_reason = innobase_get_err_msg( + ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_NOT_NULL); + DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); + } + break; + } + } + } + /* We should be able to do the operation in-place. See if we can do it online (LOCK=NONE). */ bool online = true; @@ -824,7 +853,7 @@ innobase_find_fk_index( if (!(index->type & DICT_FTS) && dict_foreign_qualify_index( table, col_names, columns, n_cols, - index, NULL, true, 0)) { + index, NULL, true, 0, NULL, NULL, NULL)) { for (ulint i = 0; i < n_drop_index; i++) { if (index == drop_index[i]) { /* Skip to-be-dropped indexes. */ @@ -1014,7 +1043,7 @@ innobase_get_foreign_key_info( referenced_table, 0, referenced_column_names, i, index, - TRUE, FALSE); + TRUE, FALSE, NULL, NULL, NULL); DBUG_EXECUTE_IF( "innodb_test_no_reference_idx", @@ -3341,7 +3370,7 @@ innobase_check_foreign_key_index( foreign->referenced_col_names, foreign->n_fields, index, /*check_charsets=*/TRUE, - /*check_null=*/FALSE) + /*check_null=*/FALSE, NULL, NULL, NULL) && !innobase_find_equiv_index( foreign->referenced_col_names, foreign->n_fields, @@ -3369,7 +3398,7 @@ innobase_check_foreign_key_index( foreign->foreign_col_names, foreign->n_fields, index, /*check_charsets=*/TRUE, - /*check_null=*/FALSE) + /*check_null=*/FALSE, NULL,NULL, NULL) && !innobase_find_equiv_index( foreign->foreign_col_names, foreign->n_fields, @@ -4838,7 +4867,8 @@ innobase_update_foreign_try( fk->n_fields, fk->referenced_index, TRUE, fk->type & (DICT_FOREIGN_ON_DELETE_SET_NULL - | DICT_FOREIGN_ON_UPDATE_SET_NULL)); + | DICT_FOREIGN_ON_UPDATE_SET_NULL), + NULL, NULL, NULL); if (!fk->foreign_index) { my_error(ER_FK_INCORRECT_OPTION, MYF(0), table_name, fk->id); @@ -4850,7 +4880,7 @@ innobase_update_foreign_try( names, while the columns in ctx->old_table have not been renamed yet. */ error = dict_create_add_foreign_to_dictionary( - ctx->old_table->name, fk, trx); + (dict_table_t*)ctx->old_table, ctx->old_table->name, fk, trx); DBUG_EXECUTE_IF( "innodb_test_cannot_add_fk_system", diff --git a/storage/xtradb/include/api0api.h b/storage/xtradb/include/api0api.h index d77d691becc..e4c9c941de5 100644 --- a/storage/xtradb/include/api0api.h +++ b/storage/xtradb/include/api0api.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2011, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2011, 2015, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -494,6 +494,14 @@ ib_trx_state( /*=========*/ ib_trx_t ib_trx); /*!< in: trx handle */ + +/*****************************************************************//** +Check if the transaction is read_only */ +ib_u32_t +ib_trx_read_only( +/*=============*/ + ib_trx_t ib_trx); /*!< in: trx handle */ + /*****************************************************************//** Release the resources of the transaction. If the transaction was selected as a victim by InnoDB and rolled back then use this function diff --git a/storage/xtradb/include/buf0buf.h b/storage/xtradb/include/buf0buf.h index 2e8e4139843..5a0bd203185 100644 --- a/storage/xtradb/include/buf0buf.h +++ b/storage/xtradb/include/buf0buf.h @@ -97,9 +97,6 @@ extern buf_block_t* back_block1; /*!< first block, for --apply-log */ extern buf_block_t* back_block2; /*!< second block, for page reorganize */ #endif /* !UNIV_HOTBACKUP */ -/** Magic value to use instead of checksums when they are disabled */ -#define BUF_NO_CHECKSUM_MAGIC 0xDEADBEEFUL - /** @brief States of a control block @see buf_page_t diff --git a/storage/xtradb/include/buf0checksum.h b/storage/xtradb/include/buf0checksum.h index cd21781dc6e..6818345f965 100644 --- a/storage/xtradb/include/buf0checksum.h +++ b/storage/xtradb/include/buf0checksum.h @@ -28,11 +28,10 @@ Created Aug 11, 2011 Vasil Dimov #include "univ.i" -#ifndef UNIV_INNOCHECKSUM - #include "buf0types.h" -#endif /* !UNIV_INNOCHECKSUM */ +/** Magic value to use instead of checksums when they are disabled */ +#define BUF_NO_CHECKSUM_MAGIC 0xDEADBEEFUL /********************************************************************//** Calculates a page CRC32 which is stored to the page when it is written @@ -70,8 +69,6 @@ buf_calc_page_old_checksum( /*=======================*/ const byte* page); /*!< in: buffer page */ -#ifndef UNIV_INNOCHECKSUM - /********************************************************************//** Return a printable string describing the checksum algorithm. @return algorithm name */ @@ -83,6 +80,4 @@ buf_checksum_algorithm_name( extern ulong srv_checksum_algorithm; -#endif /* !UNIV_INNOCHECKSUM */ - #endif /* buf0checksum_h */ diff --git a/storage/xtradb/include/buf0lru.h b/storage/xtradb/include/buf0lru.h index 6415540178c..f421e329bf0 100644 --- a/storage/xtradb/include/buf0lru.h +++ b/storage/xtradb/include/buf0lru.h @@ -28,7 +28,9 @@ Created 11/5/1995 Heikki Tuuri #include "univ.i" #ifndef UNIV_HOTBACKUP +#ifndef UNIV_INNOCHECKSUM #include "ut0byte.h" +#endif #include "buf0types.h" // Forward declaration diff --git a/storage/xtradb/include/dict0crea.h b/storage/xtradb/include/dict0crea.h index c40e5356ece..3b746fcf83c 100644 --- a/storage/xtradb/include/dict0crea.h +++ b/storage/xtradb/include/dict0crea.h @@ -113,6 +113,17 @@ UNIV_INTERN dberr_t dict_create_or_check_foreign_constraint_tables(void); /*================================================*/ + +/********************************************************************//** +Construct foreign key constraint defintion from data dictionary information. +*/ +UNIV_INTERN +char* +dict_foreign_def_get( +/*=================*/ + dict_foreign_t* foreign,/*!< in: foreign */ + trx_t* trx); /*!< in: trx */ + /********************************************************************//** Generate a foreign key constraint name when it was not named by the user. A generated constraint has a name of the format dbname/tablename_ibfk_NUMBER, @@ -177,6 +188,7 @@ UNIV_INTERN dberr_t dict_create_add_foreign_to_dictionary( /*==================================*/ + dict_table_t* table, /*!< in: table */ const char* name, /*!< in: table name */ const dict_foreign_t* foreign,/*!< in: foreign key */ trx_t* trx) /*!< in/out: dictionary transaction */ diff --git a/storage/xtradb/include/dict0dict.h b/storage/xtradb/include/dict0dict.h index 09b43fe0e71..5dfdba54f29 100644 --- a/storage/xtradb/include/dict0dict.h +++ b/storage/xtradb/include/dict0dict.h @@ -596,10 +596,17 @@ dict_foreign_find_index( /*!< in: whether to check charsets. only has an effect if types_idx != NULL */ - ulint check_null) + ulint check_null, /*!< in: nonzero if none of the columns must be declared NOT NULL */ + ulint* error, /*!< out: error code */ + ulint* err_col_no, + /*!< out: column number where + error happened */ + dict_index_t** err_index) + /*!< out: index where error + happened */ __attribute__((nonnull(1,3), warn_unused_result)); /**********************************************************************//** Returns a column's name. @@ -691,10 +698,18 @@ dict_foreign_qualify_index( /*!< in: whether to check charsets. only has an effect if types_idx != NULL */ - ulint check_null) + ulint check_null, /*!< in: nonzero if none of the columns must be declared NOT NULL */ + ulint* error, /*!< out: error code */ + ulint* err_col_no, + /*!< out: column number where + error happened */ + dict_index_t** err_index) + /*!< out: index where error + happened */ + __attribute__((nonnull(1,3), warn_unused_result)); #ifdef UNIV_DEBUG /********************************************************************//** diff --git a/storage/xtradb/include/ha_prototypes.h b/storage/xtradb/include/ha_prototypes.h index 22cb3eed42d..6008332dae3 100644 --- a/storage/xtradb/include/ha_prototypes.h +++ b/storage/xtradb/include/ha_prototypes.h @@ -28,14 +28,17 @@ Created 5/11/2006 Osku Salerma #define HA_INNODB_PROTOTYPES_H #include "my_dbug.h" -#include "mysqld_error.h" #include "my_compare.h" #include "my_sys.h" #include "m_string.h" -#include "debug_sync.h" #include "my_base.h" +#ifndef UNIV_INNOCHECKSUM +#include "mysqld_error.h" +#include "debug_sync.h" #include "trx0types.h" +#endif + #include "m_ctype.h" /* CHARSET_INFO */ // Forward declarations @@ -81,6 +84,8 @@ innobase_raw_format( ulint buf_size); /*!< in: output buffer size in bytes */ +#ifndef UNIV_INNOCHECKSUM + /*****************************************************************//** Invalidates the MySQL query cache for the table. */ UNIV_INTERN @@ -97,6 +102,8 @@ innobase_invalidate_query_cache( ulint full_name_len); /*!< in: full name length where also the null chars count */ +#endif /* #ifndef UNIV_INNOCHECKSUM */ + /*****************************************************************//** Convert a table or index name to the MySQL system_charset_info (UTF-8) and quote it if needed. @@ -620,5 +627,14 @@ innobase_convert_to_filename_charset( const char* from, /* in: identifier to convert */ ulint len); /* in: length of 'to', in bytes */ +/********************************************************************//** +Helper function to push warnings from InnoDB internals to SQL-layer. */ +UNIV_INTERN +void +ib_push_warning( + trx_t* trx, /*!< in: trx */ + ulint error, /*!< in: error code to push as warning */ + const char *format,/*!< in: warning message */ + ...); #endif /* HA_INNODB_PROTOTYPES_H */ diff --git a/storage/xtradb/include/os0file.h b/storage/xtradb/include/os0file.h index 88ba7e18ac3..e9faac0d945 100644 --- a/storage/xtradb/include/os0file.h +++ b/storage/xtradb/include/os0file.h @@ -1,6 +1,6 @@ /*********************************************************************** -Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2009, Percona Inc. Copyright (c) 2013, 2015, MariaDB Corporation. @@ -405,10 +405,10 @@ to original un-instrumented file I/O APIs */ enum os_file_type_t { OS_FILE_TYPE_UNKNOWN = 0, - OS_FILE_TYPE_FILE, /* regular file */ + OS_FILE_TYPE_FILE, /* regular file + (or a character/block device) */ OS_FILE_TYPE_DIR, /* directory */ - OS_FILE_TYPE_LINK, /* symbolic link */ - OS_FILE_TYPE_BLOCK /* block device */ + OS_FILE_TYPE_LINK /* symbolic link */ }; /* Maximum path string length in bytes when referring to tables with in the diff --git a/storage/xtradb/include/page0page.h b/storage/xtradb/include/page0page.h index 6940040a130..2da5d793fa9 100644 --- a/storage/xtradb/include/page0page.h +++ b/storage/xtradb/include/page0page.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2015, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -28,6 +28,10 @@ Created 2/2/1994 Heikki Tuuri #include "univ.i" +#include "buf0types.h" + +#ifndef UNIV_INNOCHECKSUM + #include "page0types.h" #include "fil0fil.h" #include "buf0buf.h" @@ -1110,6 +1114,24 @@ page_find_rec_with_heap_no( const rec_t* page_find_rec_max_not_deleted( const page_t* page); + +#endif /* #ifndef UNIV_INNOCHECKSUM */ + +/** Issue a warning when the checksum that is stored in the page is valid, +but different than the global setting innodb_checksum_algorithm. +@param[in] current_algo current checksum algorithm +@param[in] page_checksum page valid checksum +@param[in] space_id tablespace id +@param[in] page_no page number */ +void +page_warn_strict_checksum( + srv_checksum_algorithm_t curr_algo, + srv_checksum_algorithm_t page_checksum, + ulint space_id, + ulint page_no); + +#ifndef UNIV_INNOCHECKSUM + #ifdef UNIV_MATERIALIZE #undef UNIV_INLINE #define UNIV_INLINE UNIV_INLINE_ORIGINAL @@ -1119,4 +1141,6 @@ page_find_rec_max_not_deleted( #include "page0page.ic" #endif +#endif /* #ifndef UNIV_INNOCHECKSUM */ + #endif diff --git a/storage/xtradb/include/page0types.h b/storage/xtradb/include/page0types.h index 95143a4bb44..74ad6f72f7e 100644 --- a/storage/xtradb/include/page0types.h +++ b/storage/xtradb/include/page0types.h @@ -107,6 +107,8 @@ struct page_zip_stat_t { { } }; +#ifndef UNIV_INNOCHECKSUM + /** Compression statistics types */ typedef map<index_id_t, page_zip_stat_t> page_zip_stat_per_index_t; @@ -119,6 +121,8 @@ extern ib_mutex_t page_zip_stat_per_index_mutex; extern mysql_pfs_key_t page_zip_stat_per_index_mutex_key; #endif /* HAVE_PSI_INTERFACE */ +#endif /* !UNIV_INNOCHECKSUM */ + /**********************************************************************//** Write the "deleted" flag of a record on a compressed page. The flag must already have been written on the uncompressed page. */ diff --git a/storage/xtradb/include/page0zip.h b/storage/xtradb/include/page0zip.h index 2f9efc4a40c..41eb1e35d78 100644 --- a/storage/xtradb/include/page0zip.h +++ b/storage/xtradb/include/page0zip.h @@ -32,13 +32,17 @@ Created June 2005 by Marko Makela # define UNIV_INLINE #endif -#include "mtr0types.h" +#ifndef UNIV_INNOCHECKSUM #include "page0types.h" -#include "buf0types.h" +#include "mtr0types.h" #include "dict0types.h" #include "srv0srv.h" #include "trx0types.h" #include "mem0mem.h" +#else +#include "univ.i" +#endif /* !UNIV_INNOCHECKSUM */ +#include "buf0types.h" /* Compression level to be used by zlib. Settable by user. */ extern uint page_zip_level; @@ -50,6 +54,7 @@ extern uint page_zip_level; compression algorithm changes in zlib. */ extern my_bool page_zip_log_pages; +#ifndef UNIV_INNOCHECKSUM /**********************************************************************//** Determine the size of a compressed page in bytes. @return size in bytes */ @@ -159,6 +164,8 @@ page_zip_simple_validate( descriptor */ #endif /* UNIV_DEBUG */ +#endif /* !UNIV_INNOCHECKSUM */ + #ifdef UNIV_ZIP_DEBUG /**********************************************************************//** Check that the compressed and decompressed pages match. @@ -185,6 +192,7 @@ page_zip_validate( __attribute__((nonnull(1,2))); #endif /* UNIV_ZIP_DEBUG */ +#ifndef UNIV_INNOCHECKSUM /**********************************************************************//** Determine how big record can be inserted without recompressing the page. @return a positive number indicating the maximum size of a record @@ -452,6 +460,8 @@ page_zip_parse_compress( page_zip_des_t* page_zip)/*!< out: compressed page */ __attribute__((nonnull(1,2))); +#endif /* !UNIV_INNOCHECKSUM */ + /**********************************************************************//** Calculate the compressed page checksum. @return page checksum */ @@ -474,6 +484,9 @@ page_zip_verify_checksum( /*=====================*/ const void* data, /*!< in: compressed page */ ulint size); /*!< in: size of compressed page */ + +#ifndef UNIV_INNOCHECKSUM + /**********************************************************************//** Write a log record of compressing an index page without the data on the page. */ UNIV_INLINE @@ -506,6 +519,8 @@ void page_zip_reset_stat_per_index(); /*===========================*/ +#endif /* !UNIV_INNOCHECKSUM */ + #ifndef UNIV_HOTBACKUP /** Check if a pointer to an uncompressed page matches a compressed page. When we IMPORT a tablespace the blocks and accompanying frames are allocted @@ -531,8 +546,10 @@ from outside the buffer pool. # define UNIV_INLINE UNIV_INLINE_ORIGINAL #endif +#ifndef UNIV_INNOCHECKSUM #ifndef UNIV_NONINL # include "page0zip.ic" #endif +#endif /* !UNIV_INNOCHECKSUM */ #endif /* page0zip_h */ diff --git a/storage/xtradb/include/srv0srv.h b/storage/xtradb/include/srv0srv.h index 78a402d488c..45300bc2ded 100644 --- a/storage/xtradb/include/srv0srv.h +++ b/storage/xtradb/include/srv0srv.h @@ -514,7 +514,6 @@ extern my_bool srv_stats_sample_traditional; extern ibool srv_use_doublewrite_buf; extern ulong srv_doublewrite_batch_size; -extern ulong srv_checksum_algorithm; extern ulong srv_log_arch_expire_sec; diff --git a/storage/xtradb/include/univ.i b/storage/xtradb/include/univ.i index 241f210869f..8105d1f318b 100644 --- a/storage/xtradb/include/univ.i +++ b/storage/xtradb/include/univ.i @@ -45,10 +45,10 @@ Created 1/20/1994 Heikki Tuuri #define INNODB_VERSION_MAJOR 5 #define INNODB_VERSION_MINOR 6 -#define INNODB_VERSION_BUGFIX 24 +#define INNODB_VERSION_BUGFIX 25 #ifndef PERCONA_INNODB_VERSION -#define PERCONA_INNODB_VERSION 72.2 +#define PERCONA_INNODB_VERSION 73.1 #endif /* Enable UNIV_LOG_ARCHIVE in XtraDB */ diff --git a/storage/xtradb/lock/lock0lock.cc b/storage/xtradb/lock/lock0lock.cc index b3d9e470816..26d868ca94d 100644 --- a/storage/xtradb/lock/lock0lock.cc +++ b/storage/xtradb/lock/lock0lock.cc @@ -3027,7 +3027,8 @@ lock_rec_inherit_to_gap( && !((srv_locks_unsafe_for_binlog || lock->trx->isolation_level <= TRX_ISO_READ_COMMITTED) - && lock_get_mode(lock) == LOCK_X)) { + && lock_get_mode(lock) == + (lock->trx->duplicates ? LOCK_S : LOCK_X))) { lock_rec_add_to_queue( LOCK_REC | LOCK_GAP | lock_get_mode(lock), diff --git a/storage/xtradb/os/os0file.cc b/storage/xtradb/os/os0file.cc index cb074cdf4f5..9ef9adf5b74 100644 --- a/storage/xtradb/os/os0file.cc +++ b/storage/xtradb/os/os0file.cc @@ -1,6 +1,6 @@ /*********************************************************************** -Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2009, Percona Inc. Copyright (c) 2013, 2015, MariaDB Corporation. @@ -3604,8 +3604,9 @@ os_file_get_status( stat_info->type = OS_FILE_TYPE_LINK; break; case S_IFBLK: - stat_info->type = OS_FILE_TYPE_BLOCK; - break; + /* Handle block device as regular file. */ + case S_IFCHR: + /* Handle character device as regular file. */ case S_IFREG: stat_info->type = OS_FILE_TYPE_FILE; break; @@ -3614,8 +3615,8 @@ os_file_get_status( } - if (check_rw_perm && (stat_info->type == OS_FILE_TYPE_FILE - || stat_info->type == OS_FILE_TYPE_BLOCK)) { + if (check_rw_perm && stat_info->type == OS_FILE_TYPE_FILE) { + int fh; int access; diff --git a/storage/xtradb/page/page0page.cc b/storage/xtradb/page/page0page.cc index 4aff88818bb..6adbdeb95a4 100644 --- a/storage/xtradb/page/page0page.cc +++ b/storage/xtradb/page/page0page.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. This program is free software; you can redistribute it and/or modify it under @@ -31,6 +31,11 @@ Created 2/2/1994 Heikki Tuuri #endif #undef THIS_MODULE +#include "ha_prototypes.h" +#include "buf0checksum.h" + +#ifndef UNIV_INNOCHECKSUM + #include "page0cur.h" #include "page0zip.h" #include "buf0buf.h" @@ -2819,3 +2824,51 @@ page_find_rec_max_not_deleted( } return(prev_rec); } + +#endif /* #ifndef UNIV_INNOCHECKSUM */ + +/** Issue a warning when the checksum that is stored in the page is valid, +but different than the global setting innodb_checksum_algorithm. +@param[in] current_algo current checksum algorithm +@param[in] page_checksum page valid checksum +@param[in] space_id tablespace id +@param[in] page_no page number */ +void +page_warn_strict_checksum( + srv_checksum_algorithm_t curr_algo, + srv_checksum_algorithm_t page_checksum, + ulint space_id, + ulint page_no) +{ + srv_checksum_algorithm_t curr_algo_nonstrict; + switch (curr_algo) { + case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32: + curr_algo_nonstrict = SRV_CHECKSUM_ALGORITHM_CRC32; + break; + case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB: + curr_algo_nonstrict = SRV_CHECKSUM_ALGORITHM_INNODB; + break; + case SRV_CHECKSUM_ALGORITHM_STRICT_NONE: + curr_algo_nonstrict = SRV_CHECKSUM_ALGORITHM_NONE; + break; + default: + ut_error; + } + +#ifdef UNIV_INNOCHECKSUM + fprintf(stderr, +#else + ib_logf(IB_LOG_LEVEL_WARN, +#endif + "innodb_checksum_algorithm is set to \"%s\"" + " but the page [page id: space=" ULINTPF "," + " page number=" ULINTPF "] contains a valid checksum \"%s\"." + " Accepting the page as valid. Change innodb_checksum_algorithm" + " to \"%s\" to silently accept such pages or rewrite all pages" + " so that they contain \"%s\" checksum.", + buf_checksum_algorithm_name(curr_algo), + space_id, page_no, + buf_checksum_algorithm_name(page_checksum), + buf_checksum_algorithm_name(curr_algo_nonstrict), + buf_checksum_algorithm_name(curr_algo_nonstrict)); +} diff --git a/storage/xtradb/page/page0zip.cc b/storage/xtradb/page/page0zip.cc index 58559cc438b..42ffd3668d8 100644 --- a/storage/xtradb/page/page0zip.cc +++ b/storage/xtradb/page/page0zip.cc @@ -37,30 +37,40 @@ using namespace std; # include "page0zip.ic" #endif #undef THIS_MODULE +#include "buf0checksum.h" #include "page0page.h" +#ifndef UNIV_INNOCHECKSUM #include "mtr0log.h" -#include "ut0sort.h" #include "dict0dict.h" #include "btr0cur.h" -#include "page0types.h" #include "log0recv.h" +#endif /* !UNIV_INNOCHECKSUM */ #include "zlib.h" +#include "fil0fil.h" +#include "ut0sort.h" +#include "page0types.h" #ifndef UNIV_HOTBACKUP +#ifndef UNIV_INNOCHECKSUM # include "buf0buf.h" -# include "buf0lru.h" # include "btr0sea.h" # include "dict0boot.h" # include "lock0lock.h" # include "srv0mon.h" # include "srv0srv.h" +#endif /* !UNIV_INNOCHECKSUM */ +# include "buf0lru.h" # include "ut0crc32.h" #else /* !UNIV_HOTBACKUP */ -# include "buf0checksum.h" # define lock_move_reorganize_page(block, temp_block) ((void) 0) # define buf_LRU_stat_inc_unzip() ((void) 0) #endif /* !UNIV_HOTBACKUP */ +#ifdef UNIV_INNOCHECKSUM +#include "mach0data.h" +#endif /* UNIV_INNOCHECKSUM */ + #ifndef UNIV_HOTBACKUP +#ifndef UNIV_INNOCHECKSUM /** Statistics on compression, indexed by page_zip_des_t::ssize - 1 */ UNIV_INTERN page_zip_stat_t page_zip_stat[PAGE_ZIP_SSIZE_MAX]; /** Statistics on compression, indexed by index->id */ @@ -70,6 +80,7 @@ UNIV_INTERN ib_mutex_t page_zip_stat_per_index_mutex; #ifdef HAVE_PSI_INTERFACE UNIV_INTERN mysql_pfs_key_t page_zip_stat_per_index_mutex_key; #endif /* HAVE_PSI_INTERFACE */ +#endif /* !UNIV_INNOCHECKSUM */ #endif /* !UNIV_HOTBACKUP */ /* Compression level to be used by zlib. Settable by user. */ @@ -82,6 +93,8 @@ UNIV_INTERN my_bool page_zip_log_pages = false; /* Please refer to ../include/page0zip.ic for a description of the compressed page format. */ +#ifndef UNIV_INNOCHECKSUM + /* The infimum and supremum records are omitted from the compressed page. On compress, we compare that the records are there, and on uncompress we restore the records. */ @@ -105,6 +118,8 @@ static const byte supremum_extra_data[] = { 0x65, 0x6d, 0x75, 0x6d /* "supremum" */ }; +#endif /* !UNIV_INNOCHECKSUM */ + /** Assert that a block of memory is filled with zero bytes. Compare at most sizeof(field_ref_zero) bytes. @param b in: memory block @@ -151,6 +166,7 @@ page_zip_fail_func( # define page_zip_fail(fmt_args) /* empty */ #endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */ +#ifndef UNIV_INNOCHECKSUM #ifndef UNIV_HOTBACKUP /**********************************************************************//** Determine the guaranteed free space on an empty page. @@ -4843,6 +4859,7 @@ corrupt: return(ptr + 8 + size + trailer_size); } +#endif /* !UNIV_INNOCHECKSUM */ /**********************************************************************//** Calculate the compressed page checksum. @@ -4918,6 +4935,10 @@ page_zip_verify_checksum( stored = static_cast<ib_uint32_t>(mach_read_from_4( static_cast<const unsigned char*>(data) + FIL_PAGE_SPACE_OR_CHKSUM)); + ulint page_no = mach_read_from_4(static_cast<const unsigned char*> (data) + FIL_PAGE_OFFSET); + ulint space_id = mach_read_from_4(static_cast<const unsigned char*> + (data) + FIL_PAGE_SPACE_ID); + #if FIL_PAGE_LSN % 8 #error "FIL_PAGE_LSN must be 64 bit aligned" #endif @@ -4938,40 +4959,113 @@ page_zip_verify_checksum( return(TRUE); } + const srv_checksum_algorithm_t curr_algo = + static_cast<srv_checksum_algorithm_t>(srv_checksum_algorithm); + + if (curr_algo == SRV_CHECKSUM_ALGORITHM_NONE) { + return(TRUE); + } + calc = static_cast<ib_uint32_t>(page_zip_calc_checksum( - data, size, static_cast<srv_checksum_algorithm_t>( - srv_checksum_algorithm))); + data, size, curr_algo)); if (stored == calc) { return(TRUE); } - switch ((srv_checksum_algorithm_t) srv_checksum_algorithm) { + switch (curr_algo) { case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32: - case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB: - case SRV_CHECKSUM_ALGORITHM_STRICT_NONE: - return(stored == calc); case SRV_CHECKSUM_ALGORITHM_CRC32: + if (stored == BUF_NO_CHECKSUM_MAGIC) { + if (curr_algo + == SRV_CHECKSUM_ALGORITHM_STRICT_CRC32) { + page_warn_strict_checksum( + curr_algo, + SRV_CHECKSUM_ALGORITHM_NONE, + space_id, page_no); + } + return(TRUE); } - crc32 = calc; + innodb = static_cast<ib_uint32_t>(page_zip_calc_checksum( data, size, SRV_CHECKSUM_ALGORITHM_INNODB)); + + if (stored == innodb) { + if (curr_algo + == SRV_CHECKSUM_ALGORITHM_STRICT_CRC32) { + page_warn_strict_checksum( + curr_algo, + SRV_CHECKSUM_ALGORITHM_INNODB, + space_id, page_no); + } + + return(TRUE); + } + break; + case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB: case SRV_CHECKSUM_ALGORITHM_INNODB: + if (stored == BUF_NO_CHECKSUM_MAGIC) { + if (curr_algo + == SRV_CHECKSUM_ALGORITHM_STRICT_INNODB) { + page_warn_strict_checksum( + curr_algo, + SRV_CHECKSUM_ALGORITHM_NONE, + space_id, page_no); + } + return(TRUE); } + crc32 = static_cast<ib_uint32_t>(page_zip_calc_checksum( data, size, SRV_CHECKSUM_ALGORITHM_CRC32)); - innodb = calc; + + if (stored == crc32) { + if (curr_algo + == SRV_CHECKSUM_ALGORITHM_STRICT_INNODB) { + page_warn_strict_checksum( + curr_algo, + SRV_CHECKSUM_ALGORITHM_CRC32, + space_id, page_no); + } + + return(TRUE); + } + + break; + case SRV_CHECKSUM_ALGORITHM_STRICT_NONE: + + crc32 = static_cast<ib_uint32_t>(page_zip_calc_checksum( + data, size, SRV_CHECKSUM_ALGORITHM_CRC32)); + + if (stored == crc32) { + page_warn_strict_checksum( + curr_algo, SRV_CHECKSUM_ALGORITHM_CRC32, + space_id, page_no); + + return(TRUE); + } + + innodb = static_cast<ib_uint32_t>(page_zip_calc_checksum( + data, size, SRV_CHECKSUM_ALGORITHM_INNODB)); + + if (stored == innodb) { + page_warn_strict_checksum( + curr_algo, + SRV_CHECKSUM_ALGORITHM_INNODB, + space_id, page_no); + return(TRUE); + } + break; case SRV_CHECKSUM_ALGORITHM_NONE: - return(TRUE); + ut_error; /* no default so the compiler will emit a warning if new enum is added and not handled here */ } - return(stored == crc32 || stored == innodb); + return(FALSE); } diff --git a/storage/xtradb/row/row0ins.cc b/storage/xtradb/row/row0ins.cc index fb719266a16..b1291404176 100644 --- a/storage/xtradb/row/row0ins.cc +++ b/storage/xtradb/row/row0ins.cc @@ -2765,6 +2765,8 @@ row_ins_sec_index_entry_low( goto func_exit; } + DEBUG_SYNC_C("row_ins_sec_index_entry_dup_locks_created"); + /* We did not find a duplicate and we have now locked with s-locks the necessary records to prevent any insertion of a duplicate by another diff --git a/storage/xtradb/row/row0mysql.cc b/storage/xtradb/row/row0mysql.cc index efc5c568cd5..8a4536488fe 100644 --- a/storage/xtradb/row/row0mysql.cc +++ b/storage/xtradb/row/row0mysql.cc @@ -1326,18 +1326,14 @@ row_insert_for_mysql( mem_analyze_corruption(prebuilt); ut_error; - } else if (srv_created_new_raw || srv_force_recovery) { - fputs("InnoDB: A new raw disk partition was initialized or\n" - "InnoDB: innodb_force_recovery is on: we do not allow\n" + } else if (srv_force_recovery) { + fputs("InnoDB: innodb_force_recovery is on: we do not allow\n" "InnoDB: database modifications by the user. Shut down\n" "InnoDB: mysqld and edit my.cnf so that" - " newraw is replaced\n" - "InnoDB: with raw, and innodb_force_... is removed.\n", + "InnoDB: innodb_force_... is removed.\n", stderr); - if(srv_force_recovery) { - return(DB_READ_ONLY); - } - return(DB_ERROR); + + return(DB_READ_ONLY); } trx->op_info = "inserting"; @@ -1732,18 +1728,14 @@ row_update_for_mysql( ut_error; } - if (UNIV_UNLIKELY(srv_created_new_raw || srv_force_recovery)) { - fputs("InnoDB: A new raw disk partition was initialized or\n" - "InnoDB: innodb_force_recovery is on: we do not allow\n" + if (UNIV_UNLIKELY(srv_force_recovery)) { + fputs("InnoDB: innodb_force_recovery is on: we do not allow\n" "InnoDB: database modifications by the user. Shut down\n" - "InnoDB: mysqld and edit my.cnf so that newraw" - " is replaced\n" - "InnoDB: with raw, and innodb_force_... is removed.\n", + "InnoDB: mysqld and edit my.cnf so that" + "InnoDB: innodb_force_... is removed.\n", stderr); - if(srv_force_recovery) { - return(DB_READ_ONLY); - } - return(DB_ERROR); + + return(DB_READ_ONLY); } DEBUG_SYNC_C("innodb_row_update_for_mysql_begin"); @@ -2254,22 +2246,6 @@ row_create_table_for_mysql( goto err_exit; ); - if (srv_created_new_raw) { - fputs("InnoDB: A new raw disk partition was initialized:\n" - "InnoDB: we do not allow database modifications" - " by the user.\n" - "InnoDB: Shut down mysqld and edit my.cnf so that newraw" - " is replaced with raw.\n", stderr); -err_exit: - dict_mem_table_free(table); - - if (commit) { - trx_commit_for_mysql(trx); - } - - return(DB_ERROR); - } - trx->op_info = "creating table"; if (row_mysql_is_system_table(table->name)) { @@ -2280,7 +2256,19 @@ err_exit: "InnoDB: MySQL system tables must be" " of the MyISAM type!\n", table->name); - goto err_exit; + +#ifndef DBUG_OFF +err_exit: +#endif /* !DBUG_OFF */ + dict_mem_table_free(table); + + if (commit) { + trx_commit_for_mysql(trx); + } + + trx->op_info = ""; + + return(DB_ERROR); } trx_start_if_not_started_xa(trx); @@ -3365,16 +3353,6 @@ row_truncate_table_for_mysql( ut_ad(table); - if (srv_created_new_raw) { - fputs("InnoDB: A new raw disk partition was initialized:\n" - "InnoDB: we do not allow database modifications" - " by the user.\n" - "InnoDB: Shut down mysqld and edit my.cnf so that newraw" - " is replaced with raw.\n", stderr); - - return(DB_ERROR); - } - if (dict_table_is_discarded(table)) { return(DB_TABLESPACE_DELETED); } else if (table->ibd_file_missing) { @@ -3864,16 +3842,6 @@ row_drop_table_for_mysql( ut_a(name != NULL); - if (srv_created_new_raw) { - fputs("InnoDB: A new raw disk partition was initialized:\n" - "InnoDB: we do not allow database modifications" - " by the user.\n" - "InnoDB: Shut down mysqld and edit my.cnf so that newraw" - " is replaced with raw.\n", stderr); - - DBUG_RETURN(DB_ERROR); - } - /* The table name is prefixed with the database name and a '/'. Certain table names starting with 'innodb_' have their special meaning regardless of the database name. Thus, we need to @@ -4892,19 +4860,16 @@ row_rename_table_for_mysql( ut_a(new_name != NULL); ut_ad(trx->state == TRX_STATE_ACTIVE); - if (srv_created_new_raw || srv_force_recovery) { - fputs("InnoDB: A new raw disk partition was initialized or\n" - "InnoDB: innodb_force_recovery is on: we do not allow\n" + if (srv_force_recovery) { + fputs("InnoDB: innodb_force_recovery is on: we do not allow\n" "InnoDB: database modifications by the user. Shut down\n" - "InnoDB: mysqld and edit my.cnf so that newraw" - " is replaced\n" - "InnoDB: with raw, and innodb_force_... is removed.\n", + "InnoDB: mysqld and edit my.cnf so that" + "InnoDB: innodb_force_... is removed.\n", stderr); - if(srv_force_recovery) { - err = DB_READ_ONLY; - } + err = DB_READ_ONLY; goto funct_exit; + } else if (row_mysql_is_system_table(new_name)) { fprintf(stderr, diff --git a/storage/xtradb/srv/srv0start.cc b/storage/xtradb/srv/srv0start.cc index 3f558170f97..54ac04e7248 100644 --- a/storage/xtradb/srv/srv0start.cc +++ b/storage/xtradb/srv/srv0start.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. +Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2008, Google Inc. Copyright (c) 2009, Percona Inc. Copyright (c) 2013, 2015, MariaDB Corporation @@ -264,8 +264,8 @@ srv_file_check_mode( /* Note: stat.rw_perm is only valid of files */ - if (stat.type == OS_FILE_TYPE_FILE - || stat.type == OS_FILE_TYPE_BLOCK) { + if (stat.type == OS_FILE_TYPE_FILE) { + if (!stat.rw_perm) { ib_logf(IB_LOG_LEVEL_ERROR, @@ -462,14 +462,18 @@ srv_parse_data_file_paths_and_sizes( && *(str + 1) == 'e' && *(str + 2) == 'w') { str += 3; - (srv_data_file_is_raw_partition)[i] = SRV_NEW_RAW; + /* Initialize new raw device only during bootstrap */ + (srv_data_file_is_raw_partition)[i] = + opt_bootstrap ? SRV_NEW_RAW : SRV_OLD_RAW; } if (*str == 'r' && *(str + 1) == 'a' && *(str + 2) == 'w') { str += 3; + /* Initialize new raw device only during bootstrap */ if ((srv_data_file_is_raw_partition)[i] == 0) { - (srv_data_file_is_raw_partition)[i] = SRV_OLD_RAW; + (srv_data_file_is_raw_partition)[i] = + opt_bootstrap ? SRV_NEW_RAW : SRV_OLD_RAW; } } @@ -945,6 +949,21 @@ open_or_create_data_files( return(DB_ERROR); } + + const char* check_msg; + check_msg = fil_read_first_page( + files[i], FALSE, &flags, &space, + min_flushed_lsn, max_flushed_lsn, NULL); + + /* If first page is valid, don't overwrite DB. + It prevents overwriting DB when mysql_install_db + starts mysqld multiple times during bootstrap. */ + if (check_msg == NULL) { + + srv_created_new_raw = FALSE; + ret = FALSE; + } + } else if (srv_data_file_is_raw_partition[i] == SRV_OLD_RAW) { srv_start_raw_disk_in_use = TRUE; diff --git a/storage/xtradb/sync/sync0arr.cc b/storage/xtradb/sync/sync0arr.cc index 01cae70a8ce..d881c5de2f5 100644 --- a/storage/xtradb/sync/sync0arr.cc +++ b/storage/xtradb/sync/sync0arr.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. Copyright (c) 2013, 2015, MariaDB Corporation. All Rights Reserved. @@ -1206,8 +1206,8 @@ sync_array_print_info_low( ulint count = 0; fprintf(file, - "OS WAIT ARRAY INFO: reservation count %ld\n", - (long) arr->res_count); + "OS WAIT ARRAY INFO: reservation count " ULINTPF "\n", + arr->res_count); for (i = 0; count < arr->n_reserved; ++i) { sync_cell_t* cell; @@ -1303,7 +1303,7 @@ sync_array_print( } fprintf(file, - "OS WAIT ARRAY INFO: signal count %ld\n", (long) sg_count); + "OS WAIT ARRAY INFO: signal count " ULINTPF "\n", sg_count); } diff --git a/storage/xtradb/trx/trx0sys.cc b/storage/xtradb/trx/trx0sys.cc index 32948d6847c..bebd28b0df3 100644 --- a/storage/xtradb/trx/trx0sys.cc +++ b/storage/xtradb/trx/trx0sys.cc @@ -1332,8 +1332,6 @@ trx_sys_close(void) /* Free the double write data structures. */ buf_dblwr_free(); - mutex_enter(&trx_sys->mutex); - ut_a(UT_LIST_GET_LEN(trx_sys->ro_trx_list) == 0); /* Only prepared transactions may be left in the system. Free them. */ @@ -1373,8 +1371,6 @@ trx_sys_close(void) ut_a(UT_LIST_GET_LEN(trx_sys->rw_trx_list) == 0); ut_a(UT_LIST_GET_LEN(trx_sys->mysql_trx_list) == 0); - mutex_exit(&trx_sys->mutex); - mutex_free(&trx_sys->mutex); ut_ad(trx_sys->descr_n_used == 0); diff --git a/storage/xtradb/trx/trx0trx.cc b/storage/xtradb/trx/trx0trx.cc index 5d3b86e158f..9bca6de9c26 100644 --- a/storage/xtradb/trx/trx0trx.cc +++ b/storage/xtradb/trx/trx0trx.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -481,9 +481,7 @@ trx_free_prepared( ut_a(trx_state_eq(trx, TRX_STATE_PREPARED)); ut_a(trx->magic_n == TRX_MAGIC_N); - mutex_exit(&trx_sys->mutex); lock_trx_release_locks(trx); - mutex_enter(&trx_sys->mutex); trx_undo_free_prepared(trx); assert_trx_in_rw_list(trx); @@ -493,7 +491,9 @@ trx_free_prepared( UT_LIST_REMOVE(trx_list, trx_sys->rw_trx_list, trx); ut_d(trx->in_rw_trx_list = FALSE); + mutex_enter(&trx_sys->mutex); trx_release_descriptor(trx); + mutex_exit(&trx_sys->mutex); /* Undo trx_resurrect_table_locks(). */ UT_LIST_INIT(trx->lock.trx_locks); |