diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/lex.h | 1 | ||||
-rw-r--r-- | sql/sql_admin.cc | 28 | ||||
-rw-r--r-- | sql/sql_base.cc | 9 | ||||
-rw-r--r-- | sql/sql_table.cc | 1 | ||||
-rw-r--r-- | sql/sql_view.cc | 177 | ||||
-rw-r--r-- | sql/sql_view.h | 2 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 36 |
7 files changed, 227 insertions, 27 deletions
diff --git a/sql/lex.h b/sql/lex.h index 9bf4c439cb6..65411402f6a 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -376,6 +376,7 @@ static SYMBOL symbols[] = { { "MULTIPOINT", SYM(MULTIPOINT)}, { "MULTIPOLYGON", SYM(MULTIPOLYGON)}, { "MUTEX", SYM(MUTEX_SYM)}, + { "MYSQL", SYM(MYSQL_SYM)}, { "MYSQL_ERRNO", SYM(MYSQL_ERRNO_SYM)}, { "NAME", SYM(NAME_SYM)}, { "NAMES", SYM(NAMES_SYM)}, diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index 92aa414b569..65292a526fa 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -314,7 +314,8 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT *), int (handler::*operator_func)(THD *, HA_CHECK_OPT *), - int (view_operator_func)(THD *, TABLE_LIST*)) + int (view_operator_func)(THD *, TABLE_LIST*, + HA_CHECK_OPT *)) { TABLE_LIST *table; SELECT_LEX *select= &thd->lex->select_lex; @@ -380,7 +381,18 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, lex->query_tables_own_last= 0; if (view_operator_func == NULL) + { table->required_type=FRMTYPE_TABLE; + DBUG_ASSERT(!lex->only_view); + } + else if (lex->only_view) + { + table->required_type= FRMTYPE_VIEW; + } + else if (!lex->only_view && lex->sql_command == SQLCOM_REPAIR) + { + table->required_type= FRMTYPE_TABLE; + } if (lex->sql_command == SQLCOM_CHECK || lex->sql_command == SQLCOM_REPAIR || @@ -506,9 +518,9 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, } /* - CHECK TABLE command is only command where VIEW allowed here and this - command use only temporary teble method for VIEWs resolving => there - can't be VIEW tree substitition of join view => if opening table + CHECK/REPAIR TABLE command is only command where VIEW allowed here and + this command use only temporary table method for VIEWs resolving => + there can't be VIEW tree substitition of join view => if opening table succeed then table->table will have real TABLE pointer as value (in case of join view substitution table->table can be 0, but here it is impossible) @@ -521,7 +533,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, ER_CHECK_NO_SUCH_TABLE, ER(ER_CHECK_NO_SUCH_TABLE)); /* if it was a view will check md5 sum */ if (table->view && - view_checksum(thd, table) == HA_ADMIN_WRONG_CHECKSUM) + view_check(thd, table, check_opt) == HA_ADMIN_WRONG_CHECKSUM) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_VIEW_CHECKSUM, ER(ER_VIEW_CHECKSUM)); if (thd->stmt_da->is_error() && @@ -536,7 +548,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, if (table->view) { DBUG_PRINT("admin", ("calling view_operator_func")); - result_code= (*view_operator_func)(thd, table); + result_code= (*view_operator_func)(thd, table, check_opt); goto send_result; } @@ -1071,7 +1083,7 @@ bool Check_table_statement::execute(THD *thd) res= mysql_admin_table(thd, first_table, &m_lex->check_opt, "check", lock_type, 0, 0, HA_OPEN_FOR_REPAIR, 0, - &handler::ha_check, &view_checksum); + &handler::ha_check, &view_check); m_lex->select_lex.table_list.first= first_table; m_lex->query_tables= first_table; @@ -1126,7 +1138,7 @@ bool Repair_table_statement::execute(THD *thd) TL_WRITE, 1, test(m_lex->check_opt.sql_flags & TT_USEFRM), HA_OPEN_FOR_REPAIR, &prepare_for_repair, - &handler::ha_repair, 0); + &handler::ha_repair, &view_repair); /* ! we write after unlocking the table */ if (!res && !m_lex->no_write_to_binlog) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index affccf09513..592215da4d0 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -643,7 +643,8 @@ found: open_table_error(share, share->error, share->open_errno, share->errarg); DBUG_RETURN(0); } - if (share->is_view && !(db_flags & OPEN_VIEW)) + if ((share->is_view && !(db_flags & OPEN_VIEW)) || + (!share->is_view && (db_flags & OPEN_VIEW_ONLY))) { open_table_error(share, 1, ENOENT, 0); DBUG_RETURN(0); @@ -3027,7 +3028,11 @@ retry_share: mysql_mutex_lock(&LOCK_open); if (!(share= get_table_share_with_discover(thd, table_list, key, - key_length, OPEN_VIEW, + key_length, + (OPEN_VIEW | + ((table_list->required_type == + FRMTYPE_VIEW) ? + OPEN_VIEW_ONLY : 0)), &error, hash_value))) { diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 586b542a290..6ec99cdf901 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -28,7 +28,6 @@ #include "sql_base.h" // open_table_uncached, lock_table_names #include "lock.h" // mysql_unlock_tables #include "strfunc.h" // find_type2, find_set -#include "sql_view.h" // view_checksum #include "sql_truncate.h" // regenerate_locked_table #include "sql_partition.h" // mem_alloc_error, // generate_partition_syntax, diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 09784f7257a..24f01aeaa76 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -729,6 +729,26 @@ err: } +static void make_view_filename(LEX_STRING *dir, char *dir_buff, + size_t dir_buff_len, + LEX_STRING *path, char *path_buff, + size_t path_buff_len, + LEX_STRING *file, + TABLE_LIST *view) +{ + /* print file name */ + dir->length= build_table_filename(dir_buff, dir_buff_len - 1, + view->db, "", "", 0); + dir->str= dir_buff; + + path->length= build_table_filename(path_buff, path_buff_len - 1, + view->db, view->table_name, reg_ext, 0); + path->str= path_buff; + + file->str= path->str + dir->length; + file->length= path->length - dir->length; +} + /* number of required parameters for making view */ static const int required_view_parameters= 15; @@ -791,6 +811,86 @@ static File_option view_parameters[]= static LEX_STRING view_file_type[]= {{(char*) STRING_WITH_LEN("VIEW") }}; +int mariadb_fix_view(THD *thd, TABLE_LIST *view, bool wrong_checksum, + bool swap_alg) +{ + char dir_buff[FN_REFLEN + 1], path_buff[FN_REFLEN + 1]; + LEX_STRING dir, file, path; + DBUG_ENTER("mariadb_fix_view"); + + if (!wrong_checksum && view->mariadb_version) + DBUG_RETURN(HA_ADMIN_OK); + + make_view_filename(&dir, dir_buff, sizeof(dir_buff), + &path, path_buff, sizeof(path_buff), + &file, view); + /* init timestamp */ + if (!view->timestamp.str) + view->timestamp.str= view->timestamp_buffer; + + /* check old .frm */ + { + char path_buff[FN_REFLEN]; + LEX_STRING path; + File_parser *parser; + + path.str= path_buff; + fn_format(path_buff, file.str, dir.str, "", MY_UNPACK_FILENAME); + path.length= strlen(path_buff); + if (access(path.str, F_OK)) + DBUG_RETURN(HA_ADMIN_INVALID); + + if (!(parser= sql_parse_prepare(&path, thd->mem_root, 0))) + DBUG_RETURN(HA_ADMIN_INTERNAL_ERROR); + + if (!parser->ok() || !is_equal(&view_type, parser->type())) + DBUG_RETURN(HA_ADMIN_INVALID); + } + + if (swap_alg && view->algorithm != VIEW_ALGORITHM_UNDEFINED) + { + DBUG_ASSERT(view->algorithm == VIEW_ALGORITHM_MERGE || + view->algorithm == VIEW_ALGORITHM_TMPTABLE); + if (view->algorithm == VIEW_ALGORITHM_MERGE) + view->algorithm= VIEW_ALGORITHM_TMPTABLE; + else + view->algorithm= VIEW_ALGORITHM_MERGE; + } + else + swap_alg= 0; + if (wrong_checksum) + { + if (view->md5.length != 32) + { + if ((view->md5.str= (char *)thd->alloc(32 + 1)) == NULL) + DBUG_RETURN(HA_ADMIN_FAILED); + } + view->calc_md5(view->md5.str); + view->md5.length= 32; + } + view->mariadb_version= MYSQL_VERSION_ID; + + if (sql_create_definition_file(&dir, &file, view_file_type, + (uchar*)view, view_parameters)) + { + sql_print_error("View '%-.192s'.'%-.192s': algorithm swap error.", + view->db, view->table_name); + DBUG_RETURN(HA_ADMIN_INTERNAL_ERROR); + } + sql_print_information("View '%-.192s'.'%-.192s': versioned to %llu%s%s", + view->db, view->table_name, view->mariadb_version, + (wrong_checksum ? ", and checksum corrected" : ""), + (swap_alg ? + ((view->algorithm == VIEW_ALGORITHM_MERGE) ? + ", and algorithm swapped to 'MERGE'" + : ", and algorithm swapped to 'TEMPTABLE'") + : "")); + + + DBUG_RETURN(HA_ADMIN_OK); +} + + /* Register VIEW (write .frm & process .frm's history backups) @@ -927,17 +1027,9 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, } loop_out: /* print file name */ - dir.length= build_table_filename(dir_buff, sizeof(dir_buff) - 1, - view->db, "", "", 0); - dir.str= dir_buff; - - path.length= build_table_filename(path_buff, sizeof(path_buff) - 1, - view->db, view->table_name, reg_ext, 0); - path.str= path_buff; - - file.str= path.str + dir.length; - file.length= path.length - dir.length; - + make_view_filename(&dir, dir_buff, sizeof(dir_buff), + &path, path_buff, sizeof(path_buff), + &file, view); /* init timestamp */ if (!view->timestamp.str) view->timestamp.str= view->timestamp_buffer; @@ -1063,7 +1155,7 @@ err: SYNOPSIS mysql_make_view() - thd Thread handler + thd Thread handle parser parser object table TABLE_LIST structure for filling flags flags @@ -1634,7 +1726,7 @@ err: SYNOPSIS mysql_drop_view() - thd - thread handler + thd - thread handle views - views to delete drop_mode - cascade/check @@ -1755,7 +1847,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) SYNOPSIS check_key_in_view() - thd thread handler + thd thread handle view view for check with opened table DESCRIPTION @@ -1941,6 +2033,63 @@ int view_checksum(THD *thd, TABLE_LIST *view) HA_ADMIN_OK); } +/** + Check view + + @param thd thread handle + @param view view for check + @param check_opt check options + + @retval HA_ADMIN_OK OK + @retval HA_ADMIN_NOT_IMPLEMENTED it is not VIEW + @retval HA_ADMIN_WRONG_CHECKSUM check sum is wrong +*/ +int view_check(THD *thd, TABLE_LIST *view, HA_CHECK_OPT *check_opt) +{ + int res; + DBUG_ENTER("view_check"); + if ((res= view_checksum(thd, view)) != HA_ADMIN_OK) + DBUG_RETURN(res); + if (((check_opt->sql_flags & TT_FOR_UPGRADE) && + !view->mariadb_version)) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_TABLE_NEEDS_UPGRADE, + ER(ER_TABLE_NEEDS_UPGRADE), + view->db, + view->table_name); + DBUG_RETURN(HA_ADMIN_NEEDS_UPGRADE); + } + DBUG_RETURN(HA_ADMIN_OK); +} + + +/** + Repair view + + @param thd thread handle + @param view view for check + @param check_opt check options + + @retval HA_ADMIN_OK OK + @retval HA_ADMIN_NOT_IMPLEMENTED it is not VIEW + @retval HA_ADMIN_WRONG_CHECKSUM check sum is wrong +*/ + +int view_repair(THD *thd, TABLE_LIST *view, HA_CHECK_OPT *check_opt) +{ + DBUG_ENTER("view_repair"); + bool swap_alg= (check_opt->sql_flags & TT_FROM_MYSQL); + bool wrong_checksum= view_checksum(thd, view); + int ret; + if (wrong_checksum || swap_alg || (!view->mariadb_version)) + { + ret= mariadb_fix_view(thd, view, wrong_checksum, swap_alg); + DBUG_RETURN(ret); + } + DBUG_RETURN(HA_ADMIN_OK); +} + /* rename view diff --git a/sql/sql_view.h b/sql/sql_view.h index 2e9c77252e8..1026c57aaaf 100644 --- a/sql/sql_view.h +++ b/sql/sql_view.h @@ -44,6 +44,8 @@ bool check_key_in_view(THD *thd, TABLE_LIST * view); bool insert_view_fields(THD *thd, List<Item> *list, TABLE_LIST *view); int view_checksum(THD *thd, TABLE_LIST *view); +int view_check(THD *thd, TABLE_LIST *view, HA_CHECK_OPT *check_opt); +int view_repair(THD *thd, TABLE_LIST *view, HA_CHECK_OPT *check_opt); extern TYPELIB updatable_views_with_limit_typelib; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index bd0014f4764..8f135e63113 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1145,6 +1145,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token MULTIPOINT %token MULTIPOLYGON %token MUTEX_SYM +%token MYSQL_SYM %token MYSQL_ERRNO_SYM %token NAMES_SYM /* SQL-2003-N */ %token NAME_SYM /* SQL-2003-N */ @@ -7191,7 +7192,7 @@ opt_checksum_type: ; repair: - REPAIR opt_no_write_to_binlog table_or_tables + REPAIR opt_no_write_to_binlog table_or_view { LEX *lex=Lex; lex->sql_command = SQLCOM_REPAIR; @@ -7204,6 +7205,15 @@ repair: table_list opt_mi_repair_type { LEX* lex= thd->lex; + if ((lex->only_view && + ((lex->check_opt.flags & (T_QUICK | T_EXTEND)) || + (lex->check_opt.sql_flags & TT_USEFRM))) || + (!lex->only_view && + (lex->check_opt.sql_flags & TT_FROM_MYSQL))) + { + my_parse_error(ER(ER_SYNTAX_ERROR)); + MYSQL_YYABORT; + } DBUG_ASSERT(!lex->m_stmt); lex->m_stmt= new (thd->mem_root) Repair_table_statement(lex); if (lex->m_stmt == NULL) @@ -7225,6 +7235,7 @@ mi_repair_type: QUICK { Lex->check_opt.flags|= T_QUICK; } | EXTENDED_SYM { Lex->check_opt.flags|= T_EXTEND; } | USE_FRM { Lex->check_opt.sql_flags|= TT_USEFRM; } + | FROM MYSQL_SYM { Lex->check_opt.sql_flags|= TT_FROM_MYSQL; } ; analyze: @@ -7257,7 +7268,7 @@ binlog_base64_event: ; check: - CHECK_SYM table_or_tables + CHECK_SYM table_or_view { LEX *lex=Lex; @@ -7275,6 +7286,13 @@ check: table_list opt_mi_check_type { LEX* lex= thd->lex; + if (lex->only_view && + (lex->check_opt.flags & (T_QUICK | T_FAST | T_EXTEND | + T_CHECK_ONLY_CHANGED))) + { + my_parse_error(ER(ER_SYNTAX_ERROR)); + MYSQL_YYABORT; + } DBUG_ASSERT(!lex->m_stmt); lex->m_stmt= new (thd->mem_root) Check_table_statement(lex); if (lex->m_stmt == NULL) @@ -7382,6 +7400,7 @@ keycache: LEX *lex=Lex; lex->sql_command= SQLCOM_ASSIGN_TO_KEYCACHE; lex->ident= $6; + lex->only_view= FALSE; } ; @@ -7426,6 +7445,7 @@ preload: LEX *lex=Lex; lex->sql_command=SQLCOM_PRELOAD_KEYS; lex->alter_info.reset(); + lex->only_view= FALSE; } preload_list_or_parts {} @@ -13187,6 +13207,7 @@ keyword_sp: | MULTIPOINT {} | MULTIPOLYGON {} | MUTEX_SYM {} + | MYSQL_SYM {} | MYSQL_ERRNO_SYM {} | NAME_SYM {} | NAMES_SYM {} @@ -13786,7 +13807,18 @@ lock: table_or_tables: TABLE_SYM + { Lex->only_view= FALSE; } + | TABLES + { Lex->only_view= FALSE; } + ; + +table_or_view: + TABLE_SYM + { Lex->only_view= FALSE; } | TABLES + { Lex->only_view= FALSE; } + | VIEW_SYM + { Lex->only_view= TRUE; } ; table_lock_list: |