diff options
author | Sergei Golubchik <sergii@pisem.net> | 2014-12-19 11:35:44 +0100 |
---|---|---|
committer | Sergei Golubchik <sergii@pisem.net> | 2014-12-19 11:35:44 +0100 |
commit | a978bdda1e2de35c79e432f026869e163657a263 (patch) | |
tree | 73e36b02fe3b8515c1f05bf4d43ecfa0bbf7c420 /sql | |
parent | 724dbaabc0d06c4446417eb217d8536f193461f9 (diff) | |
parent | 0773c7f422c426e5693fc901df9999092e56aef3 (diff) | |
download | mariadb-git-a978bdda1e2de35c79e432f026869e163657a263.tar.gz |
mysql-5.5.41 merge
Diffstat (limited to 'sql')
-rw-r--r-- | sql/handler.h | 3 | ||||
-rw-r--r-- | sql/item_func.cc | 23 | ||||
-rw-r--r-- | sql/item_func.h | 7 | ||||
-rw-r--r-- | sql/log_event.cc | 17 | ||||
-rw-r--r-- | sql/log_event.h | 4 | ||||
-rw-r--r-- | sql/sql_parse.cc | 114 | ||||
-rw-r--r-- | sql/sql_parse.h | 3 | ||||
-rw-r--r-- | sql/sql_table.cc | 12 | ||||
-rw-r--r-- | sql/sys_vars.cc | 25 |
9 files changed, 179 insertions, 29 deletions
diff --git a/sql/handler.h b/sql/handler.h index d7b92003083..5c902e604e9 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1079,6 +1079,9 @@ inline LEX_STRING *hton_name(const handlerton *hton) #define HTON_NO_PARTITION (1 << 8) //You can not partition these tables #define HTON_EXTENDED_KEYS (1 << 9) //supports extended keys +// MySQL compatibility. Unused. +#define HTON_SUPPORTS_FOREIGN_KEYS (1 << 0) //Foreign key constraint supported. + class Ha_trx_info; struct THD_TRANS diff --git a/sql/item_func.cc b/sql/item_func.cc index 52693b1961a..93eafdfa938 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -6545,21 +6545,24 @@ longlong Item_func_is_free_lock::val_int() DBUG_ASSERT(fixed == 1); String *res=args[0]->val_str(&value); User_level_lock *ull; + longlong ret_val= 0LL; null_value=0; if (!res || !res->length()) { null_value=1; - return 0; + return ret_val; } mysql_mutex_lock(&LOCK_user_locks); ull= (User_level_lock *) my_hash_search(&hash_user_locks, (uchar*) res->ptr(), (size_t) res->length()); - mysql_mutex_unlock(&LOCK_user_locks); if (!ull || !ull->locked) - return 1; - return 0; + ret_val= 1; + mysql_mutex_unlock(&LOCK_user_locks); + DEBUG_SYNC(current_thd, "after_getting_user_level_lock_info"); + + return ret_val; } longlong Item_func_is_used_lock::val_int() @@ -6567,6 +6570,7 @@ longlong Item_func_is_used_lock::val_int() DBUG_ASSERT(fixed == 1); String *res=args[0]->val_str(&value); User_level_lock *ull; + my_thread_id thread_id= 0UL; null_value=1; if (!res || !res->length()) @@ -6575,12 +6579,15 @@ longlong Item_func_is_used_lock::val_int() mysql_mutex_lock(&LOCK_user_locks); ull= (User_level_lock *) my_hash_search(&hash_user_locks, (uchar*) res->ptr(), (size_t) res->length()); + if ((ull != NULL) && ull->locked) + { + null_value= 0; + thread_id= ull->thread_id; + } mysql_mutex_unlock(&LOCK_user_locks); - if (!ull || !ull->locked) - return 0; + DEBUG_SYNC(current_thd, "after_getting_user_level_lock_info"); - null_value=0; - return ull->thread_id; + return thread_id; } diff --git a/sql/item_func.h b/sql/item_func.h index ab0ae5f0bda..4b11238c10d 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1,7 +1,7 @@ #ifndef ITEM_FUNC_INCLUDED #define ITEM_FUNC_INCLUDED -/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2009, 2014, SkySQL Ab. +/* Copyright (c) 2000, 2014, Oracle and/or its affiliates. + Copyright (c) 2009, 2014, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -279,7 +279,8 @@ public: inline longlong check_integer_overflow(longlong value, bool val_unsigned) { if ((unsigned_flag && !val_unsigned && value < 0) || - (!unsigned_flag && val_unsigned && (ulonglong) value > LONGLONG_MAX)) + (!unsigned_flag && val_unsigned && + (ulonglong) value > (ulonglong) LONGLONG_MAX)) return raise_integer_overflow(); return value; } diff --git a/sql/log_event.cc b/sql/log_event.cc index 6b21a303a50..d04ac1e1a44 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1583,7 +1583,7 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len, ev = new Execute_load_log_event(buf, event_len, description_event); break; case START_EVENT_V3: /* this is sent only by MySQL <=4.x */ - ev = new Start_log_event_v3(buf, description_event); + ev = new Start_log_event_v3(buf, event_len, description_event); break; case STOP_EVENT: ev = new Stop_log_event(buf, description_event); @@ -4138,11 +4138,17 @@ void Start_log_event_v3::print(FILE* file, PRINT_EVENT_INFO* print_event_info) Start_log_event_v3::Start_log_event_v3() */ -Start_log_event_v3::Start_log_event_v3(const char* buf, +Start_log_event_v3::Start_log_event_v3(const char* buf, uint event_len, const Format_description_log_event *description_event) - :Log_event(buf, description_event) + :Log_event(buf, description_event), binlog_version(BINLOG_VERSION) { + if (event_len < (uint)description_event->common_header_len + + ST_COMMON_HEADER_LEN_OFFSET) + { + server_version[0]= 0; + return; + } buf+= description_event->common_header_len; binlog_version= uint2korr(buf+ST_BINLOG_VER_OFFSET); memcpy(server_version, buf+ST_SERVER_VER_OFFSET, @@ -4442,9 +4448,12 @@ Format_description_log_event(const char* buf, const Format_description_log_event* description_event) - :Start_log_event_v3(buf, description_event), event_type_permutation(0) + :Start_log_event_v3(buf, event_len, description_event), + common_header_len(0), post_header_len(NULL), event_type_permutation(0) { DBUG_ENTER("Format_description_log_event::Format_description_log_event(char*,...)"); + if (!Start_log_event_v3::is_valid()) + DBUG_VOID_RETURN; /* sanity check */ buf+= LOG_EVENT_MINIMAL_HEADER_LEN; if ((common_header_len=buf[ST_COMMON_HEADER_LEN_OFFSET]) < OLD_HEADER_LEN) DBUG_VOID_RETURN; /* sanity check */ diff --git a/sql/log_event.h b/sql/log_event.h index c10380618a8..4ae01323b4b 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -2366,14 +2366,14 @@ public: void print(FILE* file, PRINT_EVENT_INFO* print_event_info); #endif - Start_log_event_v3(const char* buf, + Start_log_event_v3(const char* buf, uint event_len, const Format_description_log_event* description_event); ~Start_log_event_v3() {} Log_event_type get_type_code() { return START_EVENT_V3;} #ifdef MYSQL_SERVER bool write(IO_CACHE* file); #endif - bool is_valid() const { return 1; } + bool is_valid() const { return server_version[0] != 0; } int get_data_size() { return START_V3_HEADER_LEN; //no variable-sized part diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index c21e7fa3e4b..4ad3f9ab8c5 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5383,6 +5383,115 @@ bool check_global_access(THD *thd, ulong want_access, bool no_errors) #endif } + +/** + Checks foreign key's parent table access. + + @param thd [in] Thread handler + @param create_info [in] Create information (like MAX_ROWS, ENGINE or + temporary table flag) + @param alter_info [in] Initial list of columns and indexes for the + table to be created + + @retval + false ok. + @retval + true error or access denied. Error is sent to client in this case. +*/ +bool check_fk_parent_table_access(THD *thd, + HA_CREATE_INFO *create_info, + Alter_info *alter_info) +{ + Key *key; + List_iterator<Key> key_iterator(alter_info->key_list); + + while ((key= key_iterator++)) + { + if (key->type == Key::FOREIGN_KEY) + { + TABLE_LIST parent_table; + bool is_qualified_table_name; + Foreign_key *fk_key= (Foreign_key *)key; + LEX_STRING db_name; + LEX_STRING table_name= { fk_key->ref_table->table.str, + fk_key->ref_table->table.length }; + const ulong privileges= (SELECT_ACL | INSERT_ACL | UPDATE_ACL | + DELETE_ACL | REFERENCES_ACL); + + // Check if tablename is valid or not. + DBUG_ASSERT(table_name.str != NULL); + if (check_table_name(table_name.str, table_name.length, false)) + { + my_error(ER_WRONG_TABLE_NAME, MYF(0), table_name.str); + return true; + } + + if (fk_key->ref_table->db.str) + { + is_qualified_table_name= true; + db_name.str= (char *) thd->memdup(fk_key->ref_table->db.str, + fk_key->ref_table->db.length+1); + db_name.length= fk_key->ref_table->db.length; + + // Check if database name is valid or not. + if (fk_key->ref_table->db.str && check_db_name(&db_name)) + { + my_error(ER_WRONG_DB_NAME, MYF(0), db_name.str); + return true; + } + } + else if (thd->lex->copy_db_to(&db_name.str, &db_name.length)) + return true; + else + is_qualified_table_name= false; + + // if lower_case_table_names is set then convert tablename to lower case. + if (lower_case_table_names) + { + table_name.str= (char *) thd->memdup(fk_key->ref_table->table.str, + fk_key->ref_table->table.length+1); + table_name.length= my_casedn_str(files_charset_info, table_name.str); + } + + parent_table.init_one_table(db_name.str, db_name.length, + table_name.str, table_name.length, + table_name.str, TL_IGNORE); + + /* + Check if user has any of the "privileges" at table level on + "parent_table". + Having privilege on any of the parent_table column is not + enough so checking whether user has any of the "privileges" + at table level only here. + */ + if (check_some_access(thd, privileges, &parent_table) || + parent_table.grant.want_privilege) + { + if (is_qualified_table_name) + { + const size_t qualified_table_name_len= NAME_LEN + 1 + NAME_LEN + 1; + char *qualified_table_name= (char *) thd->alloc(qualified_table_name_len); + + my_snprintf(qualified_table_name, qualified_table_name_len, "%s.%s", + db_name.str, table_name.str); + table_name.str= qualified_table_name; + } + + my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), + "REFERENCES", + thd->security_ctx->priv_user, + thd->security_ctx->host_or_ip, + table_name.str); + + return true; + } + } + } + + return false; +} + + /**************************************************************************** Check stack size; Send error if there isn't enough stack to continue ****************************************************************************/ @@ -7347,8 +7456,11 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables, if (check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE)) goto err; } - error= FALSE; + if (check_fk_parent_table_access(thd, &lex->create_info, &lex->alter_info)) + goto err; + + error= FALSE; err: DBUG_RETURN(error); } diff --git a/sql/sql_parse.h b/sql/sql_parse.h index d1d6458d22c..60d5925c573 100644 --- a/sql/sql_parse.h +++ b/sql/sql_parse.h @@ -45,6 +45,9 @@ bool delete_precheck(THD *thd, TABLE_LIST *tables); bool insert_precheck(THD *thd, TABLE_LIST *tables); bool create_table_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *create_table); +bool check_fk_parent_table_access(THD *thd, + HA_CREATE_INFO *create_info, + Alter_info *alter_info); bool parse_sql(THD *thd, Parser_state *parser_state, diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 9a0a64151d5..77dbc765809 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -6246,6 +6246,18 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, } /* + If foreign key is added then check permission to access parent table. + + In function "check_fk_parent_table_access", create_info->db_type is used + to identify whether engine supports FK constraint or not. Since + create_info->db_type is set here, check to parent table access is delayed + till this point for the alter operation. + */ + if ((alter_info->flags & ALTER_FOREIGN_KEY) && + check_fk_parent_table_access(thd, create_info, alter_info)) + goto err; + + /* If this is an ALTER TABLE and no explicit row type specified reuse the table's row type. Note: this is the same as if the row type was specified explicitly and diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 5c2cabf7c2e..7cad362f6f2 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -2650,13 +2650,13 @@ static Sys_var_bit Sys_log_off( static bool fix_sql_log_bin_after_update(sys_var *self, THD *thd, enum_var_type type) { - if (type == OPT_SESSION) - { - if (thd->variables.sql_log_bin) - thd->variables.option_bits |= OPTION_BIN_LOG; - else - thd->variables.option_bits &= ~OPTION_BIN_LOG; - } + DBUG_ASSERT(type == OPT_SESSION); + + if (thd->variables.sql_log_bin) + thd->variables.option_bits |= OPTION_BIN_LOG; + else + thd->variables.option_bits &= ~OPTION_BIN_LOG; + return FALSE; } @@ -2678,7 +2678,10 @@ static bool check_sql_log_bin(sys_var *self, THD *thd, set_var *var) return TRUE; if (var->type == OPT_GLOBAL) - return FALSE; + { + my_error(ER_INCORRECT_GLOBAL_LOCAL_VAR, MYF(0), self->name.str, "SESSION"); + return TRUE; + } if (error_if_in_trans_or_substatement(thd, ER_STORED_FUNCTION_PREVENTS_SWITCH_SQL_LOG_BIN, @@ -2689,9 +2692,9 @@ static bool check_sql_log_bin(sys_var *self, THD *thd, set_var *var) } static Sys_var_mybool Sys_log_binlog( - "sql_log_bin", "sql_log_bin", - SESSION_VAR(sql_log_bin), NO_CMD_LINE, - DEFAULT(TRUE), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_sql_log_bin), + "sql_log_bin", "Controls whether logging to the binary log is done", + SESSION_VAR(sql_log_bin), NO_CMD_LINE, DEFAULT(TRUE), + NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_sql_log_bin), ON_UPDATE(fix_sql_log_bin_after_update)); static Sys_var_bit Sys_sql_warnings( |