summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2014-12-19 11:35:44 +0100
committerSergei Golubchik <sergii@pisem.net>2014-12-19 11:35:44 +0100
commita978bdda1e2de35c79e432f026869e163657a263 (patch)
tree73e36b02fe3b8515c1f05bf4d43ecfa0bbf7c420 /sql
parent724dbaabc0d06c4446417eb217d8536f193461f9 (diff)
parent0773c7f422c426e5693fc901df9999092e56aef3 (diff)
downloadmariadb-git-a978bdda1e2de35c79e432f026869e163657a263.tar.gz
mysql-5.5.41 merge
Diffstat (limited to 'sql')
-rw-r--r--sql/handler.h3
-rw-r--r--sql/item_func.cc23
-rw-r--r--sql/item_func.h7
-rw-r--r--sql/log_event.cc17
-rw-r--r--sql/log_event.h4
-rw-r--r--sql/sql_parse.cc114
-rw-r--r--sql/sql_parse.h3
-rw-r--r--sql/sql_table.cc12
-rw-r--r--sql/sys_vars.cc25
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(