diff options
Diffstat (limited to 'storage')
29 files changed, 2302 insertions, 406 deletions
diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index f77caf7935d..34c51cefc50 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -1154,6 +1154,23 @@ static ulint btr_node_ptr_max_size(const dict_index_t* index) continue; } +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE + /* SYS_FOREIGN.ID is defined as CHAR in the + InnoDB internal SQL parser, which translates + into the incorrect VARCHAR(0). InnoDB does + not enforce maximum lengths of columns, so + that is why any data can be inserted in the + first place. + + Likewise, SYS_FOREIGN.FOR_NAME, + SYS_FOREIGN.REF_NAME, SYS_FOREIGN_COLS.ID, are + defined as CHAR, and also they are part of a key. */ + + ut_ad(!strcmp(index->table->name.m_name, + "SYS_FOREIGN") + || !strcmp(index->table->name.m_name, + "SYS_FOREIGN_COLS")); +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ ut_ad(!comp); ut_ad(col->mtype == DATA_VARCHAR); diff --git a/storage/innobase/dict/dict0boot.cc b/storage/innobase/dict/dict0boot.cc index 833f2621de6..10e78877d05 100644 --- a/storage/innobase/dict/dict0boot.cc +++ b/storage/innobase/dict/dict0boot.cc @@ -242,12 +242,13 @@ dict_boot(void) ut_ad(DICT_NUM_FIELDS__SYS_INDEXES == 10); ut_ad(DICT_NUM_COLS__SYS_FIELDS == 3); ut_ad(DICT_NUM_FIELDS__SYS_FIELDS == 5); +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE ut_ad(DICT_NUM_COLS__SYS_FOREIGN == 4); ut_ad(DICT_NUM_FIELDS__SYS_FOREIGN == 6); ut_ad(DICT_NUM_FIELDS__SYS_FOREIGN_FOR_NAME == 2); ut_ad(DICT_NUM_COLS__SYS_FOREIGN_COLS == 4); ut_ad(DICT_NUM_FIELDS__SYS_FOREIGN_COLS == 6); - +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ mtr_start(&mtr); /* Create the hash tables etc. */ diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc index 46ebe9a02a5..641610bd6c2 100644 --- a/storage/innobase/dict/dict0crea.cc +++ b/storage/innobase/dict/dict0crea.cc @@ -1383,6 +1383,138 @@ dict_check_if_system_table_exists( return(error); } +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE +/****************************************************************//** +Creates the foreign key constraints system tables inside InnoDB +at server bootstrap or server start if they are not found or are +not of the right form. +@return DB_SUCCESS or error code */ +dberr_t +dict_create_or_check_foreign_constraint_tables(void) +/*================================================*/ +{ + trx_t* trx; + my_bool srv_file_per_table_backup; + dberr_t err; + dberr_t sys_foreign_err; + dberr_t sys_foreign_cols_err; + + ut_ad(!srv_any_background_activity()); + + /* Note: The master thread has not been started at this point. */ + + + sys_foreign_err = dict_check_if_system_table_exists( + "SYS_FOREIGN", DICT_NUM_FIELDS__SYS_FOREIGN + 1, 3); + sys_foreign_cols_err = dict_check_if_system_table_exists( + "SYS_FOREIGN_COLS", DICT_NUM_FIELDS__SYS_FOREIGN_COLS + 1, 1); + + if (sys_foreign_err == DB_SUCCESS + && sys_foreign_cols_err == DB_SUCCESS) { + return(DB_SUCCESS); + } + + if (srv_read_only_mode + || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO) { + return(DB_READ_ONLY); + } + + trx = trx_create(); + + trx_set_dict_operation(trx, TRX_DICT_OP_TABLE); + + trx->op_info = "creating foreign key sys tables"; + + row_mysql_lock_data_dictionary(trx); + + /* Check which incomplete table definition to drop. */ + + if (sys_foreign_err == DB_CORRUPTION) { + row_drop_table_after_create_fail("SYS_FOREIGN", trx); + } + + if (sys_foreign_cols_err == DB_CORRUPTION) { + row_drop_table_after_create_fail("SYS_FOREIGN_COLS", trx); + } + + ib::info() << "Creating foreign key constraint system tables."; + + /* NOTE: in dict_load_foreigns we use the fact that + there are 2 secondary indexes on SYS_FOREIGN, and they + are defined just like below */ + + /* NOTE: when designing InnoDB's foreign key support in 2001, we made + an error and made the table names and the foreign key id of type + 'CHAR' (internally, really a VARCHAR). We should have made the type + VARBINARY, like in other InnoDB system tables, to get a clean + design. */ + + srv_file_per_table_backup = srv_file_per_table; + + /* We always want SYSTEM tables to be created inside the system + tablespace. */ + + srv_file_per_table = 0; + + err = que_eval_sql( + NULL, + "PROCEDURE CREATE_FOREIGN_SYS_TABLES_PROC () IS\n" + "BEGIN\n" + "CREATE TABLE\n" + "SYS_FOREIGN(ID CHAR, FOR_NAME CHAR," + " REF_NAME CHAR, N_COLS INT);\n" + "CREATE UNIQUE CLUSTERED INDEX ID_IND" + " ON SYS_FOREIGN (ID);\n" + "CREATE INDEX FOR_IND" + " ON SYS_FOREIGN (FOR_NAME);\n" + "CREATE INDEX REF_IND" + " ON SYS_FOREIGN (REF_NAME);\n" + "CREATE TABLE\n" + "SYS_FOREIGN_COLS(ID CHAR, POS INT," + " FOR_COL_NAME CHAR, REF_COL_NAME CHAR);\n" + "CREATE UNIQUE CLUSTERED INDEX ID_IND" + " ON SYS_FOREIGN_COLS (ID, POS);\n" + "END;\n", + FALSE, trx); + + if (UNIV_UNLIKELY(err != DB_SUCCESS)) { + ib::error() << "Creation of SYS_FOREIGN and SYS_FOREIGN_COLS" + " failed: " << err << ". Tablespace is" + " full. Dropping incompletely created tables."; + + ut_ad(err == DB_OUT_OF_FILE_SPACE + || err == DB_TOO_MANY_CONCURRENT_TRXS); + + row_drop_table_after_create_fail("SYS_FOREIGN", trx); + row_drop_table_after_create_fail("SYS_FOREIGN_COLS", trx); + + if (err == DB_OUT_OF_FILE_SPACE) { + err = DB_MUST_GET_MORE_FILE_SPACE; + } + } + + trx_commit_for_mysql(trx); + + row_mysql_unlock_data_dictionary(trx); + + trx->free(); + + srv_file_per_table = srv_file_per_table_backup; + + /* Note: The master thread has not been started at this point. */ + /* Confirm and move to the non-LRU part of the table LRU list. */ + sys_foreign_err = dict_check_if_system_table_exists( + "SYS_FOREIGN", DICT_NUM_FIELDS__SYS_FOREIGN + 1, 3); + ut_a(sys_foreign_err == DB_SUCCESS); + + sys_foreign_cols_err = dict_check_if_system_table_exists( + "SYS_FOREIGN_COLS", DICT_NUM_FIELDS__SYS_FOREIGN_COLS + 1, 1); + ut_a(sys_foreign_cols_err == DB_SUCCESS); + + return(err); +} +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ + /** Creates the virtual column system table (SYS_VIRTUAL) inside InnoDB at server bootstrap or server start if the table is not found or is not of the right form. diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index 0402ae5013f..b42cee7d514 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -3661,6 +3661,7 @@ dict_table_get_highest_foreign_id( DBUG_RETURN(biggest_id); } +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE /**********************************************************************//** Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement. @return DB_SUCCESS or DB_CANNOT_DROP_CONSTRAINT if syntax error or the @@ -3797,6 +3798,7 @@ syntax_error: return(DB_CANNOT_DROP_CONSTRAINT); } +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ /*==================== END OF FOREIGN KEY PROCESSING ====================*/ diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc index 44f46611b3c..133a6f204f2 100644 --- a/storage/innobase/dict/dict0load.cc +++ b/storage/innobase/dict/dict0load.cc @@ -507,6 +507,157 @@ dict_process_sys_fields_rec( } +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE +/********************************************************************//** +This function parses a SYS_FOREIGN record and populate a dict_foreign_t +structure with the information from the record. For detail information +about SYS_FOREIGN fields, please refer to dict_load_foreign() function. +@return error message, or NULL on success */ +const char* +dict_process_sys_foreign_rec( +/*=========================*/ + mem_heap_t* heap, /*!< in/out: heap memory */ + const rec_t* rec, /*!< in: current SYS_FOREIGN rec */ + dict_foreign_t* foreign) /*!< out: dict_foreign_t struct + to be filled */ +{ + ulint len; + const byte* field; + + if (rec_get_deleted_flag(rec, 0)) { + return("delete-marked record in SYS_FOREIGN"); + } + + if (rec_get_n_fields_old(rec) != DICT_NUM_FIELDS__SYS_FOREIGN) { + return("wrong number of columns in SYS_FOREIGN record"); + } + + field = rec_get_nth_field_old( + rec, DICT_FLD__SYS_FOREIGN__ID, &len); + if (len == 0 || len == UNIV_SQL_NULL) { +err_len: + return("incorrect column length in SYS_FOREIGN"); + } + + /* This receives a dict_foreign_t* that points to a stack variable. + So dict_foreign_free(foreign) is not used as elsewhere. + Since the heap used here is freed elsewhere, foreign->heap + is not assigned. */ + foreign->id = mem_heap_strdupl(heap, (const char*) field, len); + + rec_get_nth_field_offs_old( + rec, DICT_FLD__SYS_FOREIGN__DB_TRX_ID, &len); + if (len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL) { + goto err_len; + } + rec_get_nth_field_offs_old( + rec, DICT_FLD__SYS_FOREIGN__DB_ROLL_PTR, &len); + if (len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL) { + goto err_len; + } + + /* The _lookup versions of the referenced and foreign table names + are not assigned since they are not used in this dict_foreign_t */ + + field = rec_get_nth_field_old( + rec, DICT_FLD__SYS_FOREIGN__FOR_NAME, &len); + if (len == 0 || len == UNIV_SQL_NULL) { + goto err_len; + } + foreign->foreign_table_name = mem_heap_strdupl( + heap, (const char*) field, len); + + field = rec_get_nth_field_old( + rec, DICT_FLD__SYS_FOREIGN__REF_NAME, &len); + if (len == 0 || len == UNIV_SQL_NULL) { + goto err_len; + } + foreign->referenced_table_name = mem_heap_strdupl( + heap, (const char*) field, len); + + field = rec_get_nth_field_old( + rec, DICT_FLD__SYS_FOREIGN__N_COLS, &len); + if (len != 4) { + goto err_len; + } + uint32_t n_fields_and_type = mach_read_from_4(field); + + foreign->type = n_fields_and_type >> 24 & ((1U << 6) - 1); + foreign->n_fields = n_fields_and_type & dict_index_t::MAX_N_FIELDS; + + return(NULL); +} + +/********************************************************************//** +This function parses a SYS_FOREIGN_COLS record and extract necessary +information from the record and return to caller. +@return error message, or NULL on success */ +const char* +dict_process_sys_foreign_col_rec( +/*=============================*/ + mem_heap_t* heap, /*!< in/out: heap memory */ + const rec_t* rec, /*!< in: current SYS_FOREIGN_COLS rec */ + const char** name, /*!< out: foreign key constraint name */ + const char** for_col_name, /*!< out: referencing column name */ + const char** ref_col_name, /*!< out: referenced column name + in referenced table */ + ulint* pos) /*!< out: column position */ +{ + ulint len; + const byte* field; + + if (rec_get_deleted_flag(rec, 0)) { + return("delete-marked record in SYS_FOREIGN_COLS"); + } + + if (rec_get_n_fields_old(rec) != DICT_NUM_FIELDS__SYS_FOREIGN_COLS) { + return("wrong number of columns in SYS_FOREIGN_COLS record"); + } + + field = rec_get_nth_field_old( + rec, DICT_FLD__SYS_FOREIGN_COLS__ID, &len); + if (len == 0 || len == UNIV_SQL_NULL) { +err_len: + return("incorrect column length in SYS_FOREIGN_COLS"); + } + *name = mem_heap_strdupl(heap, (char*) field, len); + + field = rec_get_nth_field_old( + rec, DICT_FLD__SYS_FOREIGN_COLS__POS, &len); + if (len != 4) { + goto err_len; + } + *pos = mach_read_from_4(field); + + rec_get_nth_field_offs_old( + rec, DICT_FLD__SYS_FOREIGN_COLS__DB_TRX_ID, &len); + if (len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL) { + goto err_len; + } + rec_get_nth_field_offs_old( + rec, DICT_FLD__SYS_FOREIGN_COLS__DB_ROLL_PTR, &len); + if (len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL) { + goto err_len; + } + + field = rec_get_nth_field_old( + rec, DICT_FLD__SYS_FOREIGN_COLS__FOR_COL_NAME, &len); + if (len == 0 || len == UNIV_SQL_NULL) { + goto err_len; + } + *for_col_name = mem_heap_strdupl(heap, (char*) field, len); + + field = rec_get_nth_field_old( + rec, DICT_FLD__SYS_FOREIGN_COLS__REF_COL_NAME, &len); + if (len == 0 || len == UNIV_SQL_NULL) { + goto err_len; + } + *ref_col_name = mem_heap_strdupl(heap, (char*) field, len); + + return(NULL); +} +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ + /********************************************************************//** This function parses a SYS_TABLESPACES record, extracts necessary information from the record and returns to caller. diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 6092dd337f0..a79b358728b 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -47,6 +47,7 @@ this program; if not, write to the Free Software Foundation, Inc., #include <strfunc.h> #include <sql_acl.h> #include <sql_class.h> +#include <sql_rename.h> #include <sql_show.h> #include <sql_table.h> #include <table_cache.h> @@ -482,6 +483,11 @@ const struct _ft_vft_ext ft_vft_ext_result = {innobase_fts_get_version, innobase_fts_retrieve_docid, innobase_fts_count_matches}; +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE +static dberr_t fk_check_legacy_storage(const char* table_name, trx_t* trx); +static dberr_t fk_upgrade_legacy_storage(dict_table_t* table, trx_t* trx, THD *thd, TABLE_SHARE *share); +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ + #ifdef HAVE_PSI_INTERFACE # define PSI_KEY(n) {&n##_key, #n, 0} /* All RWLOCK used in Innodb are SX-locks */ @@ -1797,6 +1803,10 @@ convert_error_code_to_mysql( return(HA_ERR_FTS_TOO_MANY_WORDS_IN_PHRASE); case DB_COMPUTE_VALUE_FAILED: return(HA_ERR_GENERIC); // impossible +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE + case DB_LEGACY_FK: + return(HA_ERR_FK_UPGRADE); +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ } } @@ -5399,9 +5409,10 @@ initialize_auto_increment(dict_table_t* table, const Field* field) @return error code @retval 0 on success */ int -ha_innobase::open(const char* name, int, uint) +ha_innobase::open(const char* name, int, uint open_flags) { char norm_name[FN_REFLEN]; + dberr_t err; DBUG_ENTER("ha_innobase::open"); @@ -5509,8 +5520,39 @@ ha_innobase::open(const char* name, int, uint) } } +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE + trx_t *trx = innobase_trx_allocate(thd); + if (!trx) { + DBUG_RETURN(HA_ERR_OUT_OF_MEM); + } + if (open_flags & HA_OPEN_FOR_REPAIR) { + err = fk_upgrade_legacy_storage(ib_table, trx, thd, table->s); + if (err == DB_LEGACY_FK) { + err = fk_check_legacy_storage(ib_table->name.m_name, trx); + if (err == DB_LEGACY_FK) { + push_warning_printf( + thd, + Sql_condition::WARN_LEVEL_WARN, + HA_ERR_FK_UPGRADE, + "Table %s failed to upgrade foreign keys (index is not corrupt)!", + table_share->table_name.str); + } + } + } else { + err = fk_check_legacy_storage(ib_table->name.m_name, trx); + } + trx_commit_for_mysql(trx); + trx->error_state = DB_SUCCESS; + trx->free(); + if (err != DB_SUCCESS) { + dict_table_close(ib_table, FALSE, FALSE); + DBUG_RETURN(convert_error_code_to_mysql( + err, ib_table->flags, NULL)); + } +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ + mutex_enter(&dict_sys.mutex); - dberr_t err = dict_load_foreigns(ib_table, table->s, NULL, false, DICT_ERR_IGNORE_FK_NOKEY); + err = dict_load_foreigns(ib_table, table->s, NULL, false, DICT_ERR_IGNORE_FK_NOKEY); mutex_exit(&dict_sys.mutex); if (err != DB_SUCCESS) { dict_table_close(ib_table, FALSE, FALSE); @@ -10186,7 +10228,7 @@ create_table_info_t::create_table_def() table->name.m_name, field->field_name.str); err_col: dict_mem_table_free(table); - ut_ad(trx_state_eq(m_trx, TRX_STATE_NOT_STARTED)); +// ut_ad(trx_state_eq(m_trx, TRX_STATE_NOT_STARTED)); DBUG_RETURN(HA_ERR_GENERIC); } @@ -12151,6 +12193,30 @@ create_table_info_t::create_foreign_keys() return (DB_SUCCESS); } +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE +int create_table_info_t::check_legacy_fk() +{ + char table_name[MAX_FULL_NAME_LEN + 1]; + char *bufptr= table_name; + size_t len; + if (dict_table_t::build_name(LEX_STRING_WITH_LEN(m_form->s->db), + LEX_STRING_WITH_LEN(m_form->s->table_name), + bufptr, len)) { + return HA_ERR_OUT_OF_MEM; + } + row_drop_table_check_legacy_data data; + + dberr_t err = row_drop_table_check_legacy_fk(m_trx, table_name, data); + if (err != DB_SUCCESS) { + return convert_error_code_to_mysql(err, 0, NULL); + } + if (data.found) { + return HA_ERR_FK_UPGRADE; + } + return 0; +} +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ + /** Create the internal innodb table. @param create_fk whether to add FOREIGN KEY constraints */ int create_table_info_t::create_table(bool create_fk) @@ -12169,6 +12235,15 @@ int create_table_info_t::create_table(bool create_fk) the primary key is always number 0, if it exists */ ut_a(primary_key_no == -1 || primary_key_no == 0); +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE + if (enum_sql_command(thd_sql_command(m_thd)) == SQLCOM_ALTER_TABLE) { + error = check_legacy_fk(); + if (error) { + DBUG_RETURN(error); + } + } +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ + error = create_table_def(); if (error) { @@ -19380,6 +19455,84 @@ static MYSQL_SYSVAR_BOOL(encrypt_temporary_tables, innodb_encrypt_temporary_tabl "Enrypt the temporary table data.", NULL, NULL, false); +#ifdef UNIV_DEBUG + +static char* innodb_eval_sql; + +static int innodb_eval_sql_validate(THD *thd, st_mysql_sys_var*, + void* save, st_mysql_value* value) +{ + /** Preamble to all SQL statements. */ + static const char* sql_begin= "PROCEDURE P() IS\n"; + + /** Postamble to non-committing SQL statements. */ + static const char* sql_end= "\nEND;\n"; + + char *sql, *str; + char buff[8192]; // size doesn't matter: val_str() reallocates + int len = sizeof(buff); + + ut_ad(save != NULL); + ut_ad(value != NULL); + + bool free_trx = false; + trx_t * trx = thd_to_trx(thd); + if (!trx) { + trx = trx_create(); + if (!trx) { + my_error(ER_OUT_OF_RESOURCES, MYF(0)); + return 1; + } + free_trx = true; + } + trx_start_if_not_started(trx, true); + sql = (char*) value->val_str(value, buff, &len); + if (!sql) { +mem_err: + trx->error_state = DB_SUCCESS; + trx->free(); + my_error(ER_OUT_OF_RESOURCES, MYF(0)); + return 1; + } + str = ut_str3cat(sql_begin, sql, sql_end); + if (!str) { + goto mem_err; + } + + trx->op_info = "Evaluating internal SQL"; + + pars_info_t* info = pars_info_create(); + info->fatal_syntax_err = false; + dberr_t err = que_eval_sql(info, str, true, trx); + ut_free(str); + if (err != DB_SUCCESS) { + trx->op_info = "Rollback of internal trx on innodb_eval_sql"; + trx->dict_operation_lock_mode = RW_X_LATCH; + trx->rollback(); + trx->dict_operation_lock_mode = 0; + trx->op_info = ""; + ut_a(trx->error_state == DB_SUCCESS); + if (free_trx) { + trx->free(); + } + ib_push_warning(trx, err, (err == DB_ERROR ? "Syntax error" : ut_strerr(err))); + return 1; + } + trx_commit_for_mysql(trx); + if (free_trx) { + trx->free(); + } + *static_cast<const char**>(save) = sql; + return 0; +} + +static MYSQL_SYSVAR_STR(eval_sql, + innodb_eval_sql, + PLUGIN_VAR_OPCMDARG|PLUGIN_VAR_MEMALLOC, + "Evaluate internal SQL", + innodb_eval_sql_validate, NULL, NULL); +#endif /* UNIV_DEBUG */ + static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(autoextend_increment), MYSQL_SYSVAR(buffer_pool_size), @@ -19542,6 +19695,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(dict_stats_disabled_debug), MYSQL_SYSVAR(master_thread_disabled_debug), MYSQL_SYSVAR(sync_debug), + MYSQL_SYSVAR(eval_sql), #endif /* UNIV_DEBUG */ MYSQL_SYSVAR(force_primary_key), MYSQL_SYSVAR(fatal_semaphore_wait_threshold), @@ -19603,6 +19757,10 @@ i_s_innodb_sys_tablestats, i_s_innodb_sys_indexes, i_s_innodb_sys_columns, i_s_innodb_sys_fields, +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE +i_s_innodb_sys_foreign, +i_s_innodb_sys_foreign_cols, +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ i_s_innodb_sys_tablespaces, i_s_innodb_sys_datafiles, i_s_innodb_sys_virtual, @@ -21015,6 +21173,471 @@ void ins_node_t::vers_update_end(row_prebuilt_t *prebuilt, bool history_row) } } +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE +struct fk_legacy_data +{ + trx_t *trx; + dict_table_t *table; + TABLE_SHARE *s; + char ref_name[MAX_FULL_NAME_LEN + 1]; + FK_info *fk; + dberr_t err; + FK_list foreign_keys; + fk_legacy_data(trx_t *_t, dict_table_t *_tab, TABLE_SHARE *_s) : trx(_t), table(_tab), s(_s), fk(NULL), err(DB_SUCCESS) + {}; +}; + +static +ibool +fk_upgrade_create_fk( +/*=================*/ + void* row, /*!< in: sel_node_t* */ + void* user_arg) /*!< in: fk_legacy_data */ +{ + fk_legacy_data &d = *(fk_legacy_data *) user_arg; + d.err = DB_CANNOT_ADD_CONSTRAINT; + sel_node_t* node = static_cast<sel_node_t*>(row); + que_node_t* exp = node->select_list; + + // Get foreign key ID + dfield_t* fld = que_node_get_val(exp); + char src_id[MAX_FULL_NAME_LEN + 1]; + char dst_id[MAX_TABLE_NAME_LEN + 1]; + char src_ref[MAX_FULL_NAME_LEN + 1]; + ut_a(fld->len <= MAX_FULL_NAME_LEN); + memcpy(src_id, fld->data, fld->len); + src_id[fld->len] = 0; + LEX_CSTRING id; + id.str = (const char*) memchr(src_id, '/', fld->len); + + if (id.str == NULL) { + id = { (char *) src_id, fld->len }; + } else { + id.str++; + size_t prefix_len = id.str - src_id; + if (prefix_len >= fld->len) { + ib_foreign_warn(d.trx, DB_CANNOT_ADD_CONSTRAINT, d.s->table_name.str, + "Upgrade table %s with foreign key %s constraint" + " failed. Wrong foreign key ID!", + d.s->table_name.str, src_id); + return 0; + } + id.length = fld->len - prefix_len; + } + + id.length = filename_to_tablename(id.str, dst_id, sizeof(dst_id)); + ut_a(id.length); + id.str = dst_id; + + for (FK_info &fk: d.s->foreign_keys) { + if (0 == cmp_ident(fk.foreign_id, id)) { + ib_foreign_warn(d.trx, DB_CANNOT_ADD_CONSTRAINT, d.s->table_name.str, + "Upgrade table %s with foreign key %s constraint" + " failed. Duplicate foreign key ID!", + d.s->table_name.str, src_id); + return 0; + } + } + + // Get referenced table name + exp = que_node_get_next(exp); + fld = que_node_get_val(exp); + ut_a(fld); + char dst_db[MAX_TABLE_NAME_LEN + 1]; + char dst_table[MAX_TABLE_NAME_LEN + 1]; + ut_a(fld->len <= MAX_FULL_NAME_LEN); + memcpy(src_ref, fld->data, fld->len); + src_ref[fld->len] = 0; + memcpy(d.ref_name, src_ref, fld->len + 1); + LEX_CSTRING db, table; + table.str = (const char*) memchr(src_ref, '/', fld->len); + + if (table.str == NULL) { + table = { (char *) src_ref, fld->len }; + db = { NULL, 0 }; + } else { + table.str++; + size_t prefix_len = table.str - src_ref; + if (prefix_len >= fld->len) { + ib_foreign_warn(d.trx, DB_CANNOT_ADD_CONSTRAINT, d.s->table_name.str, + "Upgrade table %s with foreign key %s constraint" + " failed. Wrong referenced table name!", + d.s->table_name.str, src_id); + return 0; + } + table.length = fld->len - prefix_len; + db = { src_ref, prefix_len - 1 }; + src_ref[db.length] = 0; + } + + table.length = filename_to_tablename(table.str, dst_table, sizeof(dst_table)); + ut_a(table.length); + table.str = dst_table; + + if (db.length) { + db.length = filename_to_tablename(db.str, dst_db, sizeof(dst_db)); + ut_a(db.length); + db.str = dst_db; + } + + ut_a(!que_node_get_next(exp)); + d.fk= new (&d.s->mem_root) FK_info(); + if (!d.fk) { + d.err = DB_OUT_OF_MEMORY; + return 0; + } + d.fk->foreign_id.strdup(&d.s->mem_root, id); + if (!d.fk->foreign_id.str) { + d.err = DB_OUT_OF_MEMORY; + return 0; + } + d.fk->foreign_db = d.s->db; + d.fk->foreign_table = d.s->table_name; + if (0 != cmp_table(d.s->db, db)) { + d.fk->referenced_db.strdup(&d.s->mem_root, db); + if (!d.fk->referenced_db.str) { + d.err = DB_OUT_OF_MEMORY; + return 0; + } + } + d.fk->referenced_table.strdup(&d.s->mem_root, table); + if (!d.fk->referenced_table.str) { + d.err = DB_OUT_OF_MEMORY; + return 0; + } + d.err = DB_LEGACY_FK; + return 1; +} + +static +ibool +fk_upgrade_add_col( +/*=================*/ + void* row, /*!< in: sel_node_t* */ + void* user_arg) /*!< in: fk_legacy_data */ +{ + fk_legacy_data &d = *(fk_legacy_data *) user_arg; + if (d.err != DB_LEGACY_FK) { + return 0; + } + sel_node_t* node = static_cast<sel_node_t*>(row); + que_node_t* exp = node->select_list; + + // Get FOR_COL_NAME + dfield_t* fld = que_node_get_val(exp); + ut_a(fld); + Lex_cstring *dst_f= new (&d.s->mem_root) Lex_cstring(); + if (!dst_f) { + d.err = DB_OUT_OF_MEMORY; + return 0; + } + dst_f->strdup(&d.s->mem_root, { (char *) fld->data, fld->len }); + if (!dst_f->str) { + d.err = DB_OUT_OF_MEMORY; + return 0; + } + + if (d.fk->foreign_fields.push_back(dst_f, &d.s->mem_root)) { + d.err = DB_OUT_OF_MEMORY; + return 0; + } + + // Get REF_COL_NAME + exp = que_node_get_next(exp); + fld = que_node_get_val(exp); + ut_a(exp); + ut_a(fld); + dst_f= new (&d.s->mem_root) Lex_cstring(); + if (!dst_f) { + d.err = DB_OUT_OF_MEMORY; + return 0; + } + dst_f->strdup(&d.s->mem_root, { (char *) fld->data, fld->len }); + if (!dst_f->str) { + d.err = DB_OUT_OF_MEMORY; + return 0; + } + + if (d.fk->referenced_fields.push_back(dst_f, &d.s->mem_root)) { + d.err = DB_OUT_OF_MEMORY; + return 0; + } + + ut_a(!que_node_get_next(exp)); + return 1; +} + +static +ibool +fk_upgrade_push_fk( +/*=================*/ + void* row, /*!< in: sel_node_t* */ + void* user_arg) /*!< in: fk_legacy_data */ +{ + fk_legacy_data &d = *(fk_legacy_data *) user_arg; + if (d.err != DB_LEGACY_FK) { + return 0; + } + // Check indexes on ref and on foreign + FK_info &fk = *d.fk; + ut_ad(fk.foreign_fields.elements < MAX_NUM_FK_COLUMNS); + ut_ad(fk.foreign_fields.elements == fk.referenced_fields.elements); + uint i= 0; + const char* column_names[MAX_NUM_FK_COLUMNS]; + const char* ref_column_names[MAX_NUM_FK_COLUMNS]; + dict_index_t* index; + List_iterator_fast<Lex_cstring> it(fk.referenced_fields); + for (Lex_cstring &col: fk.foreign_fields) { + column_names[i] = col.str; + Lex_cstring *rcol = it++; + ref_column_names[i++] = rcol->str; + } + mutex_enter(&dict_sys.mutex); + index = dict_foreign_find_index( + d.table, NULL, column_names, fk.foreign_fields.elements, + NULL, true, false); + if (!index) { + mutex_exit(&dict_sys.mutex); + ib_foreign_warn(d.trx, DB_CANNOT_ADD_CONSTRAINT, d.s->table_name.str, + "Upgrade table %s with foreign key %s constraint" + " failed. Foreign key index not found!", + d.s->table_name.str, fk.foreign_id.str); + d.err = DB_CANNOT_ADD_CONSTRAINT; + return 0; + } + dict_table_t* ref_table = dict_table_open_on_name(d.ref_name, true, false, DICT_ERR_IGNORE_FK_NOKEY); + if (!ref_table) { + mutex_exit(&dict_sys.mutex); + ib_foreign_warn(d.trx, DB_CANNOT_ADD_CONSTRAINT, d.s->table_name.str, + "Upgrade table %s with foreign key %s constraint" + " failed. Could not open referenced table!", + d.s->table_name.str, fk.foreign_id.str); + d.err = DB_CANNOT_ADD_CONSTRAINT; + return 0; + } + index = dict_foreign_find_index( + ref_table, NULL, ref_column_names, fk.foreign_fields.elements, + NULL, true, false); + dict_table_close(ref_table, true, false); + mutex_exit(&dict_sys.mutex); + if (!index) { + ib_foreign_warn(d.trx, DB_CANNOT_ADD_CONSTRAINT, d.s->table_name.str, + "Upgrade table %s with foreign key %s constraint" + " failed. Referenced key index not found!", + d.s->table_name.str, fk.foreign_id.str); + d.err = DB_CANNOT_ADD_CONSTRAINT; + return 0; + } + if (d.foreign_keys.push_back(d.fk, &d.s->mem_root)) { + d.err = DB_OUT_OF_MEMORY; + return 0; + } + d.fk = NULL; + return 1; +} + +static +dberr_t +fk_upgrade_legacy_storage(dict_table_t* table, trx_t* trx, THD *thd, TABLE_SHARE *share) +{ + pars_info_t* info; + fk_legacy_data d(trx, table, share); + + info = pars_info_create(); + if (!info) { + return DB_OUT_OF_MEMORY; + } + pars_info_bind_function(info, "fk_upgrade_create_fk", fk_upgrade_create_fk, &d); + pars_info_bind_function(info, "fk_upgrade_add_col", fk_upgrade_add_col, &d); + pars_info_bind_function(info, "fk_upgrade_push_fk", fk_upgrade_push_fk, &d); + pars_info_add_str_literal(info, "for_name", table->name.m_name); + static const char sql_fetch[] = + "PROCEDURE FETCH_PROC () IS\n" + "fk_id CHAR;\n" + "unused CHAR;\n" + "DECLARE FUNCTION fk_upgrade_create_fk;\n" + "DECLARE FUNCTION fk_upgrade_add_col;\n" + "DECLARE FUNCTION fk_upgrade_push_fk;\n" + + "DECLARE CURSOR c IS" + " SELECT ID, REF_NAME FROM SYS_FOREIGN" + " WHERE FOR_NAME = :for_name;" + + "DECLARE CURSOR c2 IS" + " SELECT FOR_COL_NAME, REF_COL_NAME FROM SYS_FOREIGN_COLS" + " WHERE ID = fk_id;" + + "DECLARE CURSOR c3 IS" + " SELECT ID FROM SYS_FOREIGN;" + + "BEGIN\n" + "OPEN c;\n" + "WHILE 1 = 1 LOOP\n" + " FETCH c INTO fk_upgrade_create_fk() fk_id, unused;\n" + " IF (SQL % NOTFOUND) THEN\n" + " EXIT;\n" + " END IF;\n" + " OPEN c2;\n" + " WHILE 1 = 1 LOOP\n" + " FETCH c2 INTO fk_upgrade_add_col();\n" + " IF (SQL % NOTFOUND) THEN\n" + " CLOSE c2;\n" + " OPEN c3;\n" + " FETCH c3 INTO fk_upgrade_push_fk();\n" + " CLOSE c3;\n" + " EXIT;\n" + " END IF;\n" + " END LOOP;\n" + "END LOOP;\n" + "CLOSE c;\n" + "END;\n"; + + dberr_t err = que_eval_sql(info, sql_fetch, true, trx); + if (err != DB_SUCCESS) { + return err; + } + + if (d.err != DB_LEGACY_FK) { + return d.err; + } + + ut_ad(d.foreign_keys.elements); + + // Got legacy foreign keys, update referenced shares + FK_table_backup fk_table_backup; + FK_create_vector ref_shares; + if (d.s->fk_handle_create(thd, ref_shares, &d.foreign_keys)) { + err = DB_ERROR; + goto rollback; + } + + if (fk_table_backup.init(d.s)) { + err = DB_OUT_OF_MEMORY; + goto rollback; + } + + // Push to main share. Share is already locked by Open_table_context. + for (FK_info &fk: d.foreign_keys) { + if (d.s->foreign_keys.push_back(&fk, &d.s->mem_root)) { + err = DB_OUT_OF_MEMORY; + goto rollback; + } + } + + // Update foreign FRM + if (d.s->fk_write_shadow_frm()) { + err = DB_ERROR; + goto rollback; + } + + // Update referenced FRMs + for (FK_ddl_backup &bak: ref_shares) { + if (bak.sa.share->fk_install_shadow_frm()) { + // TODO: MDEV-21053 atomicity + err = DB_ERROR; + goto rollback; + } + } + + if (d.s->fk_install_shadow_frm()) { + err = DB_ERROR; + goto rollback; + } + + fk_table_backup.commit(); + + // Drop legacy foreign keys + static const char sql_drop[] = + "PROCEDURE DROP_PROC () IS\n" + "fk_id CHAR;\n" + "DECLARE CURSOR c IS\n" + "SELECT ID FROM SYS_FOREIGN\n" + "WHERE FOR_NAME = :for_name\n" + "LOCK IN SHARE MODE;\n" + "BEGIN\n" + "OPEN c;\n" + "WHILE 1 = 1 LOOP\n" + " FETCH c INTO fk_id;\n" + " IF (SQL % NOTFOUND) THEN\n" + " EXIT;\n" + " END IF;\n" + " DELETE FROM SYS_FOREIGN_COLS\n" + " WHERE ID = fk_id;\n" + " DELETE FROM SYS_FOREIGN\n" + " WHERE ID = fk_id;\n" + "END LOOP;\n" + "CLOSE c;\n" + "COMMIT WORK;\n" + "END;\n"; + + info = pars_info_create(); + if (!info) { + return DB_OUT_OF_MEMORY; + } + pars_info_add_str_literal(info, "for_name", table->name.m_name); + + err = que_eval_sql(info, sql_drop, true, trx); + if (err != DB_SUCCESS) { + return err; + } + + return DB_LEGACY_FK; + +rollback: + for (FK_ddl_backup &bak: ref_shares) { + bak.rollback(); + } + return err; +} + +static +ibool +fk_check_upgrade( +/*=================*/ + void* row, /*!< in: sel_node_t* */ + void* user_arg) /*!< in: bool do_upgrade */ +{ + bool &do_upgrade = *(bool *) user_arg; + do_upgrade = true; + return 0; +} + +static +dberr_t +fk_check_legacy_storage(const char* table_name, trx_t* trx) +{ + pars_info_t* info; + bool do_upgrade = false; + + info = pars_info_create(); + if (!info) { + return DB_OUT_OF_MEMORY; + } + pars_info_bind_function(info, "fk_check_upgrade", fk_check_upgrade, &do_upgrade); + pars_info_add_str_literal(info, "for_name", table_name); + static const char sql[] = + "PROCEDURE FK_PROC () IS\n" + "DECLARE FUNCTION fk_check_upgrade;\n" + + "DECLARE CURSOR c IS" + " SELECT ID FROM SYS_FOREIGN" + " WHERE FOR_NAME = :for_name;" + + "BEGIN\n" + "OPEN c;\n" + "FETCH c INTO fk_check_upgrade();\n" + "CLOSE c;\n" + "END;\n"; + + dberr_t err = que_eval_sql(info, sql, true, trx); + if (err == DB_SUCCESS && do_upgrade) { + err = DB_LEGACY_FK; + } + + return err; +} +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ + dberr_t dict_load_foreigns( dict_table_t* table, @@ -21100,7 +21723,7 @@ dict_load_foreigns( if (!foreign->foreign_table_name) return DB_OUT_OF_MEMORY; - if (dict_table_t::build_name(LEX_STRING_WITH_LEN(fk.referenced_db), + if (dict_table_t::build_name(LEX_STRING_WITH_LEN(fk.ref_db()), LEX_STRING_WITH_LEN(fk.referenced_table), bufptr, len)) { return DB_CANNOT_ADD_CONSTRAINT; } diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index 80cac0887a2..d8e04676db5 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -102,6 +102,13 @@ public: int open(const char *name, int mode, uint test_if_locked) override; +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE + bool auto_repair(int error) const override + { + return (error == HA_ERR_FK_UPGRADE); + } +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ + handler* clone(const char *name, MEM_ROOT *mem_root) override; int close(void) override; @@ -744,6 +751,10 @@ private: /** Create the internal innodb table definition. */ int create_table_def(); +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE + int check_legacy_fk(); +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ + /** Connection thread handle. */ THD* m_thd; diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 507f9cbba4f..355f1259f29 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -7171,6 +7171,71 @@ err_exit: DBUG_RETURN(true); } +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE +static +ibool +innobase_drop_column_check_legacy_step( +/*=================*/ + void* row, /*!< in: sel_node_t* */ + void* user_arg) /*!< out: bool found */ +{ + bool &found = *(bool *) user_arg; + sel_node_t* node = static_cast<sel_node_t*>(row); + que_node_t* exp = node->select_list; + found = true; + ut_a(!que_node_get_next(exp)); + return 0; +} + +static +dberr_t innobase_drop_column_check_legacy_fk(trx_t* trx, const char * table_name, + const char * col_name, bool &found) +{ + static const char sql_check[] = + "PROCEDURE FK_PROC () IS\n" + "fk_id CHAR;\n" + "DECLARE FUNCTION innobase_drop_column_check_legacy_step;\n" + + "DECLARE CURSOR c IS" + " SELECT ID FROM SYS_FOREIGN" + " WHERE REF_NAME = :ref_name;\n" + + "DECLARE CURSOR c2 IS" + " SELECT FOR_COL_NAME FROM SYS_FOREIGN_COLS" + " WHERE ID = fk_id AND REF_COL_NAME = :ref_col_name;\n" + + "BEGIN\n" + "OPEN c;\n" + "WHILE 1 = 1 LOOP\n" + " FETCH c INTO fk_id;\n" + " IF (SQL % NOTFOUND) THEN\n" + " EXIT;\n" + " END IF;\n" + " OPEN c2;\n" + " FETCH c2 INTO innobase_drop_column_check_legacy_step();\n" + " CLOSE c2;\n" + "END LOOP;\n" + "CLOSE c;\n" + "END;\n"; + + pars_info_t* info = pars_info_create(); + if (!info) { + return DB_OUT_OF_MEMORY; + } + pars_info_bind_function(info, "innobase_drop_column_check_legacy_step", + innobase_drop_column_check_legacy_step, &found); + pars_info_add_str_literal(info, "ref_name", table_name); + pars_info_add_str_literal(info, "ref_col_name", col_name); + + dberr_t err = que_eval_sql(info, sql_check, false, trx); + if (err != DB_SUCCESS) { + return err; + } + + return DB_SUCCESS; +} +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ + /* Check whether an index is needed for the foreign key constraint. If so, if it is dropped, is there an equivalent index can play its role. @return true if the index is needed and can't be dropped */ @@ -7224,6 +7289,19 @@ innobase_check_foreign_key_index( } } +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE + bool found = false; + // NB: foreign keys always reference index by first field + if (DB_SUCCESS != innobase_drop_column_check_legacy_fk( + trx, indexed_table->name.m_name, index->fields[0].name, found)) { + return false; + } + if (found) { + trx->error_info = index; + return(true); + } +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ + fks = &indexed_table->foreign_set; /* Check for all FK references in current table using the index. */ @@ -8889,6 +8967,42 @@ err_exit: rename_foreign: trx->op_info = "renaming column in SYS_FOREIGN_COLS"; +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE + static const char sql_rename_ref[] = + "PROCEDURE FETCH_PROC () IS\n" + "fk_id CHAR;\n" + + "DECLARE CURSOR c IS" + " SELECT ID FROM SYS_FOREIGN" + " WHERE REF_NAME = :ref_name;\n" + + "BEGIN\n" + "OPEN c;\n" + "WHILE 1 = 1 LOOP\n" + " FETCH c INTO fk_id;\n" + " IF (SQL % NOTFOUND) THEN\n" + " EXIT;\n" + " END IF;\n" + " UPDATE SYS_FOREIGN_COLS" + " SET REF_COL_NAME = :new" + " WHERE ID = fk_id AND REF_COL_NAME = :old;\n" + "END LOOP;\n" + "CLOSE c;\n" + "END;\n"; + + pars_info_t* info = pars_info_create(); + + pars_info_add_str_literal(info, "ref_name", ctx.old_table->name.m_name); + pars_info_add_str_literal(info, "old", from); + pars_info_add_str_literal(info, "new", to); + + error = que_eval_sql(info, sql_rename_ref, false, trx); + + if (error != DB_SUCCESS) { + goto err_exit; + } +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ + std::set<dict_foreign_t*> fk_evict; bool foreign_modified; diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index 78235df58ba..3ec342a6e85 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -6057,6 +6057,400 @@ UNIV_INTERN struct st_maria_plugin i_s_innodb_sys_fields = STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE), }; +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE +namespace Show { +/** SYS_FOREIGN ********************************************/ +/* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_FOREIGN */ +static ST_FIELD_INFO innodb_sys_foreign_fields_info[] = +{ +#define SYS_FOREIGN_ID 0 + Column("ID", Varchar(NAME_LEN + 1), NOT_NULL), + +#define SYS_FOREIGN_FOR_NAME 1 + Column("FOR_NAME", Varchar(NAME_LEN + 1), NOT_NULL), + +#define SYS_FOREIGN_REF_NAME 2 + Column("REF_NAME", Varchar(NAME_LEN + 1), NOT_NULL), + +#define SYS_FOREIGN_NUM_COL 3 + Column("N_COLS", ULong(), NOT_NULL), + +#define SYS_FOREIGN_TYPE 4 + Column("TYPE", ULong(), NOT_NULL), + + CEnd() +}; +} // namespace Show + +/**********************************************************************//** +Function to fill information_schema.innodb_sys_foreign with information +collected by scanning SYS_FOREIGN table. +@return 0 on success */ +static +int +i_s_dict_fill_sys_foreign( +/*======================*/ + THD* thd, /*!< in: thread */ + dict_foreign_t* foreign, /*!< in: table */ + TABLE* table_to_fill) /*!< in/out: fill this table */ +{ + Field** fields; + + DBUG_ENTER("i_s_dict_fill_sys_foreign"); + + fields = table_to_fill->field; + + OK(field_store_string(fields[SYS_FOREIGN_ID], foreign->id)); + + OK(field_store_string(fields[SYS_FOREIGN_FOR_NAME], + foreign->foreign_table_name)); + + OK(field_store_string(fields[SYS_FOREIGN_REF_NAME], + foreign->referenced_table_name)); + + OK(fields[SYS_FOREIGN_NUM_COL]->store(foreign->n_fields)); + + OK(fields[SYS_FOREIGN_TYPE]->store(foreign->type)); + + OK(schema_table_store_record(thd, table_to_fill)); + + DBUG_RETURN(0); +} + +/*******************************************************************//** +Function to populate INFORMATION_SCHEMA.innodb_sys_foreign table. Loop +through each record in SYS_FOREIGN, and extract the foreign key +information. +@return 0 on success */ +static +int +i_s_sys_foreign_fill_table( +/*=======================*/ + THD* thd, /*!< in: thread */ + TABLE_LIST* tables, /*!< in/out: tables to fill */ + Item* ) /*!< in: condition (not used) */ +{ + btr_pcur_t pcur; + const rec_t* rec; + mem_heap_t* heap; + mtr_t mtr; + + DBUG_ENTER("i_s_sys_foreign_fill_table"); + RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str); + + /* deny access to user without PROCESS_ACL privilege */ + if (check_global_access(thd, PROCESS_ACL)) { + + DBUG_RETURN(0); + } + + heap = mem_heap_create(1000); + mutex_enter(&dict_sys.mutex); + mtr_start(&mtr); + + rec = dict_startscan_system(&pcur, &mtr, SYS_FOREIGN); + + while (rec) { + const char* err_msg; + dict_foreign_t foreign_rec; + + /* Populate a dict_foreign_t structure with information from + a SYS_FOREIGN row */ + err_msg = dict_process_sys_foreign_rec(heap, rec, &foreign_rec); + + mtr_commit(&mtr); + mutex_exit(&dict_sys.mutex); + + if (!err_msg) { + i_s_dict_fill_sys_foreign(thd, &foreign_rec, + tables->table); + } else { + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + ER_CANT_FIND_SYSTEM_REC, "%s", + err_msg); + } + + mem_heap_empty(heap); + + /* Get the next record */ + mtr_start(&mtr); + mutex_enter(&dict_sys.mutex); + rec = dict_getnext_system(&pcur, &mtr); + } + + mtr_commit(&mtr); + mutex_exit(&dict_sys.mutex); + mem_heap_free(heap); + + DBUG_RETURN(0); +} + +/*******************************************************************//** +Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_foreign +@return 0 on success */ +static +int +innodb_sys_foreign_init( +/*====================*/ + void* p) /*!< in/out: table schema object */ +{ + ST_SCHEMA_TABLE* schema; + + DBUG_ENTER("innodb_sys_foreign_init"); + + schema = (ST_SCHEMA_TABLE*) p; + + schema->fields_info = Show::innodb_sys_foreign_fields_info; + schema->fill_table = i_s_sys_foreign_fill_table; + + DBUG_RETURN(0); +} + +UNIV_INTERN struct st_maria_plugin i_s_innodb_sys_foreign = +{ + /* the plugin type (a MYSQL_XXX_PLUGIN value) */ + /* int */ + STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN), + + /* pointer to type-specific plugin descriptor */ + /* void* */ + STRUCT_FLD(info, &i_s_info), + + /* plugin name */ + /* const char* */ + STRUCT_FLD(name, "INNODB_SYS_FOREIGN"), + + /* plugin author (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(author, plugin_author), + + /* general descriptive text (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(descr, "InnoDB SYS_FOREIGN"), + + /* the plugin license (PLUGIN_LICENSE_XXX) */ + /* int */ + STRUCT_FLD(license, PLUGIN_LICENSE_GPL), + + /* the function to invoke when plugin is loaded */ + /* int (*)(void*); */ + STRUCT_FLD(init, innodb_sys_foreign_init), + + /* the function to invoke when plugin is unloaded */ + /* int (*)(void*); */ + STRUCT_FLD(deinit, i_s_common_deinit), + + /* plugin version (for SHOW PLUGINS) */ + /* unsigned int */ + STRUCT_FLD(version, INNODB_VERSION_SHORT), + + /* struct st_mysql_show_var* */ + STRUCT_FLD(status_vars, NULL), + + /* struct st_mysql_sys_var** */ + STRUCT_FLD(system_vars, NULL), + + /* Maria extension */ + STRUCT_FLD(version_info, INNODB_VERSION_STR), + STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE), +}; + +namespace Show { +/** SYS_FOREIGN_COLS ********************************************/ +/* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS */ +static ST_FIELD_INFO innodb_sys_foreign_cols_fields_info[] = +{ +#define SYS_FOREIGN_COL_ID 0 + Column("ID", Varchar(NAME_LEN + 1), NOT_NULL), + +#define SYS_FOREIGN_COL_FOR_NAME 1 + Column("FOR_COL_NAME", Varchar(NAME_CHAR_LEN), NOT_NULL), + +#define SYS_FOREIGN_COL_REF_NAME 2 + Column("REF_COL_NAME", Varchar(NAME_CHAR_LEN), NOT_NULL), + +#define SYS_FOREIGN_COL_POS 3 + Column("POS", ULong(), NOT_NULL), + + CEnd() +}; +} // namespace Show + +/**********************************************************************//** +Function to fill information_schema.innodb_sys_foreign_cols with information +collected by scanning SYS_FOREIGN_COLS table. +@return 0 on success */ +static +int +i_s_dict_fill_sys_foreign_cols( +/*==========================*/ + THD* thd, /*!< in: thread */ + const char* name, /*!< in: foreign key constraint name */ + const char* for_col_name, /*!< in: referencing column name*/ + const char* ref_col_name, /*!< in: referenced column + name */ + ulint pos, /*!< in: column position */ + TABLE* table_to_fill) /*!< in/out: fill this table */ +{ + Field** fields; + + DBUG_ENTER("i_s_dict_fill_sys_foreign_cols"); + + fields = table_to_fill->field; + + OK(field_store_string(fields[SYS_FOREIGN_COL_ID], name)); + + OK(field_store_string(fields[SYS_FOREIGN_COL_FOR_NAME], for_col_name)); + + OK(field_store_string(fields[SYS_FOREIGN_COL_REF_NAME], ref_col_name)); + + OK(fields[SYS_FOREIGN_COL_POS]->store(pos, true)); + + OK(schema_table_store_record(thd, table_to_fill)); + + DBUG_RETURN(0); +} +/*******************************************************************//** +Function to populate INFORMATION_SCHEMA.innodb_sys_foreign_cols table. Loop +through each record in SYS_FOREIGN_COLS, and extract the foreign key column +information and fill the INFORMATION_SCHEMA.innodb_sys_foreign_cols table. +@return 0 on success */ +static +int +i_s_sys_foreign_cols_fill_table( +/*============================*/ + THD* thd, /*!< in: thread */ + TABLE_LIST* tables, /*!< in/out: tables to fill */ + Item* ) /*!< in: condition (not used) */ +{ + btr_pcur_t pcur; + const rec_t* rec; + mem_heap_t* heap; + mtr_t mtr; + + DBUG_ENTER("i_s_sys_foreign_cols_fill_table"); + RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str); + + /* deny access to user without PROCESS_ACL privilege */ + if (check_global_access(thd, PROCESS_ACL)) { + DBUG_RETURN(0); + } + + heap = mem_heap_create(1000); + mutex_enter(&dict_sys.mutex); + mtr_start(&mtr); + + rec = dict_startscan_system(&pcur, &mtr, SYS_FOREIGN_COLS); + + while (rec) { + const char* err_msg; + const char* name; + const char* for_col_name; + const char* ref_col_name; + ulint pos; + + /* Extract necessary information from a SYS_FOREIGN_COLS row */ + err_msg = dict_process_sys_foreign_col_rec( + heap, rec, &name, &for_col_name, &ref_col_name, &pos); + + mtr_commit(&mtr); + mutex_exit(&dict_sys.mutex); + + if (!err_msg) { + i_s_dict_fill_sys_foreign_cols( + thd, name, for_col_name, ref_col_name, pos, + tables->table); + } else { + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + ER_CANT_FIND_SYSTEM_REC, "%s", + err_msg); + } + + mem_heap_empty(heap); + + /* Get the next record */ + mutex_enter(&dict_sys.mutex); + mtr_start(&mtr); + rec = dict_getnext_system(&pcur, &mtr); + } + + mtr_commit(&mtr); + mutex_exit(&dict_sys.mutex); + mem_heap_free(heap); + + DBUG_RETURN(0); +} +/*******************************************************************//** +Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_foreign_cols +@return 0 on success */ +static +int +innodb_sys_foreign_cols_init( +/*========================*/ + void* p) /*!< in/out: table schema object */ +{ + ST_SCHEMA_TABLE* schema; + + DBUG_ENTER("innodb_sys_foreign_cols_init"); + + schema = (ST_SCHEMA_TABLE*) p; + + schema->fields_info = Show::innodb_sys_foreign_cols_fields_info; + schema->fill_table = i_s_sys_foreign_cols_fill_table; + + DBUG_RETURN(0); +} + +UNIV_INTERN struct st_maria_plugin i_s_innodb_sys_foreign_cols = +{ + /* the plugin type (a MYSQL_XXX_PLUGIN value) */ + /* int */ + STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN), + + /* pointer to type-specific plugin descriptor */ + /* void* */ + STRUCT_FLD(info, &i_s_info), + + /* plugin name */ + /* const char* */ + STRUCT_FLD(name, "INNODB_SYS_FOREIGN_COLS"), + + /* plugin author (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(author, plugin_author), + + /* general descriptive text (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(descr, "InnoDB SYS_FOREIGN_COLS"), + + /* the plugin license (PLUGIN_LICENSE_XXX) */ + /* int */ + STRUCT_FLD(license, PLUGIN_LICENSE_GPL), + + /* the function to invoke when plugin is loaded */ + /* int (*)(void*); */ + STRUCT_FLD(init, innodb_sys_foreign_cols_init), + + /* the function to invoke when plugin is unloaded */ + /* int (*)(void*); */ + STRUCT_FLD(deinit, i_s_common_deinit), + + /* plugin version (for SHOW PLUGINS) */ + /* unsigned int */ + STRUCT_FLD(version, INNODB_VERSION_SHORT), + + /* struct st_mysql_show_var* */ + STRUCT_FLD(status_vars, NULL), + + /* struct st_mysql_sys_var** */ + STRUCT_FLD(system_vars, NULL), + + /* Maria extension */ + STRUCT_FLD(version_info, INNODB_VERSION_STR), + STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE), +}; +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ + namespace Show { /** SYS_TABLESPACES ********************************************/ /* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES */ diff --git a/storage/innobase/handler/i_s.h b/storage/innobase/handler/i_s.h index 8779760e393..4efa8116476 100644 --- a/storage/innobase/handler/i_s.h +++ b/storage/innobase/handler/i_s.h @@ -56,6 +56,10 @@ extern struct st_maria_plugin i_s_innodb_sys_tablestats; extern struct st_maria_plugin i_s_innodb_sys_indexes; extern struct st_maria_plugin i_s_innodb_sys_columns; extern struct st_maria_plugin i_s_innodb_sys_fields; +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE +extern struct st_maria_plugin i_s_innodb_sys_foreign; +extern struct st_maria_plugin i_s_innodb_sys_foreign_cols; +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ extern struct st_maria_plugin i_s_innodb_sys_tablespaces; extern struct st_maria_plugin i_s_innodb_sys_datafiles; extern struct st_maria_plugin i_s_innodb_mutexes; diff --git a/storage/innobase/include/db0err.h b/storage/innobase/include/db0err.h index 6cfc63f4a9e..0689327e1a5 100644 --- a/storage/innobase/include/db0err.h +++ b/storage/innobase/include/db0err.h @@ -163,6 +163,9 @@ enum dberr_t { DB_PAGE_CORRUPTED, /* Page read from tablespace is corrupted. */ +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE + DB_LEGACY_FK, +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ /* The following are partial failure codes */ DB_FAIL = 1000, DB_OVERFLOW, diff --git a/storage/innobase/include/dict0boot.h b/storage/innobase/include/dict0boot.h index 0f96df8fd9f..8a24bb0c6c0 100644 --- a/storage/innobase/include/dict0boot.h +++ b/storage/innobase/include/dict0boot.h @@ -225,6 +225,7 @@ enum dict_fld_sys_fields_enum { DICT_FLD__SYS_FIELDS__COL_NAME = 4, DICT_NUM_FIELDS__SYS_FIELDS = 5 }; +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE /* The columns in SYS_FOREIGN */ enum dict_col_sys_foreign_enum { DICT_COL__SYS_FOREIGN__ID = 0, @@ -267,6 +268,7 @@ enum dict_fld_sys_foreign_cols_enum { DICT_FLD__SYS_FOREIGN_COLS__REF_COL_NAME = 5, DICT_NUM_FIELDS__SYS_FOREIGN_COLS = 6 }; +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ /* The columns in SYS_TABLESPACES */ enum dict_col_sys_tablespaces_enum { DICT_COL__SYS_TABLESPACES__SPACE = 0, diff --git a/storage/innobase/include/dict0crea.h b/storage/innobase/include/dict0crea.h index e2b793a0610..ab908fdf107 100644 --- a/storage/innobase/include/dict0crea.h +++ b/storage/innobase/include/dict0crea.h @@ -113,6 +113,17 @@ dict_create_index_tree_in_mem( dict_index_t* index, /*!< in/out: index */ const trx_t* trx); /*!< in: InnoDB transaction handle */ +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE +/****************************************************************//** +Creates the foreign key constraints system tables inside InnoDB +at server bootstrap or server start if they are not found or are +not of the right form. +@return DB_SUCCESS or error code */ +dberr_t +dict_create_or_check_foreign_constraint_tables(void); +/*================================================*/ +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ + /********************************************************************//** 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, @@ -171,6 +182,7 @@ dict_replace_tablespace_in_dictionary( const char* path, trx_t* trx); +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE /********************************************************************//** Construct foreign key constraint defintion from data dictionary information. */ @@ -180,6 +192,7 @@ dict_foreign_def_get( /*=================*/ dict_foreign_t* foreign,/*!< in: foreign */ trx_t* trx); /*!< in: trx */ +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ /* Table create node structure */ struct tab_node_t{ diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index b5319d51c9a..2edadb9ede5 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -462,6 +462,7 @@ dict_foreign_replace_index( to use table->col_names */ const dict_index_t* index) /*!< in: index to be replaced */ MY_ATTRIBUTE((nonnull(1,3), warn_unused_result)); +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE /**********************************************************************//** Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement. @return DB_SUCCESS or DB_CANNOT_DROP_CONSTRAINT if syntax error or the @@ -478,6 +479,7 @@ dict_foreign_parse_drop_constraints( const char*** constraints_to_drop) /*!< out: id's of the constraints to drop */ MY_ATTRIBUTE((nonnull, warn_unused_result)); +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ /**********************************************************************//** Returns a table object and increments its open handle count. NOTE! This is a high-level function to be used mainly from outside the diff --git a/storage/innobase/include/dict0load.h b/storage/innobase/include/dict0load.h index 63661f062b7..e241b7ade71 100644 --- a/storage/innobase/include/dict0load.h +++ b/storage/innobase/include/dict0load.h @@ -201,6 +201,34 @@ dict_process_sys_fields_rec( ulint* pos, /*!< out: Field position */ index_id_t* index_id, /*!< out: current index id */ index_id_t last_id); /*!< in: previous index id */ +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE +/********************************************************************//** +This function parses a SYS_FOREIGN record and populate a dict_foreign_t +structure with the information from the record. For detail information +about SYS_FOREIGN fields, please refer to dict_load_foreign() function +@return error message, or NULL on success */ +const char* +dict_process_sys_foreign_rec( +/*=========================*/ + mem_heap_t* heap, /*!< in/out: heap memory */ + const rec_t* rec, /*!< in: current SYS_FOREIGN rec */ + dict_foreign_t* foreign); /*!< out: dict_foreign_t to be + filled */ +/********************************************************************//** +This function parses a SYS_FOREIGN_COLS record and extract necessary +information from the record and return to caller. +@return error message, or NULL on success */ +const char* +dict_process_sys_foreign_col_rec( +/*=============================*/ + mem_heap_t* heap, /*!< in/out: heap memory */ + const rec_t* rec, /*!< in: current SYS_FOREIGN_COLS rec */ + const char** name, /*!< out: foreign key constraint name */ + const char** for_col_name, /*!< out: referencing column name */ + const char** ref_col_name, /*!< out: referenced column name + in referenced table */ + ulint* pos); /*!< out: column position */ +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ /********************************************************************//** This function parses a SYS_TABLESPACES record, extracts necessary information from the record and returns to caller. diff --git a/storage/innobase/include/pars0grm.h b/storage/innobase/include/pars0grm.h index 58d424abfdc..4d232352efa 100644 --- a/storage/innobase/include/pars0grm.h +++ b/storage/innobase/include/pars0grm.h @@ -1,4 +1,4 @@ -/* A Bison parser, made by GNU Bison 3.4.2. */ +/* A Bison parser, made by GNU Bison 3.4.1. */ /* Bison interface for Yacc-like parsers in C diff --git a/storage/innobase/include/pars0pars.h b/storage/innobase/include/pars0pars.h index 03aa72d3be8..acb44598bb7 100644 --- a/storage/innobase/include/pars0pars.h +++ b/storage/innobase/include/pars0pars.h @@ -583,6 +583,9 @@ struct pars_info_t { ibool graph_owns_us; /*!< if TRUE (which is the default), que_graph_free() will free us */ +#ifdef UNIV_DEBUG + bool fatal_syntax_err; +#endif /* UNIV_DEBUG */ }; /** User-supplied function and argument. */ diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h index c4163f8d2e0..8433a82fddf 100644 --- a/storage/innobase/include/row0mysql.h +++ b/storage/innobase/include/row0mysql.h @@ -940,4 +940,16 @@ void row_wait_for_background_drop_list_empty(); #endif /* UNIV_DEBUG */ +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE +struct row_drop_table_check_legacy_data +{ + char foreign_name[MAX_FULL_NAME_LEN + 1]; + bool found; + row_drop_table_check_legacy_data() : found(false) {} +}; + +dberr_t row_drop_table_check_legacy_fk(trx_t* trx, const char * table_name, + row_drop_table_check_legacy_data &d); +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ + #endif /* row0mysql.h */ diff --git a/storage/innobase/innodb.cmake b/storage/innobase/innodb.cmake index dc6afe59088..035750d19d3 100644 --- a/storage/innobase/innodb.cmake +++ b/storage/innobase/innodb.cmake @@ -194,6 +194,11 @@ IF (WITH_INNODB_DISALLOW_WRITES) ADD_DEFINITIONS(-DWITH_INNODB_DISALLOW_WRITES) ENDIF() +OPTION(WITH_INNODB_LEGACY_FOREIGN_STORAGE "Create SYS_FOREIGN, SYS_FOREIGN_COLS tables" ON) +IF (WITH_INNODB_LEGACY_FOREIGN_STORAGE) + ADD_DEFINITIONS(-DWITH_INNODB_LEGACY_FOREIGN_STORAGE) +ENDIF() + # Include directories under innobase INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/storage/innobase/include diff --git a/storage/innobase/pars/pars0grm.cc b/storage/innobase/pars/pars0grm.cc index 7e10a783310..eb918973823 100644 --- a/storage/innobase/pars/pars0grm.cc +++ b/storage/innobase/pars/pars0grm.cc @@ -1,4 +1,4 @@ -/* A Bison parser, made by GNU Bison 3.4.2. */ +/* A Bison parser, made by GNU Bison 3.4.1. */ /* Bison implementation for Yacc-like parsers in C @@ -48,7 +48,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "3.4.2" +#define YYBISON_VERSION "3.4.1" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -454,7 +454,7 @@ union yyalloc /* YYFINAL -- State number of the termination state. */ #define YYFINAL 5 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 603 +#define YYLAST 623 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 96 @@ -463,7 +463,7 @@ union yyalloc /* YYNRULES -- Number of rules. */ #define YYNRULES 150 /* YYNSTATES -- Number of states. */ -#define YYNSTATES 300 +#define YYNSTATES 301 #define YYUNDEFTOK 2 #define YYMAXUTOK 335 @@ -526,13 +526,13 @@ static const yytype_uint16 yyrline[] = 228, 229, 234, 235, 236, 241, 242, 243, 247, 248, 256, 257, 258, 263, 265, 268, 272, 273, 277, 278, 283, 284, 289, 290, 291, 295, 296, 303, 318, 323, - 326, 334, 340, 341, 346, 352, 361, 369, 377, 384, - 392, 400, 407, 413, 414, 419, 420, 422, 426, 433, - 439, 449, 453, 457, 464, 471, 475, 483, 492, 493, - 498, 499, 504, 505, 511, 519, 520, 525, 526, 530, - 531, 535, 549, 550, 554, 559, 564, 565, 566, 570, - 576, 578, 579, 583, 591, 597, 598, 601, 603, 604, - 608 + 327, 336, 342, 343, 348, 354, 363, 371, 379, 386, + 394, 402, 409, 415, 416, 421, 422, 424, 428, 435, + 441, 451, 455, 459, 466, 473, 477, 485, 494, 495, + 500, 501, 506, 507, 513, 521, 522, 527, 528, 532, + 533, 537, 551, 552, 556, 561, 566, 567, 568, 572, + 578, 580, 581, 585, 593, 599, 600, 603, 605, 606, + 610 }; #endif @@ -608,10 +608,10 @@ static const yytype_uint16 yytoknum[] = }; # endif -#define YYPACT_NINF -129 +#define YYPACT_NINF -162 #define yypact_value_is_default(Yystate) \ - (!!((Yystate) == (-129))) + (!!((Yystate) == (-162))) #define YYTABLE_NINF -1 @@ -622,36 +622,37 @@ static const yytype_uint16 yytoknum[] = STATE-NUM. */ static const yytype_int16 yypact[] = { - 5, 34, 46, -28, -41, -129, -129, -12, 45, 57, - 23, -129, 9, -129, -129, -129, 20, -9, -129, -129, - -129, -129, 2, -129, 83, 87, 278, -129, 93, 28, - 71, 427, 427, -129, 335, 105, 85, -1, 104, -27, - 129, 132, 133, 76, 77, -129, 141, -129, 149, -129, - 61, 19, 62, 118, 65, 66, 118, 68, 69, 70, - 72, 73, 74, 75, 78, 79, 82, 84, 89, 90, - 91, 94, 138, -129, 427, -129, -129, -129, -129, 86, - 427, 96, -129, -129, -129, -129, -129, 427, 427, 438, - 92, 454, 95, -129, 1, -129, -24, 130, 157, -1, - -129, -129, 144, -1, -1, -129, 139, -129, 154, -129, - -129, -129, 98, -129, -129, -129, 108, -129, -129, 345, - -129, -129, -129, -129, -129, -129, -129, -129, -129, -129, - -129, -129, -129, -129, -129, -129, -129, -129, -129, -129, - -129, 112, 1, 135, 285, 143, -8, 15, 427, 427, - 427, 427, 427, 278, 203, 427, 427, 427, 427, 427, - 427, 427, 427, 278, 124, 204, 381, -1, 427, -129, - 209, -129, 120, -129, 173, 215, 131, 427, 180, 1, - -129, -129, -129, -129, 285, 285, 30, 30, 1, 10, - -129, 30, 30, 30, 60, 60, -8, -8, 1, -39, - 192, 137, -129, 136, -129, -13, -129, 472, 146, -129, - 147, 225, 227, 151, -129, 136, -129, -21, 0, 229, - 278, 427, -129, 213, 219, -129, 427, 220, -129, 237, - 427, -1, 214, 427, 427, 209, 23, -129, 14, 196, - 160, 158, 162, -129, -129, 278, 486, -129, 231, 1, - -129, -129, -129, 218, 194, 517, 1, -129, 175, -129, - 225, -1, -129, -129, -129, 278, -129, -129, 251, 234, - 278, 266, 260, -129, 181, 278, 201, 239, -129, 235, - 184, 271, -129, 272, 208, 275, 258, -129, -129, -129, - 17, -129, -7, -129, -129, 277, -129, -129, -129, -129 + 10, 21, 39, -47, -45, -162, -162, -44, 28, 41, + -5, -162, 6, -162, -162, -162, -38, -37, -162, -162, + -162, -162, -4, -162, 45, 47, 267, -162, 37, -28, + 8, 416, 416, -162, 324, 55, 24, 2, 35, -24, + 61, 62, 76, 17, 18, -162, 84, -162, 129, -162, + 4, -10, 5, 69, 12, 14, 69, 15, 19, 23, + 27, 34, 44, 48, 51, 53, 56, 57, 59, 65, + 70, 71, 74, -162, 416, -162, -162, -162, -162, 25, + 416, 36, -162, -162, -162, -162, -162, 416, 416, 436, + 54, 456, 68, -162, 537, -162, -29, 121, 147, 2, + -162, -162, 122, 2, 2, -162, 113, -162, 126, -162, + -162, -162, 78, -162, -162, -162, 79, -162, -162, 334, + -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, + -162, -162, -162, -162, -162, -162, -162, -162, -162, -162, + -162, 85, 537, 114, 98, 117, 9, 355, 416, 416, + 416, 416, 416, 267, 172, 416, 416, 416, 416, 416, + 416, 416, 416, 267, 104, 183, 370, 2, 416, -162, + 185, -162, 103, -162, 151, 198, 118, 416, 161, 537, + -162, -162, -162, -162, 98, 98, 13, 13, 537, 49, + -162, 13, 13, 13, -7, -7, 9, 9, 537, -64, + 181, 120, -162, 119, -162, -26, -162, 474, 134, -162, + 123, 208, 210, 128, 183, 119, -162, -58, -57, 213, + 267, 416, -162, 197, 205, -162, 416, 201, -162, 222, + 416, 2, 202, 416, 416, 185, -5, -162, -53, 179, + 142, 119, 140, 144, -162, -162, 267, 489, -162, 219, + 537, -162, -162, -162, 200, 173, 519, 537, -162, 152, + -162, 208, 2, -162, -162, -162, 267, -162, -162, 233, + 220, 267, 250, 245, -162, 167, 267, 187, 225, -162, + 224, 168, 255, -162, 256, 192, 259, 243, -162, -162, + -162, -50, -162, -17, -162, -162, 262, -162, -162, -162, + -162 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. @@ -680,37 +681,38 @@ static const yytype_uint8 yydefact[] = 143, 48, 49, 37, 45, 46, 42, 43, 44, 105, 39, 38, 40, 41, 33, 32, 34, 35, 66, 0, 0, 0, 63, 74, 72, 76, 60, 0, 0, 92, - 95, 0, 0, 63, 116, 115, 56, 0, 0, 0, + 95, 0, 0, 63, 62, 115, 56, 0, 0, 0, 0, 0, 103, 107, 0, 26, 0, 0, 69, 0, 0, 0, 78, 0, 0, 0, 0, 118, 0, 0, - 0, 0, 0, 89, 94, 106, 0, 104, 0, 67, - 109, 64, 61, 0, 80, 0, 91, 93, 120, 124, - 0, 0, 59, 58, 57, 0, 108, 79, 0, 85, - 0, 0, 122, 119, 0, 102, 0, 0, 87, 0, - 0, 0, 117, 0, 0, 0, 0, 121, 123, 125, - 0, 81, 82, 110, 131, 0, 83, 84, 86, 126 + 0, 116, 0, 0, 89, 94, 106, 0, 104, 0, + 67, 109, 64, 61, 0, 80, 0, 91, 93, 120, + 124, 0, 0, 59, 58, 57, 0, 108, 79, 0, + 85, 0, 0, 122, 119, 0, 102, 0, 0, 87, + 0, 0, 0, 117, 0, 0, 0, 0, 121, 123, + 125, 0, 81, 82, 110, 131, 0, 83, 84, 86, + 126 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { - -129, -129, -48, -128, -30, -129, -129, -129, -129, -129, - 113, 110, 123, -129, -129, -52, -129, -129, -129, -129, - -40, -129, -129, 55, -129, 238, -129, -129, -129, -129, - -129, -129, -129, 88, -129, -129, -129, -129, -129, -129, - -129, -129, -129, -129, 35, -129, -129, -129, -129, -129, - -129, -129, -129, -96, -129, -129, 81, 290, -129, -129, - -129, 286, -129, -129 + -162, -162, -48, -132, -30, -162, -162, -162, -162, -162, + -161, 94, 106, -162, -162, -52, -162, -162, -162, -162, + -35, -162, -162, 38, -162, 221, -162, -162, -162, -162, + -162, -162, -162, 60, -162, -162, -162, -162, -162, -162, + -162, -162, -162, -162, 26, -162, -162, -162, -162, -162, + -162, -162, -162, -96, -162, -162, 40, 266, -162, -162, + -162, 257, -162, -162 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { -1, 2, 47, 48, 94, 90, 217, 49, 214, 205, - 203, 199, 95, 96, 97, 120, 254, 269, 298, 278, + 203, 199, 95, 96, 97, 120, 255, 270, 299, 279, 50, 51, 52, 209, 210, 121, 53, 54, 55, 56, 57, 58, 59, 222, 223, 224, 60, 61, 62, 63, - 64, 65, 66, 67, 237, 238, 272, 282, 68, 290, + 64, 65, 66, 67, 237, 238, 273, 283, 68, 291, 106, 174, 69, 102, 70, 71, 16, 11, 12, 19, 20, 21, 22, 3 }; @@ -720,130 +722,134 @@ static const yytype_int16 yydefgoto[] = number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_uint16 yytable[] = { - 114, 89, 91, 169, 124, 152, 100, 171, 172, 148, - 149, 117, 150, 151, 152, 165, 10, 30, 230, 1, - 104, 26, 105, 148, 149, 189, 150, 151, 152, 296, - 297, 31, 141, 220, 221, 200, 32, 33, 34, 13, - 14, 4, 35, 152, 142, 24, 5, 34, 36, 7, - 144, 37, 225, 38, 226, 17, 39, 146, 147, 116, - 25, 6, 17, 9, 10, 154, 40, 41, 42, 166, - 241, 206, 242, 152, 154, 43, 44, 101, 45, 8, - 231, 155, 156, 157, 158, 159, 160, 161, 154, 179, - 28, 243, 245, 226, 29, 155, 156, 157, 158, 159, - 160, 161, 15, 154, 46, 259, 183, 260, 294, 23, - 295, 72, 98, 158, 159, 160, 161, 73, 184, 185, - 186, 187, 188, 74, 99, 191, 192, 193, 194, 195, - 196, 197, 198, 154, 103, 252, 107, 275, 207, 108, - 109, 114, 279, 110, 111, 160, 161, 198, 112, 119, - 115, 118, 114, 232, 122, 123, 30, 126, 127, 128, - 167, 129, 130, 131, 132, 274, 34, 133, 134, 113, - 31, 135, 168, 136, 143, 32, 33, 34, 137, 138, - 139, 35, 162, 140, 145, 164, 170, 36, 176, 173, - 37, 246, 38, 175, 181, 39, 249, 114, 177, 30, - 179, 180, 182, 255, 256, 40, 41, 42, 190, 201, - 211, 202, 227, 31, 43, 44, 208, 45, 32, 33, - 34, 212, 213, 216, 35, 219, 234, 114, 228, 229, - 36, 114, 236, 37, 239, 38, 244, 221, 39, 248, - 235, 240, 30, 46, 251, 250, 253, 261, 40, 41, - 42, 262, 266, 263, 264, 286, 31, 43, 44, 267, - 45, 32, 33, 34, 268, 271, 276, 35, 277, 280, - 281, 283, 284, 36, 285, 287, 37, 288, 38, 289, - 291, 39, 292, 293, 299, 30, 46, 218, 215, 204, - 257, 40, 41, 42, 125, 273, 150, 151, 152, 31, - 43, 44, 18, 45, 32, 33, 34, 0, 27, 0, - 35, 247, 0, 0, 0, 0, 36, 258, 0, 37, - 0, 38, 0, 0, 39, 0, 0, 0, 0, 46, - 0, 0, 0, 0, 40, 41, 42, 0, 75, 76, - 77, 78, 79, 43, 44, 80, 45, 0, 75, 76, - 77, 78, 79, 0, 0, 80, 0, 0, 154, 0, - 0, 0, 0, 0, 92, 155, 156, 157, 158, 159, - 160, 161, 46, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 75, 76, 77, 78, 79, 178, - 81, 80, 0, 0, 0, 82, 83, 84, 85, 86, - 81, 0, 0, 0, 0, 82, 83, 84, 85, 86, - 92, 0, 0, 0, 0, 0, 0, 0, 87, 0, - 93, 0, 0, 0, 0, 88, 0, 0, 87, 0, - 75, 76, 77, 78, 79, 88, 81, 80, 0, 0, - 0, 82, 83, 84, 85, 86, 148, 149, 0, 150, - 151, 152, 0, 0, 0, 0, 0, 0, 0, 0, - 153, 0, 148, 149, 87, 150, 151, 152, 0, 0, - 0, 88, 0, 0, 0, 0, 0, 0, 0, 163, - 148, 149, 81, 150, 151, 152, 0, 82, 83, 84, - 85, 86, 0, 0, 148, 149, 0, 150, 151, 152, - 0, 0, 0, 0, 0, 233, 0, 0, 265, 0, - 87, 154, 0, 0, 0, 0, 0, 88, 155, 156, - 157, 158, 159, 160, 161, 148, 149, 154, 150, 151, + 114, 89, 91, 169, 124, 230, 152, 171, 172, 100, + 165, 13, 14, 10, 215, 26, 117, 24, 34, 297, + 298, 189, 152, 104, 1, 105, 152, 225, 4, 226, + 116, 200, 25, 242, 244, 243, 226, 141, 260, 5, + 261, 295, 6, 296, 142, 7, 9, 8, 10, 17, + 144, 23, 28, 241, 29, 72, 30, 146, 147, 17, + 74, 73, 98, 99, 166, 103, 154, 231, 107, 108, + 31, 206, 220, 221, 15, 32, 33, 34, 160, 161, + 101, 35, 154, 109, 110, 111, 154, 36, 246, 179, + 37, 112, 38, 115, 118, 39, 158, 159, 160, 161, + 119, 122, 34, 123, 126, 40, 41, 42, 127, 150, + 151, 152, 128, 143, 43, 44, 129, 45, 184, 185, + 186, 187, 188, 130, 145, 191, 192, 193, 194, 195, + 196, 197, 198, 131, 276, 253, 30, 132, 207, 280, + 133, 114, 134, 46, 162, 135, 136, 198, 137, 113, + 31, 167, 114, 232, 138, 32, 33, 34, 164, 139, + 140, 35, 168, 173, 170, 175, 275, 36, 176, 177, + 37, 154, 38, 181, 180, 39, 182, 190, 155, 156, + 157, 158, 159, 160, 161, 40, 41, 42, 30, 201, + 202, 247, 208, 211, 43, 44, 250, 45, 114, 212, + 179, 227, 31, 256, 257, 213, 219, 32, 33, 34, + 216, 228, 229, 35, 234, 236, 235, 239, 240, 36, + 245, 221, 37, 46, 38, 249, 251, 39, 114, 252, + 262, 30, 114, 263, 254, 264, 265, 40, 41, 42, + 267, 268, 272, 269, 287, 31, 43, 44, 277, 45, + 32, 33, 34, 281, 278, 282, 35, 284, 285, 288, + 286, 289, 36, 290, 292, 37, 293, 38, 294, 300, + 39, 218, 204, 258, 30, 46, 259, 125, 18, 27, + 40, 41, 42, 248, 0, 0, 0, 274, 31, 43, + 44, 0, 45, 32, 33, 34, 0, 0, 0, 35, + 0, 0, 0, 0, 0, 36, 0, 0, 37, 0, + 38, 0, 0, 39, 0, 0, 0, 0, 46, 0, + 0, 0, 0, 40, 41, 42, 0, 75, 76, 77, + 78, 79, 43, 44, 80, 45, 0, 75, 76, 77, + 78, 79, 0, 0, 80, 0, 0, 0, 0, 0, + 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, + 0, 46, 0, 148, 149, 0, 150, 151, 152, 0, + 0, 0, 0, 75, 76, 77, 78, 79, 178, 81, + 80, 0, 0, 0, 82, 83, 84, 85, 86, 81, + 0, 0, 0, 0, 82, 83, 84, 85, 86, 92, + 0, 0, 0, 0, 0, 0, 0, 87, 0, 93, + 0, 0, 0, 0, 88, 0, 0, 87, 0, 75, + 76, 77, 78, 79, 88, 81, 80, 0, 154, 0, + 82, 83, 84, 85, 86, 155, 156, 157, 158, 159, + 160, 161, 0, 0, 148, 149, 183, 150, 151, 152, + 0, 0, 0, 87, 0, 0, 0, 0, 153, 0, + 88, 0, 0, 0, 148, 149, 0, 150, 151, 152, + 0, 81, 0, 0, 0, 0, 82, 83, 84, 85, + 86, 163, 148, 149, 0, 150, 151, 152, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 148, 149, 87, + 150, 151, 152, 0, 0, 0, 88, 233, 0, 154, + 0, 266, 0, 0, 0, 0, 155, 156, 157, 158, + 159, 160, 161, 0, 0, 0, 0, 148, 149, 154, + 150, 151, 152, 0, 0, 0, 155, 156, 157, 158, + 159, 160, 161, 0, 271, 148, 149, 154, 150, 151, 152, 0, 0, 0, 155, 156, 157, 158, 159, 160, - 161, 0, 270, 0, 0, 154, 0, 0, 0, 0, - 0, 0, 155, 156, 157, 158, 159, 160, 161, 154, - 0, 0, 0, 0, 0, 0, 155, 156, 157, 158, - 159, 160, 161, 0, 0, 0, 0, 0, 0, 0, + 161, 0, 154, 0, 0, 0, 0, 0, 0, 155, + 156, 157, 158, 159, 160, 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 154, 0, 0, 0, 0, 0, 0, 155, + 156, 157, 158, 159, 160, 161, 0, 0, 0, 0, 154, 0, 0, 0, 0, 0, 0, 155, 156, 157, 158, 159, 160, 161 }; static const yytype_int16 yycheck[] = { - 48, 31, 32, 99, 56, 13, 7, 103, 104, 8, - 9, 51, 11, 12, 13, 39, 7, 7, 31, 14, - 47, 19, 49, 8, 9, 153, 11, 12, 13, 36, - 37, 21, 72, 23, 24, 163, 26, 27, 28, 16, - 17, 7, 32, 13, 74, 54, 0, 28, 38, 90, - 80, 41, 91, 43, 93, 53, 46, 87, 88, 40, - 69, 89, 53, 18, 7, 73, 56, 57, 58, 93, - 91, 167, 93, 13, 73, 65, 66, 78, 68, 91, - 93, 80, 81, 82, 83, 84, 85, 86, 73, 119, - 7, 91, 220, 93, 7, 80, 81, 82, 83, 84, - 85, 86, 79, 73, 94, 91, 91, 93, 91, 89, - 93, 18, 7, 83, 84, 85, 86, 89, 148, 149, - 150, 151, 152, 52, 39, 155, 156, 157, 158, 159, - 160, 161, 162, 73, 30, 231, 7, 265, 168, 7, - 7, 189, 270, 67, 67, 85, 86, 177, 7, 31, - 89, 89, 200, 205, 89, 89, 7, 89, 89, 89, - 30, 89, 89, 89, 89, 261, 28, 89, 89, 20, - 21, 89, 15, 89, 88, 26, 27, 28, 89, 89, - 89, 32, 90, 89, 88, 90, 42, 38, 90, 50, - 41, 221, 43, 39, 59, 46, 226, 245, 90, 7, - 230, 89, 59, 233, 234, 56, 57, 58, 5, 85, - 90, 7, 20, 21, 65, 66, 7, 68, 26, 27, - 28, 48, 7, 92, 32, 45, 80, 275, 91, 93, - 38, 279, 7, 41, 7, 43, 7, 24, 46, 20, - 93, 90, 7, 94, 7, 25, 32, 51, 56, 57, - 58, 91, 21, 95, 92, 20, 21, 65, 66, 41, - 68, 26, 27, 28, 70, 90, 15, 32, 34, 3, - 10, 90, 71, 38, 35, 91, 41, 6, 43, 7, - 72, 46, 7, 25, 7, 7, 94, 177, 175, 166, - 235, 56, 57, 58, 56, 260, 11, 12, 13, 21, - 65, 66, 12, 68, 26, 27, 28, -1, 22, -1, - 32, 223, -1, -1, -1, -1, 38, 236, -1, 41, - -1, 43, -1, -1, 46, -1, -1, -1, -1, 94, - -1, -1, -1, -1, 56, 57, 58, -1, 3, 4, - 5, 6, 7, 65, 66, 10, 68, -1, 3, 4, - 5, 6, 7, -1, -1, 10, -1, -1, 73, -1, - -1, -1, -1, -1, 29, 80, 81, 82, 83, 84, - 85, 86, 94, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 3, 4, 5, 6, 7, 44, - 55, 10, -1, -1, -1, 60, 61, 62, 63, 64, - 55, -1, -1, -1, -1, 60, 61, 62, 63, 64, - 29, -1, -1, -1, -1, -1, -1, -1, 83, -1, - 85, -1, -1, -1, -1, 90, -1, -1, 83, -1, - 3, 4, 5, 6, 7, 90, 55, 10, -1, -1, - -1, 60, 61, 62, 63, 64, 8, 9, -1, 11, - 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, - 22, -1, 8, 9, 83, 11, 12, 13, -1, -1, - -1, 90, -1, -1, -1, -1, -1, -1, -1, 25, - 8, 9, 55, 11, 12, 13, -1, 60, 61, 62, - 63, 64, -1, -1, 8, 9, -1, 11, 12, 13, - -1, -1, -1, -1, -1, 33, -1, -1, 22, -1, - 83, 73, -1, -1, -1, -1, -1, 90, 80, 81, - 82, 83, 84, 85, 86, 8, 9, 73, 11, 12, + 48, 31, 32, 99, 56, 31, 13, 103, 104, 7, + 39, 16, 17, 7, 175, 19, 51, 54, 28, 36, + 37, 153, 13, 47, 14, 49, 13, 91, 7, 93, + 40, 163, 69, 91, 91, 93, 93, 72, 91, 0, + 93, 91, 89, 93, 74, 90, 18, 91, 7, 53, + 80, 89, 7, 214, 7, 18, 7, 87, 88, 53, + 52, 89, 7, 39, 93, 30, 73, 93, 7, 7, + 21, 167, 23, 24, 79, 26, 27, 28, 85, 86, + 78, 32, 73, 7, 67, 67, 73, 38, 220, 119, + 41, 7, 43, 89, 89, 46, 83, 84, 85, 86, + 31, 89, 28, 89, 89, 56, 57, 58, 89, 11, + 12, 13, 89, 88, 65, 66, 89, 68, 148, 149, + 150, 151, 152, 89, 88, 155, 156, 157, 158, 159, + 160, 161, 162, 89, 266, 231, 7, 89, 168, 271, + 89, 189, 89, 94, 90, 89, 89, 177, 89, 20, + 21, 30, 200, 205, 89, 26, 27, 28, 90, 89, + 89, 32, 15, 50, 42, 39, 262, 38, 90, 90, + 41, 73, 43, 59, 89, 46, 59, 5, 80, 81, + 82, 83, 84, 85, 86, 56, 57, 58, 7, 85, + 7, 221, 7, 90, 65, 66, 226, 68, 246, 48, + 230, 20, 21, 233, 234, 7, 45, 26, 27, 28, + 92, 91, 93, 32, 80, 7, 93, 7, 90, 38, + 7, 24, 41, 94, 43, 20, 25, 46, 276, 7, + 51, 7, 280, 91, 32, 95, 92, 56, 57, 58, + 21, 41, 90, 70, 20, 21, 65, 66, 15, 68, + 26, 27, 28, 3, 34, 10, 32, 90, 71, 91, + 35, 6, 38, 7, 72, 41, 7, 43, 25, 7, + 46, 177, 166, 235, 7, 94, 236, 56, 12, 22, + 56, 57, 58, 223, -1, -1, -1, 261, 21, 65, + 66, -1, 68, 26, 27, 28, -1, -1, -1, 32, + -1, -1, -1, -1, -1, 38, -1, -1, 41, -1, + 43, -1, -1, 46, -1, -1, -1, -1, 94, -1, + -1, -1, -1, 56, 57, 58, -1, 3, 4, 5, + 6, 7, 65, 66, 10, 68, -1, 3, 4, 5, + 6, 7, -1, -1, 10, -1, -1, -1, -1, -1, + -1, -1, -1, 29, -1, -1, -1, -1, -1, -1, + -1, 94, -1, 8, 9, -1, 11, 12, 13, -1, + -1, -1, -1, 3, 4, 5, 6, 7, 44, 55, + 10, -1, -1, -1, 60, 61, 62, 63, 64, 55, + -1, -1, -1, -1, 60, 61, 62, 63, 64, 29, + -1, -1, -1, -1, -1, -1, -1, 83, -1, 85, + -1, -1, -1, -1, 90, -1, -1, 83, -1, 3, + 4, 5, 6, 7, 90, 55, 10, -1, 73, -1, + 60, 61, 62, 63, 64, 80, 81, 82, 83, 84, + 85, 86, -1, -1, 8, 9, 91, 11, 12, 13, + -1, -1, -1, 83, -1, -1, -1, -1, 22, -1, + 90, -1, -1, -1, 8, 9, -1, 11, 12, 13, + -1, 55, -1, -1, -1, -1, 60, 61, 62, 63, + 64, 25, 8, 9, -1, 11, 12, 13, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 8, 9, 83, + 11, 12, 13, -1, -1, -1, 90, 33, -1, 73, + -1, 22, -1, -1, -1, -1, 80, 81, 82, 83, + 84, 85, 86, -1, -1, -1, -1, 8, 9, 73, + 11, 12, 13, -1, -1, -1, 80, 81, 82, 83, + 84, 85, 86, -1, 25, 8, 9, 73, 11, 12, 13, -1, -1, -1, 80, 81, 82, 83, 84, 85, - 86, -1, 25, -1, -1, 73, -1, -1, -1, -1, - -1, -1, 80, 81, 82, 83, 84, 85, 86, 73, - -1, -1, -1, -1, -1, -1, 80, 81, 82, 83, - 84, 85, 86, -1, -1, -1, -1, -1, -1, -1, + 86, -1, 73, -1, -1, -1, -1, -1, -1, 80, + 81, 82, 83, 84, 85, 86, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 73, -1, -1, -1, -1, -1, -1, 80, + 81, 82, 83, 84, 85, 86, -1, -1, -1, -1, 73, -1, -1, -1, -1, -1, -1, 80, 81, 82, 83, 84, 85, 86 }; @@ -876,12 +882,13 @@ static const yytype_uint8 yystos[] = 120, 90, 48, 7, 104, 106, 92, 102, 107, 45, 23, 24, 129, 130, 131, 91, 93, 20, 91, 93, 31, 93, 111, 33, 80, 93, 7, 140, 141, 7, - 90, 91, 93, 91, 7, 99, 100, 129, 20, 100, - 25, 7, 149, 32, 112, 100, 100, 119, 152, 91, - 93, 51, 91, 95, 92, 22, 21, 41, 70, 113, - 25, 90, 142, 140, 149, 99, 15, 34, 115, 99, - 3, 10, 143, 90, 71, 35, 20, 91, 6, 7, - 145, 72, 7, 25, 91, 93, 36, 37, 114, 7 + 90, 106, 91, 93, 91, 7, 99, 100, 129, 20, + 100, 25, 7, 149, 32, 112, 100, 100, 119, 152, + 91, 93, 51, 91, 95, 92, 22, 21, 41, 70, + 113, 25, 90, 142, 140, 149, 99, 15, 34, 115, + 99, 3, 10, 143, 90, 71, 35, 20, 91, 6, + 7, 145, 72, 7, 25, 91, 93, 36, 37, 114, + 7 }; /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ @@ -919,7 +926,7 @@ static const yytype_uint8 yyr2[] = 0, 4, 0, 1, 1, 0, 4, 8, 3, 5, 2, 3, 1, 3, 4, 4, 2, 2, 3, 2, 2, 3, 4, 1, 2, 0, 2, 1, 7, 6, - 10, 1, 1, 2, 2, 4, 4, 4, 1, 3, + 10, 1, 1, 2, 2, 4, 5, 4, 1, 3, 0, 3, 0, 2, 6, 1, 3, 0, 1, 0, 1, 10, 1, 1, 2, 2, 1, 1, 1, 3, 0, 1, 2, 6, 4, 1, 1, 0, 1, 2, @@ -1009,9 +1016,7 @@ yy_symbol_value_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep) if (yytype < YYNTOKENS) YYPRINT (yyo, yytoknum[yytype], *yyvaluep); # endif - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YYUSE (yytype); - YY_IGNORE_MAYBE_UNINITIALIZED_END } @@ -1612,260 +1617,260 @@ yyreduce: case 23: #line 166 "pars0grm.y" { yyval = que_node_list_add_last(NULL, yyvsp[0]); } -#line 1616 "pars0grm.cc" +#line 1621 "pars0grm.cc" break; case 24: #line 168 "pars0grm.y" { yyval = que_node_list_add_last(yyvsp[-1], yyvsp[0]); } -#line 1622 "pars0grm.cc" +#line 1627 "pars0grm.cc" break; case 25: #line 172 "pars0grm.y" { yyval = yyvsp[0];} -#line 1628 "pars0grm.cc" +#line 1633 "pars0grm.cc" break; case 26: #line 174 "pars0grm.y" { yyval = pars_func(yyvsp[-3], yyvsp[-1]); } -#line 1634 "pars0grm.cc" +#line 1639 "pars0grm.cc" break; case 27: #line 175 "pars0grm.y" { yyval = yyvsp[0];} -#line 1640 "pars0grm.cc" +#line 1645 "pars0grm.cc" break; case 28: #line 176 "pars0grm.y" { yyval = yyvsp[0];} -#line 1646 "pars0grm.cc" +#line 1651 "pars0grm.cc" break; case 29: #line 177 "pars0grm.y" { yyval = yyvsp[0];} -#line 1652 "pars0grm.cc" +#line 1657 "pars0grm.cc" break; case 30: #line 178 "pars0grm.y" { yyval = yyvsp[0];} -#line 1658 "pars0grm.cc" +#line 1663 "pars0grm.cc" break; case 31: #line 179 "pars0grm.y" { yyval = yyvsp[0];} -#line 1664 "pars0grm.cc" +#line 1669 "pars0grm.cc" break; case 32: #line 180 "pars0grm.y" { yyval = pars_op('+', yyvsp[-2], yyvsp[0]); } -#line 1670 "pars0grm.cc" +#line 1675 "pars0grm.cc" break; case 33: #line 181 "pars0grm.y" { yyval = pars_op('-', yyvsp[-2], yyvsp[0]); } -#line 1676 "pars0grm.cc" +#line 1681 "pars0grm.cc" break; case 34: #line 182 "pars0grm.y" { yyval = pars_op('*', yyvsp[-2], yyvsp[0]); } -#line 1682 "pars0grm.cc" +#line 1687 "pars0grm.cc" break; case 35: #line 183 "pars0grm.y" { yyval = pars_op('/', yyvsp[-2], yyvsp[0]); } -#line 1688 "pars0grm.cc" +#line 1693 "pars0grm.cc" break; case 36: #line 184 "pars0grm.y" { yyval = pars_op('-', yyvsp[0], NULL); } -#line 1694 "pars0grm.cc" +#line 1699 "pars0grm.cc" break; case 37: #line 185 "pars0grm.y" { yyval = yyvsp[-1]; } -#line 1700 "pars0grm.cc" +#line 1705 "pars0grm.cc" break; case 38: #line 186 "pars0grm.y" { yyval = pars_op('=', yyvsp[-2], yyvsp[0]); } -#line 1706 "pars0grm.cc" +#line 1711 "pars0grm.cc" break; case 39: #line 188 "pars0grm.y" { yyval = pars_op(PARS_LIKE_TOKEN, yyvsp[-2], yyvsp[0]); } -#line 1712 "pars0grm.cc" +#line 1717 "pars0grm.cc" break; case 40: #line 189 "pars0grm.y" { yyval = pars_op('<', yyvsp[-2], yyvsp[0]); } -#line 1718 "pars0grm.cc" +#line 1723 "pars0grm.cc" break; case 41: #line 190 "pars0grm.y" { yyval = pars_op('>', yyvsp[-2], yyvsp[0]); } -#line 1724 "pars0grm.cc" +#line 1729 "pars0grm.cc" break; case 42: #line 191 "pars0grm.y" { yyval = pars_op(PARS_GE_TOKEN, yyvsp[-2], yyvsp[0]); } -#line 1730 "pars0grm.cc" +#line 1735 "pars0grm.cc" break; case 43: #line 192 "pars0grm.y" { yyval = pars_op(PARS_LE_TOKEN, yyvsp[-2], yyvsp[0]); } -#line 1736 "pars0grm.cc" +#line 1741 "pars0grm.cc" break; case 44: #line 193 "pars0grm.y" { yyval = pars_op(PARS_NE_TOKEN, yyvsp[-2], yyvsp[0]); } -#line 1742 "pars0grm.cc" +#line 1747 "pars0grm.cc" break; case 45: #line 194 "pars0grm.y" { yyval = pars_op(PARS_AND_TOKEN, yyvsp[-2], yyvsp[0]); } -#line 1748 "pars0grm.cc" +#line 1753 "pars0grm.cc" break; case 46: #line 195 "pars0grm.y" { yyval = pars_op(PARS_OR_TOKEN, yyvsp[-2], yyvsp[0]); } -#line 1754 "pars0grm.cc" +#line 1759 "pars0grm.cc" break; case 47: #line 196 "pars0grm.y" { yyval = pars_op(PARS_NOT_TOKEN, yyvsp[0], NULL); } -#line 1760 "pars0grm.cc" +#line 1765 "pars0grm.cc" break; case 48: #line 198 "pars0grm.y" { yyval = pars_op(PARS_NOTFOUND_TOKEN, yyvsp[-2], NULL); } -#line 1766 "pars0grm.cc" +#line 1771 "pars0grm.cc" break; case 49: #line 200 "pars0grm.y" { yyval = pars_op(PARS_NOTFOUND_TOKEN, yyvsp[-2], NULL); } -#line 1772 "pars0grm.cc" +#line 1777 "pars0grm.cc" break; case 50: #line 204 "pars0grm.y" { yyval = &pars_to_binary_token; } -#line 1778 "pars0grm.cc" +#line 1783 "pars0grm.cc" break; case 51: #line 205 "pars0grm.y" { yyval = &pars_substr_token; } -#line 1784 "pars0grm.cc" +#line 1789 "pars0grm.cc" break; case 52: #line 206 "pars0grm.y" { yyval = &pars_concat_token; } -#line 1790 "pars0grm.cc" +#line 1795 "pars0grm.cc" break; case 53: #line 207 "pars0grm.y" { yyval = &pars_instr_token; } -#line 1796 "pars0grm.cc" +#line 1801 "pars0grm.cc" break; case 54: #line 208 "pars0grm.y" { yyval = &pars_length_token; } -#line 1802 "pars0grm.cc" +#line 1807 "pars0grm.cc" break; case 58: #line 219 "pars0grm.y" { yyval = pars_stored_procedure_call( static_cast<sym_node_t*>(yyvsp[-4])); } -#line 1809 "pars0grm.cc" +#line 1814 "pars0grm.cc" break; case 59: #line 224 "pars0grm.y" { yyval = yyvsp[-2]; } -#line 1815 "pars0grm.cc" +#line 1820 "pars0grm.cc" break; case 60: #line 228 "pars0grm.y" { yyval = que_node_list_add_last(NULL, yyvsp[0]); } -#line 1821 "pars0grm.cc" +#line 1826 "pars0grm.cc" break; case 61: #line 230 "pars0grm.y" { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); } -#line 1827 "pars0grm.cc" +#line 1832 "pars0grm.cc" break; case 62: #line 234 "pars0grm.y" { yyval = NULL; } -#line 1833 "pars0grm.cc" +#line 1838 "pars0grm.cc" break; case 63: #line 235 "pars0grm.y" { yyval = que_node_list_add_last(NULL, yyvsp[0]); } -#line 1839 "pars0grm.cc" +#line 1844 "pars0grm.cc" break; case 64: #line 237 "pars0grm.y" { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); } -#line 1845 "pars0grm.cc" +#line 1850 "pars0grm.cc" break; case 65: #line 241 "pars0grm.y" { yyval = NULL; } -#line 1851 "pars0grm.cc" +#line 1856 "pars0grm.cc" break; case 66: #line 242 "pars0grm.y" { yyval = que_node_list_add_last(NULL, yyvsp[0]);} -#line 1857 "pars0grm.cc" +#line 1862 "pars0grm.cc" break; case 67: #line 243 "pars0grm.y" { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); } -#line 1863 "pars0grm.cc" +#line 1868 "pars0grm.cc" break; case 68: #line 247 "pars0grm.y" { yyval = yyvsp[0]; } -#line 1869 "pars0grm.cc" +#line 1874 "pars0grm.cc" break; case 69: @@ -1874,105 +1879,105 @@ yyreduce: que_node_list_add_last(NULL, sym_tab_add_int_lit( pars_sym_tab_global, 1))); } -#line 1878 "pars0grm.cc" +#line 1883 "pars0grm.cc" break; case 70: #line 256 "pars0grm.y" { yyval = NULL; } -#line 1884 "pars0grm.cc" +#line 1889 "pars0grm.cc" break; case 71: #line 257 "pars0grm.y" { yyval = que_node_list_add_last(NULL, yyvsp[0]); } -#line 1890 "pars0grm.cc" +#line 1895 "pars0grm.cc" break; case 72: #line 259 "pars0grm.y" { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); } -#line 1896 "pars0grm.cc" +#line 1901 "pars0grm.cc" break; case 73: #line 263 "pars0grm.y" { yyval = pars_select_list(&pars_star_denoter, NULL); } -#line 1903 "pars0grm.cc" +#line 1908 "pars0grm.cc" break; case 74: #line 266 "pars0grm.y" { yyval = pars_select_list( yyvsp[-2], static_cast<sym_node_t*>(yyvsp[0])); } -#line 1910 "pars0grm.cc" +#line 1915 "pars0grm.cc" break; case 75: #line 268 "pars0grm.y" { yyval = pars_select_list(yyvsp[0], NULL); } -#line 1916 "pars0grm.cc" +#line 1921 "pars0grm.cc" break; case 76: #line 272 "pars0grm.y" { yyval = NULL; } -#line 1922 "pars0grm.cc" +#line 1927 "pars0grm.cc" break; case 77: #line 273 "pars0grm.y" { yyval = yyvsp[0]; } -#line 1928 "pars0grm.cc" +#line 1933 "pars0grm.cc" break; case 78: #line 277 "pars0grm.y" { yyval = NULL; } -#line 1934 "pars0grm.cc" +#line 1939 "pars0grm.cc" break; case 79: #line 279 "pars0grm.y" { yyval = &pars_update_token; } -#line 1940 "pars0grm.cc" +#line 1945 "pars0grm.cc" break; case 80: #line 283 "pars0grm.y" { yyval = NULL; } -#line 1946 "pars0grm.cc" +#line 1951 "pars0grm.cc" break; case 81: #line 285 "pars0grm.y" { yyval = &pars_share_token; } -#line 1952 "pars0grm.cc" +#line 1957 "pars0grm.cc" break; case 82: #line 289 "pars0grm.y" { yyval = &pars_asc_token; } -#line 1958 "pars0grm.cc" +#line 1963 "pars0grm.cc" break; case 83: #line 290 "pars0grm.y" { yyval = &pars_asc_token; } -#line 1964 "pars0grm.cc" +#line 1969 "pars0grm.cc" break; case 84: #line 291 "pars0grm.y" { yyval = &pars_desc_token; } -#line 1970 "pars0grm.cc" +#line 1975 "pars0grm.cc" break; case 85: #line 295 "pars0grm.y" { yyval = NULL; } -#line 1976 "pars0grm.cc" +#line 1981 "pars0grm.cc" break; case 86: @@ -1980,7 +1985,7 @@ yyreduce: { yyval = pars_order_by( static_cast<sym_node_t*>(yyvsp[-1]), static_cast<pars_res_word_t*>(yyvsp[0])); } -#line 1984 "pars0grm.cc" +#line 1989 "pars0grm.cc" break; case 87: @@ -1992,395 +1997,397 @@ yyreduce: static_cast<pars_res_word_t*>(yyvsp[-2]), static_cast<pars_res_word_t*>(yyvsp[-1]), static_cast<order_node_t*>(yyvsp[0])); } -#line 1996 "pars0grm.cc" +#line 2001 "pars0grm.cc" break; case 88: #line 319 "pars0grm.y" { yyval = yyvsp[0]; } -#line 2002 "pars0grm.cc" +#line 2007 "pars0grm.cc" break; case 89: #line 324 "pars0grm.y" - { yyval = pars_insert_statement( - static_cast<sym_node_t*>(yyvsp[-4]), yyvsp[-1], NULL); } -#line 2009 "pars0grm.cc" + { if (!(yyval = pars_insert_statement( + static_cast<sym_node_t*>(yyvsp[-4]), yyvsp[-1], NULL))) + YYABORT; } +#line 2015 "pars0grm.cc" break; case 90: -#line 327 "pars0grm.y" - { yyval = pars_insert_statement( +#line 328 "pars0grm.y" + { if (!(yyval = pars_insert_statement( static_cast<sym_node_t*>(yyvsp[-1]), NULL, - static_cast<sel_node_t*>(yyvsp[0])); } -#line 2018 "pars0grm.cc" + static_cast<sel_node_t*>(yyvsp[0])))) + YYABORT; } +#line 2025 "pars0grm.cc" break; case 91: -#line 334 "pars0grm.y" +#line 336 "pars0grm.y" { yyval = pars_column_assignment( static_cast<sym_node_t*>(yyvsp[-2]), static_cast<que_node_t*>(yyvsp[0])); } -#line 2026 "pars0grm.cc" +#line 2033 "pars0grm.cc" break; case 92: -#line 340 "pars0grm.y" +#line 342 "pars0grm.y" { yyval = que_node_list_add_last(NULL, yyvsp[0]); } -#line 2032 "pars0grm.cc" +#line 2039 "pars0grm.cc" break; case 93: -#line 342 "pars0grm.y" +#line 344 "pars0grm.y" { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); } -#line 2038 "pars0grm.cc" +#line 2045 "pars0grm.cc" break; case 94: -#line 348 "pars0grm.y" +#line 350 "pars0grm.y" { yyval = yyvsp[0]; } -#line 2044 "pars0grm.cc" +#line 2051 "pars0grm.cc" break; case 95: -#line 354 "pars0grm.y" +#line 356 "pars0grm.y" { yyval = pars_update_statement_start( FALSE, static_cast<sym_node_t*>(yyvsp[-2]), static_cast<col_assign_node_t*>(yyvsp[0])); } -#line 2053 "pars0grm.cc" +#line 2060 "pars0grm.cc" break; case 96: -#line 362 "pars0grm.y" +#line 364 "pars0grm.y" { yyval = pars_update_statement( static_cast<upd_node_t*>(yyvsp[-1]), NULL, static_cast<que_node_t*>(yyvsp[0])); } -#line 2062 "pars0grm.cc" +#line 2069 "pars0grm.cc" break; case 97: -#line 370 "pars0grm.y" +#line 372 "pars0grm.y" { yyval = pars_update_statement( static_cast<upd_node_t*>(yyvsp[-1]), static_cast<sym_node_t*>(yyvsp[0]), NULL); } -#line 2071 "pars0grm.cc" +#line 2078 "pars0grm.cc" break; case 98: -#line 378 "pars0grm.y" +#line 380 "pars0grm.y" { yyval = pars_update_statement_start( TRUE, static_cast<sym_node_t*>(yyvsp[0]), NULL); } -#line 2079 "pars0grm.cc" +#line 2086 "pars0grm.cc" break; case 99: -#line 385 "pars0grm.y" +#line 387 "pars0grm.y" { yyval = pars_update_statement( static_cast<upd_node_t*>(yyvsp[-1]), NULL, static_cast<que_node_t*>(yyvsp[0])); } -#line 2088 "pars0grm.cc" +#line 2095 "pars0grm.cc" break; case 100: -#line 393 "pars0grm.y" +#line 395 "pars0grm.y" { yyval = pars_update_statement( static_cast<upd_node_t*>(yyvsp[-1]), static_cast<sym_node_t*>(yyvsp[0]), NULL); } -#line 2097 "pars0grm.cc" +#line 2104 "pars0grm.cc" break; case 101: -#line 401 "pars0grm.y" +#line 403 "pars0grm.y" { yyval = pars_assignment_statement( static_cast<sym_node_t*>(yyvsp[-2]), static_cast<que_node_t*>(yyvsp[0])); } -#line 2105 "pars0grm.cc" +#line 2112 "pars0grm.cc" break; case 102: -#line 409 "pars0grm.y" +#line 411 "pars0grm.y" { yyval = pars_elsif_element(yyvsp[-2], yyvsp[0]); } -#line 2111 "pars0grm.cc" +#line 2118 "pars0grm.cc" break; case 103: -#line 413 "pars0grm.y" +#line 415 "pars0grm.y" { yyval = que_node_list_add_last(NULL, yyvsp[0]); } -#line 2117 "pars0grm.cc" +#line 2124 "pars0grm.cc" break; case 104: -#line 415 "pars0grm.y" +#line 417 "pars0grm.y" { yyval = que_node_list_add_last(yyvsp[-1], yyvsp[0]); } -#line 2123 "pars0grm.cc" +#line 2130 "pars0grm.cc" break; case 105: -#line 419 "pars0grm.y" +#line 421 "pars0grm.y" { yyval = NULL; } -#line 2129 "pars0grm.cc" +#line 2136 "pars0grm.cc" break; case 106: -#line 421 "pars0grm.y" +#line 423 "pars0grm.y" { yyval = yyvsp[0]; } -#line 2135 "pars0grm.cc" +#line 2142 "pars0grm.cc" break; case 107: -#line 422 "pars0grm.y" +#line 424 "pars0grm.y" { yyval = yyvsp[0]; } -#line 2141 "pars0grm.cc" +#line 2148 "pars0grm.cc" break; case 108: -#line 429 "pars0grm.y" +#line 431 "pars0grm.y" { yyval = pars_if_statement(yyvsp[-5], yyvsp[-3], yyvsp[-2]); } -#line 2147 "pars0grm.cc" +#line 2154 "pars0grm.cc" break; case 109: -#line 435 "pars0grm.y" +#line 437 "pars0grm.y" { yyval = pars_while_statement(yyvsp[-4], yyvsp[-2]); } -#line 2153 "pars0grm.cc" +#line 2160 "pars0grm.cc" break; case 110: -#line 443 "pars0grm.y" +#line 445 "pars0grm.y" { yyval = pars_for_statement( static_cast<sym_node_t*>(yyvsp[-8]), yyvsp[-6], yyvsp[-4], yyvsp[-2]); } -#line 2161 "pars0grm.cc" +#line 2168 "pars0grm.cc" break; case 111: -#line 449 "pars0grm.y" +#line 451 "pars0grm.y" { yyval = pars_exit_statement(); } -#line 2167 "pars0grm.cc" +#line 2174 "pars0grm.cc" break; case 112: -#line 453 "pars0grm.y" +#line 455 "pars0grm.y" { yyval = pars_return_statement(); } -#line 2173 "pars0grm.cc" +#line 2180 "pars0grm.cc" break; case 113: -#line 458 "pars0grm.y" +#line 460 "pars0grm.y" { yyval = pars_open_statement( ROW_SEL_OPEN_CURSOR, static_cast<sym_node_t*>(yyvsp[0])); } -#line 2181 "pars0grm.cc" +#line 2188 "pars0grm.cc" break; case 114: -#line 465 "pars0grm.y" +#line 467 "pars0grm.y" { yyval = pars_open_statement( ROW_SEL_CLOSE_CURSOR, static_cast<sym_node_t*>(yyvsp[0])); } -#line 2189 "pars0grm.cc" +#line 2196 "pars0grm.cc" break; case 115: -#line 472 "pars0grm.y" +#line 474 "pars0grm.y" { yyval = pars_fetch_statement( static_cast<sym_node_t*>(yyvsp[-2]), static_cast<sym_node_t*>(yyvsp[0]), NULL); } -#line 2197 "pars0grm.cc" +#line 2204 "pars0grm.cc" break; case 116: -#line 476 "pars0grm.y" +#line 478 "pars0grm.y" { yyval = pars_fetch_statement( - static_cast<sym_node_t*>(yyvsp[-2]), - NULL, - static_cast<sym_node_t*>(yyvsp[0])); } -#line 2206 "pars0grm.cc" + static_cast<sym_node_t*>(yyvsp[-3]), + static_cast<sym_node_t*>(yyvsp[0]), + static_cast<sym_node_t*>(yyvsp[-1])); } +#line 2213 "pars0grm.cc" break; case 117: -#line 484 "pars0grm.y" +#line 486 "pars0grm.y" { yyval = pars_column_def( static_cast<sym_node_t*>(yyvsp[-3]), static_cast<pars_res_word_t*>(yyvsp[-2]), static_cast<sym_node_t*>(yyvsp[-1]), yyvsp[0]); } -#line 2216 "pars0grm.cc" +#line 2223 "pars0grm.cc" break; case 118: -#line 492 "pars0grm.y" +#line 494 "pars0grm.y" { yyval = que_node_list_add_last(NULL, yyvsp[0]); } -#line 2222 "pars0grm.cc" +#line 2229 "pars0grm.cc" break; case 119: -#line 494 "pars0grm.y" +#line 496 "pars0grm.y" { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); } -#line 2228 "pars0grm.cc" +#line 2235 "pars0grm.cc" break; case 120: -#line 498 "pars0grm.y" +#line 500 "pars0grm.y" { yyval = NULL; } -#line 2234 "pars0grm.cc" +#line 2241 "pars0grm.cc" break; case 121: -#line 500 "pars0grm.y" +#line 502 "pars0grm.y" { yyval = yyvsp[-1]; } -#line 2240 "pars0grm.cc" +#line 2247 "pars0grm.cc" break; case 122: -#line 504 "pars0grm.y" +#line 506 "pars0grm.y" { yyval = NULL; } -#line 2246 "pars0grm.cc" +#line 2253 "pars0grm.cc" break; case 123: -#line 506 "pars0grm.y" +#line 508 "pars0grm.y" { yyval = &pars_int_token; /* pass any non-NULL pointer */ } -#line 2253 "pars0grm.cc" +#line 2260 "pars0grm.cc" break; case 124: -#line 513 "pars0grm.y" +#line 515 "pars0grm.y" { yyval = pars_create_table( static_cast<sym_node_t*>(yyvsp[-3]), static_cast<sym_node_t*>(yyvsp[-1])); } -#line 2261 "pars0grm.cc" +#line 2268 "pars0grm.cc" break; case 125: -#line 519 "pars0grm.y" +#line 521 "pars0grm.y" { yyval = que_node_list_add_last(NULL, yyvsp[0]); } -#line 2267 "pars0grm.cc" +#line 2274 "pars0grm.cc" break; case 126: -#line 521 "pars0grm.y" +#line 523 "pars0grm.y" { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); } -#line 2273 "pars0grm.cc" +#line 2280 "pars0grm.cc" break; case 127: -#line 525 "pars0grm.y" +#line 527 "pars0grm.y" { yyval = NULL; } -#line 2279 "pars0grm.cc" +#line 2286 "pars0grm.cc" break; case 128: -#line 526 "pars0grm.y" +#line 528 "pars0grm.y" { yyval = &pars_unique_token; } -#line 2285 "pars0grm.cc" +#line 2292 "pars0grm.cc" break; case 129: -#line 530 "pars0grm.y" +#line 532 "pars0grm.y" { yyval = NULL; } -#line 2291 "pars0grm.cc" +#line 2298 "pars0grm.cc" break; case 130: -#line 531 "pars0grm.y" +#line 533 "pars0grm.y" { yyval = &pars_clustered_token; } -#line 2297 "pars0grm.cc" +#line 2304 "pars0grm.cc" break; case 131: -#line 540 "pars0grm.y" +#line 542 "pars0grm.y" { yyval = pars_create_index( static_cast<pars_res_word_t*>(yyvsp[-8]), static_cast<pars_res_word_t*>(yyvsp[-7]), static_cast<sym_node_t*>(yyvsp[-5]), static_cast<sym_node_t*>(yyvsp[-3]), static_cast<sym_node_t*>(yyvsp[-1])); } -#line 2308 "pars0grm.cc" +#line 2315 "pars0grm.cc" break; case 132: -#line 549 "pars0grm.y" +#line 551 "pars0grm.y" { yyval = yyvsp[0]; } -#line 2314 "pars0grm.cc" +#line 2321 "pars0grm.cc" break; case 133: -#line 550 "pars0grm.y" +#line 552 "pars0grm.y" { yyval = yyvsp[0]; } -#line 2320 "pars0grm.cc" +#line 2327 "pars0grm.cc" break; case 134: -#line 555 "pars0grm.y" +#line 557 "pars0grm.y" { yyval = pars_commit_statement(); } -#line 2326 "pars0grm.cc" +#line 2333 "pars0grm.cc" break; case 135: -#line 560 "pars0grm.y" +#line 562 "pars0grm.y" { yyval = pars_rollback_statement(); } -#line 2332 "pars0grm.cc" +#line 2339 "pars0grm.cc" break; case 136: -#line 564 "pars0grm.y" +#line 566 "pars0grm.y" { yyval = &pars_int_token; } -#line 2338 "pars0grm.cc" +#line 2345 "pars0grm.cc" break; case 137: -#line 565 "pars0grm.y" +#line 567 "pars0grm.y" { yyval = &pars_bigint_token; } -#line 2344 "pars0grm.cc" +#line 2351 "pars0grm.cc" break; case 138: -#line 566 "pars0grm.y" +#line 568 "pars0grm.y" { yyval = &pars_char_token; } -#line 2350 "pars0grm.cc" +#line 2357 "pars0grm.cc" break; case 139: -#line 571 "pars0grm.y" +#line 573 "pars0grm.y" { yyval = pars_variable_declaration( static_cast<sym_node_t*>(yyvsp[-2]), static_cast<pars_res_word_t*>(yyvsp[-1])); } -#line 2358 "pars0grm.cc" +#line 2365 "pars0grm.cc" break; case 143: -#line 585 "pars0grm.y" +#line 587 "pars0grm.y" { yyval = pars_cursor_declaration( static_cast<sym_node_t*>(yyvsp[-3]), static_cast<sel_node_t*>(yyvsp[-1])); } -#line 2366 "pars0grm.cc" +#line 2373 "pars0grm.cc" break; case 144: -#line 592 "pars0grm.y" +#line 594 "pars0grm.y" { yyval = pars_function_declaration( static_cast<sym_node_t*>(yyvsp[-1])); } -#line 2373 "pars0grm.cc" +#line 2380 "pars0grm.cc" break; case 150: -#line 614 "pars0grm.y" +#line 616 "pars0grm.y" { yyval = pars_procedure_definition( static_cast<sym_node_t*>(yyvsp[-8]), yyvsp[-1]); } -#line 2380 "pars0grm.cc" +#line 2387 "pars0grm.cc" break; -#line 2384 "pars0grm.cc" +#line 2391 "pars0grm.cc" default: break; } @@ -2612,5 +2619,5 @@ yyreturn: #endif return yyresult; } -#line 618 "pars0grm.y" +#line 620 "pars0grm.y" diff --git a/storage/innobase/pars/pars0grm.y b/storage/innobase/pars/pars0grm.y index 625ed41bbd4..1d79ba34b52 100644 --- a/storage/innobase/pars/pars0grm.y +++ b/storage/innobase/pars/pars0grm.y @@ -321,13 +321,15 @@ insert_statement_start: insert_statement: insert_statement_start PARS_VALUES_TOKEN '(' exp_list ')' - { $$ = pars_insert_statement( - static_cast<sym_node_t*>($1), $4, NULL); } + { if (!($$ = pars_insert_statement( + static_cast<sym_node_t*>($1), $4, NULL))) + YYABORT; } | insert_statement_start select_statement - { $$ = pars_insert_statement( + { if (!($$ = pars_insert_statement( static_cast<sym_node_t*>($1), NULL, - static_cast<sel_node_t*>($2)); } + static_cast<sel_node_t*>($2)))) + YYABORT; } ; column_assignment: @@ -472,10 +474,10 @@ fetch_statement: { $$ = pars_fetch_statement( static_cast<sym_node_t*>($2), static_cast<sym_node_t*>($4), NULL); } - | PARS_FETCH_TOKEN PARS_ID_TOKEN PARS_INTO_TOKEN user_function_call + | PARS_FETCH_TOKEN PARS_ID_TOKEN PARS_INTO_TOKEN user_function_call variable_list { $$ = pars_fetch_statement( static_cast<sym_node_t*>($2), - NULL, + static_cast<sym_node_t*>($5), static_cast<sym_node_t*>($4)); } ; diff --git a/storage/innobase/pars/pars0pars.cc b/storage/innobase/pars/pars0pars.cc index 2f3791aeb5e..5e11e2c89e4 100644 --- a/storage/innobase/pars/pars0pars.cc +++ b/storage/innobase/pars/pars0pars.cc @@ -1296,6 +1296,14 @@ pars_insert_statement( if (node->values_list) { pars_resolve_exp_list_variables_and_types(NULL, values_list); +#ifdef UNIV_DEBUG + if (!pars_sym_tab_global->info->fatal_syntax_err + && que_node_list_get_len(values_list) + != dict_table_get_n_user_cols(table_sym->table)) { + + return NULL; + } +#endif /* UNIV_DEBUG */ ut_a(que_node_list_get_len(values_list) == dict_table_get_n_user_cols(table_sym->table)); } @@ -1618,30 +1626,30 @@ pars_fetch_statement( sym_node_t* cursor_decl; fetch_node_t* node; - /* Logical XOR. */ - ut_a(!into_list != !user_func); + ut_ad(into_list || user_func); node = static_cast<fetch_node_t*>( mem_heap_alloc( pars_sym_tab_global->heap, sizeof(fetch_node_t))); node->common.type = QUE_NODE_FETCH; + node->into_list = NULL; + node->func = NULL; pars_resolve_exp_variables_and_types(NULL, cursor); if (into_list) { pars_resolve_exp_list_variables_and_types(NULL, into_list); node->into_list = into_list; - node->func = NULL; - } else { + } + + if (user_func) { pars_resolve_exp_variables_and_types(NULL, user_func); node->func = pars_info_lookup_user_func( pars_sym_tab_global->info, user_func->name); ut_a(node->func); - - node->into_list = NULL; } cursor_decl = cursor->alias; @@ -1965,8 +1973,6 @@ yyerror( /*!< in: error message string */ { ut_ad(s); - - ib::fatal() << "PARSER: Syntax error in SQL string"; } /*************************************************************//** @@ -1997,7 +2003,17 @@ pars_sql( pars_sym_tab_global->next_char_pos = 0; pars_sym_tab_global->info = info; - yyparse(); + if (yyparse()) { +#ifdef UNIV_DEBUG + if (info->fatal_syntax_err) { +#endif /* UNIV_DEBUG */ + ib::fatal() << "PARSER: Syntax error in SQL string"; +#ifdef UNIV_DEBUG + } + mem_heap_free(heap); + return NULL; +#endif /* UNIV_DEBUG */ + } sym_node = UT_LIST_GET_FIRST(pars_sym_tab_global->sym_list); @@ -2066,13 +2082,24 @@ pars_info_create(void) heap = mem_heap_create(512); + if (!heap) { + return NULL; + } + info = static_cast<pars_info_t*>(mem_heap_alloc(heap, sizeof(*info))); + if (!info) { + return NULL; + } + info->heap = heap; info->funcs = NULL; info->bound_lits = NULL; info->bound_ids = NULL; info->graph_owns_us = TRUE; +#ifdef UNIV_DEBUG + info->fatal_syntax_err = true; +#endif /* UNIV_DEBUG */ return(info); } diff --git a/storage/innobase/pars/pars0sym.cc b/storage/innobase/pars/pars0sym.cc index 5e4c0e0f6e0..dc1f49ddb3b 100644 --- a/storage/innobase/pars/pars0sym.cc +++ b/storage/innobase/pars/pars0sym.cc @@ -207,6 +207,11 @@ sym_tab_add_bound_lit( ulint len = 0; blit = pars_info_get_bound_lit(sym_tab->info, name); +#ifdef UNIV_DEBUG + if (!sym_tab->info->fatal_syntax_err && !blit) { + return NULL; + } +#endif /* UNIV_DEBUG */ ut_a(blit); node = static_cast<sym_node_t*>( diff --git a/storage/innobase/que/que0que.cc b/storage/innobase/que/que0que.cc index 18fe7626d57..1e7ff847266 100644 --- a/storage/innobase/que/que0que.cc +++ b/storage/innobase/que/que0que.cc @@ -1116,6 +1116,14 @@ que_eval_sql( mutex_exit(&dict_sys.mutex); } +#ifdef UNIV_DEBUG + if (!graph) { + trx->error_state = DB_ERROR; + DBUG_RETURN(trx->error_state); + } +#endif /* UNIV_DEBUG */ + ut_ad(graph); + graph->trx = trx; trx->graph = NULL; diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 7251be09c5b..a1365a90dc4 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -3270,6 +3270,58 @@ row_drop_table_from_cache( return(err); } +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE +static +ibool +row_drop_table_check_legacy_step( +/*=================*/ + void* row, /*!< in: sel_node_t* */ + void* user_arg) /*!< in/out: row_drop_table_check_legacy_data */ +{ + row_drop_table_check_legacy_data &d = *(row_drop_table_check_legacy_data *) user_arg; + sel_node_t* node = static_cast<sel_node_t*>(row); + que_node_t* exp = node->select_list; + dfield_t* fld = que_node_get_val(exp); + ut_a(fld->len < sizeof(d.foreign_name)); + memcpy(d.foreign_name, fld->data, fld->len); + d.foreign_name[fld->len] = 0; + d.found = true; + ut_a(!que_node_get_next(exp)); + return 0; +} + +dberr_t row_drop_table_check_legacy_fk(trx_t* trx, const char * table_name, row_drop_table_check_legacy_data &d) +{ + static const char sql_check[] = + "PROCEDURE FK_PROC () IS\n" + "DECLARE FUNCTION row_drop_table_check_legacy_step;\n" + + "DECLARE CURSOR c IS" + " SELECT FOR_NAME FROM SYS_FOREIGN" + " WHERE REF_NAME = :ref_name;\n" + + "BEGIN\n" + "OPEN c;\n" + "FETCH c INTO row_drop_table_check_legacy_step();\n" + "CLOSE c;\n" + "END;\n"; + + pars_info_t* info = pars_info_create(); + if (!info) { + return DB_OUT_OF_MEMORY; + } + pars_info_bind_function(info, "row_drop_table_check_legacy_step", row_drop_table_check_legacy_step, &d); + pars_info_add_str_literal(info, "ref_name", table_name); + + dberr_t err = que_eval_sql(info, sql_check, false, trx); + if (err != DB_SUCCESS) { + return err; + } + + return DB_SUCCESS; +} +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ + /** Drop a table for MySQL. If the data dictionary was not already locked by the transaction, the transaction will be committed. Otherwise, the data dictionary @@ -3453,15 +3505,41 @@ row_drop_table_for_mysql( ut_print_name(ef, trx, name); fputs("\n" "because it is referenced by ", ef); - ut_print_name(ef, trx, - foreign->foreign_table_name); + ut_print_name(ef, trx, foreign->foreign_table_name); putc('\n', ef); mutex_exit(&dict_foreign_err_mutex); goto funct_exit; } } - } +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE + row_drop_table_check_legacy_data data; + + err = row_drop_table_check_legacy_fk(trx, table->name.m_name, data); + if (err != DB_SUCCESS) { + goto funct_exit; + } + if (data.found) { + FILE* ef = dict_foreign_err_file; + + err = DB_CANNOT_DROP_CONSTRAINT; + + mutex_enter(&dict_foreign_err_mutex); + rewind(ef); + ut_print_timestamp(ef); + + fputs(" Cannot drop table ", ef); + ut_print_name(ef, trx, name); + fputs("\n" + "because it is referenced by ", ef); + ut_print_name(ef, trx, data.foreign_name); + putc('\n', ef); + mutex_exit(&dict_foreign_err_mutex); + + goto funct_exit; + } +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ + } // if (!srv_read_only_mode && trx->check_foreigns) DBUG_EXECUTE_IF("row_drop_table_add_to_background", goto defer;); @@ -3571,6 +3649,7 @@ defer: pars_info_add_str_literal(info, "name", name); +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE if (sqlcom != SQLCOM_TRUNCATE && strchr(name, '/') && dict_table_get_low("SYS_FOREIGN") @@ -3596,13 +3675,14 @@ defer: "END LOOP;\n" "CLOSE fk;\n" "END;\n", FALSE, trx); - if (err == DB_SUCCESS) { - info = pars_info_create(); - pars_info_add_str_literal(info, "name", name); - goto do_drop; + if (err != DB_SUCCESS) { + goto error; } - } else { -do_drop: + info = pars_info_create(); + pars_info_add_str_literal(info, "name", name); + } +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ + { if (dict_table_get_low("SYS_VIRTUAL")) { err = que_eval_sql( info, @@ -3675,6 +3755,9 @@ do_drop: } } +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE +error: +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ switch (err) { fil_space_t* space; char* filepath; @@ -3969,6 +4052,64 @@ loop: DBUG_RETURN(err); } +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE +/****************************************************************//** +Delete a single constraint. +@return error code or DB_SUCCESS */ +static MY_ATTRIBUTE((nonnull, warn_unused_result)) +dberr_t +row_delete_constraint_low( +/*======================*/ + const char* id, /*!< in: constraint id */ + trx_t* trx) /*!< in: transaction handle */ +{ + pars_info_t* info = pars_info_create(); + + pars_info_add_str_literal(info, "id", id); + + return(que_eval_sql(info, + "PROCEDURE DELETE_CONSTRAINT () IS\n" + "BEGIN\n" + "DELETE FROM SYS_FOREIGN_COLS WHERE ID = :id;\n" + "DELETE FROM SYS_FOREIGN WHERE ID = :id;\n" + "END;\n" + , FALSE, trx)); +} + +/****************************************************************//** +Delete a single constraint. +@return error code or DB_SUCCESS */ +static MY_ATTRIBUTE((nonnull, warn_unused_result)) +dberr_t +row_delete_constraint( +/*==================*/ + const char* id, /*!< in: constraint id */ + const char* database_name, /*!< in: database name, with the + trailing '/' */ + mem_heap_t* heap, /*!< in: memory heap */ + trx_t* trx) /*!< in: transaction handle */ +{ + dberr_t err; + + /* New format constraints have ids <databasename>/<constraintname>. */ + err = row_delete_constraint_low( + mem_heap_strcat(heap, database_name, id), trx); + + if ((err == DB_SUCCESS) && !strchr(id, '/')) { + /* Old format < 4.0.18 constraints have constraint ids + NUMBER_NUMBER. We only try deleting them if the + constraint name does not contain a '/' character, otherwise + deleting a new format constraint named 'foo/bar' from + database 'baz' would remove constraint 'bar' from database + 'foo', if it existed. */ + + err = row_delete_constraint_low(id, trx); + } + + return(err); +} +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ + /*********************************************************************//** Renames a table for MySQL. @return error code or DB_SUCCESS */ @@ -3986,9 +4127,12 @@ row_rename_table_for_mysql( ibool dict_locked = FALSE; dberr_t err = DB_ERROR; mem_heap_t* heap = NULL; +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE const char** constraints_to_drop = NULL; ulint n_constraints_to_drop = 0; - ibool old_is_tmp, new_is_tmp; + bool old_is_tmp; +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ + bool new_is_tmp; pars_info_t* info = NULL; int retry; bool aux_fts_rename = false; @@ -4012,7 +4156,9 @@ row_rename_table_for_mysql( trx->op_info = "renaming table"; +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE old_is_tmp = dict_table_t::is_temporary_name(old_name); +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ new_is_tmp = dict_table_t::is_temporary_name(new_name); dict_locked = trx->dict_operation_lock_mode == RW_X_LATCH; @@ -4084,7 +4230,9 @@ row_rename_table_for_mysql( goto funct_exit; - } else if (use_fk && !old_is_tmp && new_is_tmp) { + } +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE + else if (use_fk && !old_is_tmp && new_is_tmp) { /* MySQL is doing an ALTER TABLE command and it renames the original table to a temporary table name. We want to preserve the original foreign key constraint definitions despite the @@ -4101,6 +4249,7 @@ row_rename_table_for_mysql( goto funct_exit; } } +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ /* Is a foreign key check running on this table? */ for (retry = 0; retry < 100 @@ -4180,6 +4329,142 @@ row_rename_table_for_mysql( goto end; } +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE + if (!new_is_tmp) { + /* Rename all constraints. */ + char new_table_name[MAX_TABLE_NAME_LEN + 1]; + char old_table_utf8[MAX_TABLE_NAME_LEN + 1]; + uint errors = 0; + + strncpy(old_table_utf8, old_name, MAX_TABLE_NAME_LEN); + old_table_utf8[MAX_TABLE_NAME_LEN] = '\0'; + innobase_convert_to_system_charset( + strchr(old_table_utf8, '/') + 1, + strchr(old_name, '/') +1, + MAX_TABLE_NAME_LEN, &errors); + + if (errors) { + /* Table name could not be converted from charset + my_charset_filename to UTF-8. This means that the + table name is already in UTF-8 (#mysql#50). */ + strncpy(old_table_utf8, old_name, MAX_TABLE_NAME_LEN); + old_table_utf8[MAX_TABLE_NAME_LEN] = '\0'; + } + + info = pars_info_create(); + + pars_info_add_str_literal(info, "new_table_name", new_name); + pars_info_add_str_literal(info, "old_table_name", old_name); + pars_info_add_str_literal(info, "old_table_name_utf8", + old_table_utf8); + + strncpy(new_table_name, new_name, MAX_TABLE_NAME_LEN); + new_table_name[MAX_TABLE_NAME_LEN] = '\0'; + innobase_convert_to_system_charset( + strchr(new_table_name, '/') + 1, + strchr(new_name, '/') +1, + MAX_TABLE_NAME_LEN, &errors); + + if (errors) { + /* Table name could not be converted from charset + my_charset_filename to UTF-8. This means that the + table name is already in UTF-8 (#mysql#50). */ + strncpy(new_table_name, new_name, MAX_TABLE_NAME_LEN); + new_table_name[MAX_TABLE_NAME_LEN] = '\0'; + } + + pars_info_add_str_literal(info, "new_table_utf8", new_table_name); + + err = que_eval_sql( + info, + "PROCEDURE RENAME_CONSTRAINT_IDS () IS\n" + "gen_constr_prefix CHAR;\n" + "new_db_name CHAR;\n" + "foreign_id CHAR;\n" + "new_foreign_id CHAR;\n" + "old_db_name_len INT;\n" + "old_t_name_len INT;\n" + "new_db_name_len INT;\n" + "id_len INT;\n" + "offset INT;\n" + "found INT;\n" + "BEGIN\n" + "found := 1;\n" + "old_db_name_len := INSTR(:old_table_name, '/')-1;\n" + "new_db_name_len := INSTR(:new_table_name, '/')-1;\n" + "new_db_name := SUBSTR(:new_table_name, 0,\n" + " new_db_name_len);\n" + "old_t_name_len := LENGTH(:old_table_name);\n" + "gen_constr_prefix := CONCAT(:old_table_name_utf8,\n" + " '_ibfk_');\n" + "WHILE found = 1 LOOP\n" + " SELECT ID INTO foreign_id\n" + " FROM SYS_FOREIGN\n" + " WHERE FOR_NAME = :old_table_name\n" + " AND TO_BINARY(FOR_NAME)\n" + " = TO_BINARY(:old_table_name)\n" + " LOCK IN SHARE MODE;\n" + " IF (SQL % NOTFOUND) THEN\n" + " found := 0;\n" + " ELSE\n" + " UPDATE SYS_FOREIGN\n" + " SET FOR_NAME = :new_table_name\n" + " WHERE ID = foreign_id;\n" + " id_len := LENGTH(foreign_id);\n" + " IF (INSTR(foreign_id, '/') > 0) THEN\n" + " IF (INSTR(foreign_id,\n" + " gen_constr_prefix) > 0)\n" + " THEN\n" + " offset := INSTR(foreign_id, '_ibfk_') - 1;\n" + " new_foreign_id :=\n" + " CONCAT(:new_table_utf8,\n" + " SUBSTR(foreign_id, offset,\n" + " id_len - offset));\n" + " ELSE\n" + " new_foreign_id :=\n" + " CONCAT(new_db_name,\n" + " SUBSTR(foreign_id,\n" + " old_db_name_len,\n" + " id_len - old_db_name_len));\n" + " END IF;\n" + " UPDATE SYS_FOREIGN\n" + " SET ID = new_foreign_id\n" + " WHERE ID = foreign_id;\n" + " UPDATE SYS_FOREIGN_COLS\n" + " SET ID = new_foreign_id\n" + " WHERE ID = foreign_id;\n" + " END IF;\n" + " END IF;\n" + "END LOOP;\n" + "UPDATE SYS_FOREIGN SET REF_NAME = :new_table_name\n" + "WHERE REF_NAME = :old_table_name\n" + " AND TO_BINARY(REF_NAME)\n" + " = TO_BINARY(:old_table_name);\n" + "END;\n" + , FALSE, trx); + + } else if (n_constraints_to_drop > 0) { + /* Drop some constraints of tmp tables. */ + + ulint db_name_len = dict_get_db_name_len(old_name) + 1; + char* db_name = mem_heap_strdupl(heap, old_name, + db_name_len); + ulint i; + + for (i = 0; i < n_constraints_to_drop; i++) { + err = row_delete_constraint(constraints_to_drop[i], + db_name, heap, trx); + + if (err != DB_SUCCESS) { + break; + } + } + } + if (err != DB_SUCCESS) { + goto end; + } +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ + if ((dict_table_has_fts_index(table) || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID)) && !dict_tables_have_same_db(old_name, new_name)) { @@ -4191,6 +4476,35 @@ row_rename_table_for_mysql( end: if (err != DB_SUCCESS) { +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE + if (err == DB_DUPLICATE_KEY) { + ib::error() << "Possible reasons:"; + ib::error() << "(1) Table rename would cause two" + " FOREIGN KEY constraints to have the same" + " internal name in case-insensitive" + " comparison."; + ib::error() << "(2) Table " + << ut_get_name(trx, new_name) + << " exists in the InnoDB internal data" + " dictionary though MySQL is trying to rename" + " table " << ut_get_name(trx, old_name) + << " to it. Have you deleted the .frm file and" + " not used DROP TABLE?"; + ib::info() << TROUBLESHOOTING_MSG; + ib::error() << "If table " + << ut_get_name(trx, new_name) + << " is a temporary table #sql..., then" + " it can be that there are still queries" + " running on the table, and it will be dropped" + " automatically when the queries end. You can" + " drop the orphaned table inside InnoDB by" + " creating an InnoDB table with the same name" + " in another database and copying the .frm file" + " to the current database. Then MySQL thinks" + " the table exists, and DROP TABLE will" + " succeed."; + } +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ trx->error_state = DB_SUCCESS; trx->rollback(); trx->error_state = DB_SUCCESS; diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index 595a72eb415..58640c20db0 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -2349,7 +2349,8 @@ fetch_step( if (node->into_list) { sel_assign_into_var_values(node->into_list, sel_node); - } else { + } + if (node->func) { ibool ret = (*node->func->func)( sel_node, node->func->arg); diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 32b087b5d67..3e76dabc438 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -1929,10 +1929,21 @@ skip_monitors: } } +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE + /* Create the SYS_FOREIGN and SYS_FOREIGN_COLS system tables */ + err = dict_create_or_check_foreign_constraint_tables(); + if (err == DB_SUCCESS) { + err = dict_create_or_check_sys_tablespace(); + if (err == DB_SUCCESS) { + err = dict_create_or_check_sys_virtual(); + } + } +#else err = dict_create_or_check_sys_tablespace(); if (err == DB_SUCCESS) { err = dict_create_or_check_sys_virtual(); } +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ switch (err) { case DB_SUCCESS: break; diff --git a/storage/innobase/ut/ut0ut.cc b/storage/innobase/ut/ut0ut.cc index bf35e7857c5..e09d511ed22 100644 --- a/storage/innobase/ut/ut0ut.cc +++ b/storage/innobase/ut/ut0ut.cc @@ -472,6 +472,10 @@ ut_strerr( return ("File system does not support punch hole (trim) operation."); case DB_PAGE_CORRUPTED: return("Page read from tablespace is corrupted."); +#ifdef WITH_INNODB_LEGACY_FOREIGN_STORAGE + case DB_LEGACY_FK: + return("Table requires foreign keys upgrade."); +#endif /* WITH_INNODB_LEGACY_FOREIGN_STORAGE */ /* do not add default: in order to produce a warning if new code is added to the enum but not added here */ diff --git a/storage/rocksdb/mysql-test/rocksdb/r/tbl_opt_data_index_dir.result b/storage/rocksdb/mysql-test/rocksdb/r/tbl_opt_data_index_dir.result index 95dae68b4e6..90f163b7d4b 100644 --- a/storage/rocksdb/mysql-test/rocksdb/r/tbl_opt_data_index_dir.result +++ b/storage/rocksdb/mysql-test/rocksdb/r/tbl_opt_data_index_dir.result @@ -1,16 +1,16 @@ DROP TABLE IF EXISTS t1; CREATE TABLE t1 (a INT PRIMARY KEY, b CHAR(8)) ENGINE=rocksdb DATA DIRECTORY = '/foo/bar/data'; -ERROR HY000: Can't create table `test`.`t1` (errno: 198 "Unknown error 198") +ERROR HY000: Can't create table `test`.`t1` (errno: 199 "Unknown error 199") show warnings; Level Code Message -Error 1005 Can't create table `test`.`t1` (errno: 198 "Unknown error 198") -Warning 1296 Got error 198 'Specifying DATA DIRECTORY for an individual table is not supported.' from ROCKSDB +Error 1005 Can't create table `test`.`t1` (errno: 199 "Unknown error 199") +Warning 1296 Got error 199 'Specifying DATA DIRECTORY for an individual table is not supported.' from ROCKSDB CREATE TABLE t1 (a INT PRIMARY KEY, b CHAR(8)) ENGINE=rocksdb INDEX DIRECTORY = '/foo/bar/index'; -ERROR HY000: Can't create table `test`.`t1` (errno: 199 "Unknown error 199") +ERROR HY000: Can't create table `test`.`t1` (errno: 200 "Unknown error 200") show warnings; Level Code Message -Error 1005 Can't create table `test`.`t1` (errno: 199 "Unknown error 199") -Warning 1296 Got error 199 'Specifying INDEX DIRECTORY for an individual table is not supported.' from ROCKSDB +Error 1005 Can't create table `test`.`t1` (errno: 200 "Unknown error 200") +Warning 1296 Got error 200 'Specifying INDEX DIRECTORY for an individual table is not supported.' from ROCKSDB CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY) ENGINE=rocksdb PARTITION BY RANGE (id) ( PARTITION P0 VALUES LESS THAN (1000) @@ -19,11 +19,11 @@ PARTITION P1 VALUES LESS THAN (2000) DATA DIRECTORY = '/foo/bar/data/', PARTITION P2 VALUES LESS THAN (MAXVALUE) ); -ERROR HY000: Can't create table `test`.`t1` (errno: 198 "Unknown error 198") +ERROR HY000: Can't create table `test`.`t1` (errno: 199 "Unknown error 199") show warnings; Level Code Message -Error 1005 Can't create table `test`.`t1` (errno: 198 "Unknown error 198") -Warning 1296 Got error 198 'Specifying DATA DIRECTORY for an individual table is not supported.' from ROCKSDB +Error 1005 Can't create table `test`.`t1` (errno: 199 "Unknown error 199") +Warning 1296 Got error 199 'Specifying DATA DIRECTORY for an individual table is not supported.' from ROCKSDB Error 6 Error on delete of './test/t1.par' (Errcode: 2 "No such file or directory") CREATE TABLE t1 (id int not null primary key) ENGINE=rocksdb PARTITION BY RANGE (id) ( @@ -33,9 +33,9 @@ PARTITION P1 VALUES LESS THAN (2000) INDEX DIRECTORY = '/foo/bar/data/', PARTITION P2 VALUES LESS THAN (MAXVALUE) ); -ERROR HY000: Can't create table `test`.`t1` (errno: 199 "Unknown error 199") +ERROR HY000: Can't create table `test`.`t1` (errno: 200 "Unknown error 200") show warnings; Level Code Message -Error 1005 Can't create table `test`.`t1` (errno: 199 "Unknown error 199") -Warning 1296 Got error 199 'Specifying INDEX DIRECTORY for an individual table is not supported.' from ROCKSDB +Error 1005 Can't create table `test`.`t1` (errno: 200 "Unknown error 200") +Warning 1296 Got error 200 'Specifying INDEX DIRECTORY for an individual table is not supported.' from ROCKSDB Error 6 Error on delete of './test/t1.par' (Errcode: 2 "No such file or directory") |