diff options
author | unknown <jani@ua141d10.elisa.omakaista.fi> | 2007-03-29 17:27:42 +0300 |
---|---|---|
committer | unknown <jani@ua141d10.elisa.omakaista.fi> | 2007-03-29 17:27:42 +0300 |
commit | 374718ff456af3c210df6b4638b2a43b89b9762a (patch) | |
tree | 94d5a320e9c08b8f33e5b1e51f794fe67b8c9cc7 /sql | |
parent | 4bcc759f71bf256f20180b5e585b726a2eb1583d (diff) | |
parent | 00aaa9a3d482f726d903489ad142b2ddccceaf8a (diff) | |
download | mariadb-git-374718ff456af3c210df6b4638b2a43b89b9762a.tar.gz |
Merge ua141d10.elisa.omakaista.fi:/home/my/bk/mysql-5.0-marvel
into ua141d10.elisa.omakaista.fi:/home/my/bk/mysql-5.1-marvel
client/mysql.cc:
Auto merged
client/mysqlbinlog.cc:
Auto merged
BitKeeper/deleted/.del-my_lread.c:
Auto merged
BitKeeper/deleted/.del-my_lwrite.c:
Auto merged
BitKeeper/deleted/.del-raid.cc~488f5fa6538394e1:
Auto merged
BitKeeper/deleted/.del-raid.h~2d2503a66b128ac6:
Auto merged
client/mysqldump.c:
Auto merged
extra/perror.c:
Auto merged
include/my_sys.h:
Auto merged
libmysql/libmysql.c:
Auto merged
libmysqld/libmysqld.c:
Auto merged
mysql-test/r/mysqlbinlog2.result:
Auto merged
mysql-test/r/sp-security.result:
Auto merged
mysql-test/r/view_grant.result:
Auto merged
mysql-test/t/grant.test:
Auto merged
mysql-test/t/sp-security.test:
Auto merged
mysql-test/t/sp.test:
Auto merged
mysql-test/t/sp_trans.test:
Auto merged
mysql-test/t/view_grant.test:
Auto merged
mysys/default.c:
Auto merged
mysys/hash.c:
Auto merged
mysys/mf_iocache.c:
Auto merged
mysys/mf_keycache.c:
Auto merged
mysys/my_alloc.c:
Auto merged
mysys/my_dup.c:
Auto merged
mysys/my_getwd.c:
Auto merged
mysys/my_handler.c:
Auto merged
mysys/my_lib.c:
Auto merged
mysys/my_malloc.c:
Auto merged
mysys/my_pread.c:
Auto merged
mysys/my_read.c:
Auto merged
mysys/my_seek.c:
Auto merged
mysys/my_static.c:
Auto merged
mysys/safemalloc.c:
Auto merged
mysys/thr_alarm.c:
Auto merged
mysys/typelib.c:
Auto merged
sql/handler.cc:
Auto merged
sql/item.cc:
Auto merged
sql/item_cmpfunc.cc:
Auto merged
sql/item_func.h:
Auto merged
sql/item_subselect.cc:
Auto merged
sql/log_event.cc:
Auto merged
sql/net_serv.cc:
Auto merged
sql/opt_range.cc:
Auto merged
sql/slave.cc:
Auto merged
sql/sp.cc:
Auto merged
sql/sp_head.cc:
Auto merged
sql/sql_acl.cc:
Auto merged
sql/sql_base.cc:
Auto merged
sql/sql_cache.cc:
Auto merged
sql/sql_class.cc:
Auto merged
sql/sql_class.h:
Auto merged
sql/sql_delete.cc:
Auto merged
sql/sql_load.cc:
Auto merged
sql/sql_prepare.cc:
Auto merged
sql/sql_repl.cc:
Auto merged
sql/sql_select.cc:
Auto merged
sql/sql_table.cc:
Auto merged
sql/sql_view.cc:
Auto merged
sql/strfunc.cc:
Auto merged
sql/table.cc:
Auto merged
sql/tztime.cc:
Auto merged
sql/unireg.cc:
Auto merged
sql-common/client.c:
Auto merged
sql-common/my_time.c:
Auto merged
storage/archive/ha_archive.cc:
Auto merged
storage/heap/_check.c:
Auto merged
storage/heap/hp_delete.c:
Auto merged
storage/heap/hp_hash.c:
Auto merged
storage/heap/hp_open.c:
Auto merged
storage/heap/hp_rkey.c:
Auto merged
storage/heap/hp_rrnd.c:
Auto merged
storage/heap/hp_write.c:
Auto merged
storage/innobase/handler/ha_innodb.cc:
Auto merged
storage/myisam/mi_close.c:
Auto merged
storage/myisam/mi_delete.c:
Auto merged
storage/myisam/mi_dynrec.c:
Auto merged
storage/myisam/mi_keycache.c:
Auto merged
storage/myisam/mi_page.c:
Auto merged
storage/myisam/mi_statrec.c:
Auto merged
storage/myisam/myisamchk.c:
Auto merged
storage/myisammrg/myrg_extra.c:
Auto merged
storage/ndb/src/mgmclient/CommandInterpreter.cpp:
Auto merged
tests/mysql_client_test.c:
Auto merged
mysql-test/r/grant.result:
Merged from 5.0
mysql-test/r/sp.result:
Merged from 5.0
mysql-test/r/sp_trans.result:
Merged from 5.0
mysql-test/t/mysqlbinlog2.test:
Merged from 5.0
mysys/thr_lock.c:
Merged from 5.0
sql/ha_ndbcluster.cc:
Merged from 5.0
sql/log.cc:
Merged from 5.0
sql/mysql_priv.h:
Merged from 5.0
sql/mysqld.cc:
Merged from 5.0
sql/set_var.cc:
Merged from 5.0
sql/sql_db.cc:
Merged from 5.0
sql/sql_insert.cc:
Merged from 5.0
sql/sql_parse.cc:
Merged from 5.0
sql/sql_show.cc:
Merged from 5.0
sql/sql_update.cc:
Merged from 5.0
Diffstat (limited to 'sql')
-rw-r--r-- | sql/ha_ndbcluster.cc | 5 | ||||
-rw-r--r-- | sql/handler.cc | 2 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 2 | ||||
-rw-r--r-- | sql/item_func.h | 4 | ||||
-rw-r--r-- | sql/log.cc | 6 | ||||
-rw-r--r-- | sql/mysql_priv.h | 10 | ||||
-rw-r--r-- | sql/net_serv.cc | 2 | ||||
-rw-r--r-- | sql/set_var.cc | 2 | ||||
-rw-r--r-- | sql/sp.cc | 6 | ||||
-rw-r--r-- | sql/sp_head.cc | 8 | ||||
-rw-r--r-- | sql/sql_acl.cc | 31 | ||||
-rw-r--r-- | sql/sql_cache.cc | 6 | ||||
-rw-r--r-- | sql/sql_class.cc | 7 | ||||
-rw-r--r-- | sql/sql_class.h | 8 | ||||
-rw-r--r-- | sql/sql_db.cc | 330 | ||||
-rw-r--r-- | sql/sql_delete.cc | 4 | ||||
-rw-r--r-- | sql/sql_insert.cc | 12 | ||||
-rw-r--r-- | sql/sql_load.cc | 16 | ||||
-rw-r--r-- | sql/sql_parse.cc | 43 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 2 | ||||
-rw-r--r-- | sql/sql_show.cc | 20 | ||||
-rw-r--r-- | sql/sql_table.cc | 2 | ||||
-rw-r--r-- | sql/sql_update.cc | 54 | ||||
-rw-r--r-- | sql/sql_view.cc | 35 |
24 files changed, 381 insertions, 236 deletions
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 8e8aa162fff..4ad0e696a12 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -4150,8 +4150,7 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) { m_transaction_on= FALSE; /* Would be simpler if has_transactions() didn't always say "yes" */ - thd->options|= OPTION_STATUS_NO_TRANS_UPDATE; - thd->no_trans_update= TRUE; + thd->no_trans_update.all= thd->no_trans_update.stmt= TRUE; } else if (!thd->transaction.on) m_transaction_on= FALSE; @@ -4837,7 +4836,7 @@ int ha_ndbcluster::create(const char *name, for (i= 0; i < form->s->fields; i++) { Field *field= form->field[i]; - DBUG_PRINT("info", ("name: %s, type: %u, pack_length: %d", + DBUG_PRINT("info", ("name: %s type: %u pack_length: %d", field->field_name, field->real_type(), field->pack_length())); if ((my_errno= create_ndb_column(col, field, create_info))) diff --git a/sql/handler.cc b/sql/handler.cc index 0ecfce9349e..77cf7c76278 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -844,7 +844,7 @@ int ha_rollback_trans(THD *thd, bool all) the error log; but we don't want users to wonder why they have this message in the error log, so we don't send it. */ - if (is_real_trans && (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && + if (is_real_trans && thd->no_trans_update.all && !thd->slave_thread && thd->killed != THD::KILL_CONNECTION) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARNING_NOT_COMPLETE_ROLLBACK, diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 747d37c18d2..5bc2abb608a 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2405,7 +2405,7 @@ byte *in_row::get_value(Item *item) void in_row::set(uint pos, Item *item) { DBUG_ENTER("in_row::set"); - DBUG_PRINT("enter", ("pos %u item 0x%lx", pos, (ulong) item)); + DBUG_PRINT("enter", ("pos: %u item: 0x%lx", pos, (ulong) item)); ((cmp_item_row*) base)[pos].store_value_by_template(&tmp, item); DBUG_VOID_RETURN; } diff --git a/sql/item_func.h b/sql/item_func.h index 6464b5757c8..4479961637f 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1440,7 +1440,7 @@ private: bool execute(Field **flp); bool execute_impl(THD *thd, Field *return_value_fld); Field *sp_result_field(void) const; - + public: Item_func_sp(Name_resolution_context *context_arg, sp_name *name); @@ -1451,6 +1451,8 @@ public: virtual ~Item_func_sp() {} + table_map used_tables() const { return RAND_TABLE_BIT; } + void cleanup(); const char *func_name() const; diff --git a/sql/log.cc b/sql/log.cc index 4a51c52056d..54b71e15b07 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1587,8 +1587,7 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) table. Such cases should be rare (updating a non-transactional table inside a transaction...) */ - if (unlikely(thd->options & (OPTION_STATUS_NO_TRANS_UPDATE | - OPTION_KEEP_LOG))) + if (unlikely(thd->no_trans_update.all || (thd->options & OPTION_KEEP_LOG))) { Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, FALSE); qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE) @@ -1643,8 +1642,7 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv) non-transactional table. Otherwise, truncate the binlog cache starting from the SAVEPOINT command. */ - if (unlikely(thd->options & - (OPTION_STATUS_NO_TRANS_UPDATE | OPTION_KEEP_LOG))) + if (unlikely(thd->no_trans_update.all || (thd->options & OPTION_KEEP_LOG))) { int error= thd->binlog_query(THD::STMT_QUERY_TYPE, diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 0dcdea5c4f4..0ef6877a795 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -340,9 +340,6 @@ MY_LOCALE *my_locale_by_number(uint number); /* The following is used to detect a conflict with DISTINCT */ #define SELECT_ALL (ULL(1) << 24) // SELECT, user, parser -/* Set if we are updating a non-transaction safe table */ -#define OPTION_STATUS_NO_TRANS_UPDATE (ULL(1) << 25) // THD, intern - /* The following can be set when importing tables in a 'wrong order' to suppress foreign key checks */ #define OPTION_NO_FOREIGN_KEY_CHECKS (ULL(1) << 26) // THD, user, binlog @@ -835,7 +832,8 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent); bool do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db, char *new_table_name, char *new_table_alias, bool skip_error); -bool mysql_change_db(THD *thd,const char *name,bool no_access_check); +bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, + bool force_switch); void mysql_parse(THD *thd,char *inBuf,uint length); bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length); bool is_update_query(enum enum_sql_command command); @@ -1114,7 +1112,7 @@ void init_status_vars(); void free_status_vars(); /* information schema */ -extern LEX_STRING information_schema_name; +extern LEX_STRING INFORMATION_SCHEMA_NAME; extern const LEX_STRING partition_keywords[]; LEX_STRING *make_lex_string(THD *thd, LEX_STRING *lex_str, const char* str, uint length, @@ -1133,7 +1131,7 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond); bool get_schema_tables_result(JOIN *join, enum enum_schema_table_state executed_place); #define is_schema_db(X) \ - !my_strcasecmp(system_charset_info, information_schema_name.str, (X)) + !my_strcasecmp(system_charset_info, INFORMATION_SCHEMA_NAME.str, (X)) /* sql_prepare.cc */ diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 041a7fb67f6..f4b940af898 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -818,7 +818,7 @@ my_real_read(NET *net, ulong *complen) { my_bool interrupted = vio_should_retry(net->vio); - DBUG_PRINT("info",("vio_read returned %ld, errno: %d", + DBUG_PRINT("info",("vio_read returned %ld errno: %d", length, vio_errno(net->vio))); #if !defined(__WIN__) || defined(MYSQL_SERVER) /* diff --git a/sql/set_var.cc b/sql/set_var.cc index fef6fccfd06..b8459c33bc2 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -3086,12 +3086,14 @@ static bool set_option_autocommit(THD *thd, set_var *var) thd->options&= ~(ulonglong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE | OPTION_KEEP_LOG); + thd->no_trans_update.all= FALSE; thd->server_status|= SERVER_STATUS_AUTOCOMMIT; if (ha_commit(thd)) return 1; } else { + thd->no_trans_update.all= FALSE; thd->options&= ~(ulonglong) (OPTION_STATUS_NO_TRANS_UPDATE); thd->server_status&= ~SERVER_STATUS_AUTOCOMMIT; } diff --git a/sql/sp.cc b/sql/sp.cc index aa6d40f5fc0..3991271abc3 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -391,14 +391,14 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, { sp_head *sp= newlex.sphead; - if (dbchanged && (ret= mysql_change_db(thd, old_db.str, 1))) + if (dbchanged && (ret= mysql_change_db(thd, &old_db, TRUE))) goto end; delete sp; ret= SP_PARSE_ERROR; } else { - if (dbchanged && (ret= mysql_change_db(thd, old_db.str, 1))) + if (dbchanged && (ret= mysql_change_db(thd, &old_db, TRUE))) goto end; *sphp= newlex.sphead; (*sphp)->set_definer(&definer_user_name, &definer_host_name); @@ -1863,7 +1863,7 @@ sp_use_new_db(THD *thd, LEX_STRING new_db, LEX_STRING *old_db, DBUG_RETURN(0); } - ret= mysql_change_db(thd, new_db.str, no_access_check); + ret= mysql_change_db(thd, &new_db, no_access_check); *dbchangedp= ret == 0; DBUG_RETURN(ret); diff --git a/sql/sp_head.cc b/sql/sp_head.cc index f5e32847fb0..b406a2d704a 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -349,13 +349,13 @@ sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr) enum_check_fields save_count_cuted_fields= thd->count_cuted_fields; bool save_abort_on_warning= thd->abort_on_warning; - bool save_no_trans_update= thd->no_trans_update; + bool save_no_trans_update_stmt= thd->no_trans_update.stmt; thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL; thd->abort_on_warning= thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES); - thd->no_trans_update= 0; + thd->no_trans_update.stmt= FALSE; /* Save the value in the field. Convert the value if needed. */ @@ -363,7 +363,7 @@ sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr) thd->count_cuted_fields= save_count_cuted_fields; thd->abort_on_warning= save_abort_on_warning; - thd->no_trans_update= save_no_trans_update; + thd->no_trans_update.stmt= save_no_trans_update_stmt; if (thd->net.report_error) { @@ -1171,7 +1171,7 @@ sp_head::execute(THD *thd) (It would generate an error from mysql_change_db() when old_db=="") */ if (! thd->killed) - err_status|= mysql_change_db(thd, old_db.str, 1); + err_status|= mysql_change_db(thd, &old_db, TRUE); } m_flags&= ~IS_INVOKED; DBUG_PRINT("info", diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index aaa88071173..ba1ec66fb02 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -4052,6 +4052,26 @@ err2: } +static bool check_grant_db_routine(THD *thd, const char *db, HASH *hash) +{ + Security_context *sctx= thd->security_ctx; + + for (uint idx= 0; idx < hash->records; ++idx) + { + GRANT_NAME *item= (GRANT_NAME*) hash_element(hash, idx); + + if (strcmp(item->user, sctx->priv_user) == 0 && + strcmp(item->db, db) == 0 && + compare_hostname(&item->host, sctx->host, sctx->ip)) + { + return FALSE; + } + } + + return TRUE; +} + + /* Check if a user has the right to access a database Access is accepted if he has a grant for any table/routine in the database @@ -4063,9 +4083,10 @@ bool check_grant_db(THD *thd,const char *db) Security_context *sctx= thd->security_ctx; char helping [NAME_LEN+USERNAME_LENGTH+2]; uint len; - bool error= 1; + bool error= TRUE; len= (uint) (strmov(strmov(helping, sctx->priv_user) + 1, db) - helping) + 1; + rw_rdlock(&LOCK_grant); for (uint idx=0 ; idx < column_priv_hash.records ; idx++) @@ -4076,11 +4097,17 @@ bool check_grant_db(THD *thd,const char *db) !memcmp(grant_table->hash_key,helping,len) && compare_hostname(&grant_table->host, sctx->host, sctx->ip)) { - error=0; // Found match + error= FALSE; /* Found match. */ break; } } + + if (error) + error= check_grant_db_routine(thd, db, &proc_priv_hash) && + check_grant_db_routine(thd, db, &func_priv_hash); + rw_unlock(&LOCK_grant); + return error; } diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 89b7a25033f..8d8838d4585 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -377,7 +377,7 @@ inline Query_cache_block * Query_cache_block_table::block() void Query_cache_block::init(ulong block_length) { DBUG_ENTER("Query_cache_block::init"); - DBUG_PRINT("qcache", ("init block 0x%lx length: %lu", (ulong) this, + DBUG_PRINT("qcache", ("init block: 0x%lx length: %lu", (ulong) this, block_length)); length = block_length; used = 0; @@ -3685,7 +3685,7 @@ void Query_cache::queries_dump() Query_cache_query_flags flags; memcpy(&flags, str+len, QUERY_CACHE_FLAGS_SIZE); str[len]= 0; // make zero ending DB name - DBUG_PRINT("qcache", ("F:%u C:%u L:%lu T:'%s' (%u) '%s' '%s'", + DBUG_PRINT("qcache", ("F: %u C: %u L: %lu T: '%s' (%u) '%s' '%s'", flags.client_long_flag, flags.character_set_client_num, (ulong)flags.limit, @@ -4008,7 +4008,7 @@ my_bool Query_cache::check_integrity(bool locked) } while (block != bins[i].free_blocks); if (count != bins[i].number) { - DBUG_PRINT("error", ("bins[%d].number = %d, but bin have %d blocks", + DBUG_PRINT("error", ("bins[%d].number= %d, but bin have %d blocks", i, bins[i].number, count)); result = 1; } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index d8371bef446..b2114f1f965 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -830,7 +830,8 @@ void THD::add_changed_table(const char *key, long key_length) { list_include(prev_changed, curr, changed_table_dup(key, key_length)); DBUG_PRINT("info", - ("key_length %ld %u", key_length, (*prev_changed)->key_length)); + ("key_length: %ld %u", key_length, + (*prev_changed)->key_length)); DBUG_VOID_RETURN; } else if (cmp == 0) @@ -840,7 +841,7 @@ void THD::add_changed_table(const char *key, long key_length) { list_include(prev_changed, curr, changed_table_dup(key, key_length)); DBUG_PRINT("info", - ("key_length %ld %u", key_length, + ("key_length: %ld %u", key_length, (*prev_changed)->key_length)); DBUG_VOID_RETURN; } @@ -852,7 +853,7 @@ void THD::add_changed_table(const char *key, long key_length) } } *prev_changed = changed_table_dup(key, key_length); - DBUG_PRINT("info", ("key_length %ld %u", key_length, + DBUG_PRINT("info", ("key_length: %ld %u", key_length, (*prev_changed)->key_length)); DBUG_VOID_RETURN; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 6b79917f772..a308c2bfa84 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1356,7 +1356,11 @@ public: bool charset_is_system_charset, charset_is_collation_connection; bool charset_is_character_set_filesystem; bool enable_slow_log; /* enable slow log for current statement */ - bool no_trans_update, abort_on_warning; + struct { + bool all:1; + bool stmt:1; + } no_trans_update; + bool abort_on_warning; bool got_warning; /* Set on call to push_warning() */ bool no_warnings_for_error; /* no warnings on call to my_error() */ /* set during loop of derived table processing */ @@ -1587,7 +1591,7 @@ public: inline bool really_abort_on_warning() { return (abort_on_warning && - (!no_trans_update || + (!no_trans_update.stmt || (variables.sql_mode & MODE_STRICT_ALL_TABLES))); } void set_status_var_init(); diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 4fd35b7e6e8..4e96a987d99 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -577,7 +577,7 @@ bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, DBUG_ENTER("mysql_create_db"); /* do not create 'information_schema' db */ - if (!my_strcasecmp(system_charset_info, db, information_schema_name.str)) + if (!my_strcasecmp(system_charset_info, db, INFORMATION_SCHEMA_NAME.str)) { my_error(ER_DB_CREATE_EXISTS, MYF(0), db); DBUG_RETURN(-1); @@ -1256,155 +1256,253 @@ err: } -/* - Change the current database. +/** + @brief Internal implementation: switch current database to a valid one. - SYNOPSIS - mysql_change_db() - thd thread handle - name database name - no_access_check if TRUE, don't do access check. In this - case name may be "" + @param thd Thread context. + @param new_db_name Name of the database to switch to. The function will + take ownership of the name (the caller must not free + the allocated memory). If the name is NULL, we're + going to switch to NULL db. + @param new_db_access Privileges of the new database. + @param new_db_charset Character set of the new database. +*/ - DESCRIPTION - Check that the database name corresponds to a valid and - existent database, check access rights (unless called with - no_access_check), and set the current database. This function - is called to change the current database upon user request - (COM_CHANGE_DB command) or temporarily, to execute a stored - routine. +static void mysql_change_db_impl(THD *thd, + LEX_STRING *new_db_name, + ulong new_db_access, + CHARSET_INFO *new_db_charset) +{ + /* 1. Change current database in THD. */ - NOTES - This function is not the only way to switch the database that - is currently employed. When the replication slave thread - switches the database before executing a query, it calls - thd->set_db directly. However, if the query, in turn, uses - a stored routine, the stored routine will use this function, - even if it's run on the slave. - - This function allocates the name of the database on the system - heap: this is necessary to be able to uniformly change the - database from any module of the server. Up to 5.0 different - modules were using different memory to store the name of the - database, and this led to memory corruption: a stack pointer - set by Stored Procedures was used by replication after the - stack address was long gone. - - This function does not send anything, including error - messages, to the client. If that should be sent to the client, - call net_send_error after this function. + if (new_db_name == NULL) + { + /* + THD::set_db() does all the job -- it frees previous database name and + sets the new one. + */ - RETURN VALUES - 0 OK - 1 error + thd->set_db(NULL, 0); + } + else if (new_db_name == &INFORMATION_SCHEMA_NAME) + { + /* + Here we must use THD::set_db(), because we want to copy + INFORMATION_SCHEMA_NAME constant. + */ + + thd->set_db(INFORMATION_SCHEMA_NAME.str, INFORMATION_SCHEMA_NAME.length); + } + else + { + /* + Here we already have a copy of database name to be used in THD. So, + we just call THD::reset_db(). Since THD::reset_db() does not releases + the previous database name, we should do it explicitly. + */ + + x_free(thd->db); + + thd->reset_db(new_db_name->str, new_db_name->length); + } + + /* 2. Update security context. */ + +#ifndef NO_EMBEDDED_ACCESS_CHECKS + thd->security_ctx->db_access= new_db_access; +#endif + + /* 3. Update db-charset environment variables. */ + + thd->db_charset= new_db_charset; + thd->variables.collation_database= new_db_charset; +} + + +/** + @brief Change the current database. + + @param thd thread handle + @param name database name + @param force_switch if this flag is set (TRUE), mysql_change_db() will + switch to NULL db if the specified database is not + available anymore. Corresponding warning will be + thrown in this case. This flag is used to change + database in stored-routine-execution code. + + @details Check that the database name corresponds to a valid and existent + database, check access rights (unless called with no_access_check), and + set the current database. This function is called to change the current + database upon user request (COM_CHANGE_DB command) or temporarily, to + execute a stored routine. + + This function is not the only way to switch the database that is + currently employed. When the replication slave thread switches the + database before executing a query, it calls thd->set_db directly. + However, if the query, in turn, uses a stored routine, the stored routine + will use this function, even if it's run on the slave. + + This function allocates the name of the database on the system heap: this + is necessary to be able to uniformly change the database from any module + of the server. Up to 5.0 different modules were using different memory to + store the name of the database, and this led to memory corruption: + a stack pointer set by Stored Procedures was used by replication after + the stack address was long gone. + + @return Operation status + @retval FALSE Success + @retval TRUE Error */ -bool mysql_change_db(THD *thd, const char *name, bool no_access_check) +bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch) { - LEX_STRING db_name; - bool system_db= 0; -#ifndef NO_EMBEDDED_ACCESS_CHECKS - ulong db_access; + LEX_STRING new_db_file_name; + Security_context *sctx= thd->security_ctx; - LINT_INIT(db_access); -#endif + ulong db_access= sctx->db_access; + DBUG_ENTER("mysql_change_db"); - DBUG_PRINT("enter",("name: '%s'",name)); + DBUG_PRINT("enter",("name: '%s'", new_db_name->str)); - if (name == NULL || name[0] == '\0' && no_access_check == FALSE) + if (new_db_name == NULL || + new_db_name->length == 0) { - my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0)); - DBUG_RETURN(1); /* purecov: inspected */ + if (force_switch) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR)); + + /* Change db to NULL. */ + + mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server); + + DBUG_RETURN(FALSE); + } + else + { + my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0)); + + DBUG_RETURN(TRUE); + } } - else if (name[0] == '\0') + + if (my_strcasecmp(system_charset_info, new_db_name->str, + INFORMATION_SCHEMA_NAME.str) == 0) { - /* Called from SP to restore the original database, which was NULL */ - DBUG_ASSERT(no_access_check); - system_db= 1; - db_name.str= NULL; - db_name.length= 0; - goto end; + /* Switch database to INFORMATION_SCHEMA. */ + + mysql_change_db_impl(thd, &INFORMATION_SCHEMA_NAME, SELECT_ACL, + system_charset_info); + + DBUG_RETURN(FALSE); } + /* Now we need to make a copy because check_db_name requires a - non-constant argument. TODO: fix check_db_name. + non-constant argument. Actually, it takes database file name. + + TODO: fix check_db_name(). */ - if ((db_name.str= my_strdup(name, MYF(MY_WME))) == NULL) - DBUG_RETURN(1); /* the error is set */ - db_name.length= strlen(db_name.str); - if (check_db_name(&db_name)) - { - my_error(ER_WRONG_DB_NAME, MYF(0), db_name.str); - my_free(db_name.str, MYF(0)); - DBUG_RETURN(1); - } - DBUG_PRINT("info",("Use database: %s", db_name.str)); - if (!my_strcasecmp(system_charset_info, db_name.str, - information_schema_name.str)) + + new_db_file_name.str= my_strndup(new_db_name->str, new_db_name->length, + MYF(MY_WME)); + new_db_file_name.length= new_db_name->length; + + if (new_db_file_name.str == NULL) + DBUG_RETURN(TRUE); /* the error is set */ + + /* + NOTE: if check_db_name() fails, we should throw an error in any case, + even if we are called from sp_head::execute(). + + It's next to impossible however to get this error when we are called + from sp_head::execute(). But let's switch database to NULL in this case + to be sure. + */ + + if (check_db_name(new_db_file_name.str)) { - system_db= 1; -#ifndef NO_EMBEDDED_ACCESS_CHECKS - db_access= SELECT_ACL; -#endif - goto end; + my_error(ER_WRONG_DB_NAME, MYF(0), new_db_file_name.str); + my_free(new_db_file_name.str, MYF(0)); + + if (force_switch) + { + /* Change db to NULL. */ + mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server); + } + DBUG_RETURN(TRUE); } + DBUG_PRINT("info",("Use database: %s", new_db_file_name.str)); + #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (!no_access_check) + if (!force_switch) /* FIXME: this is BUG#27337. */ { - if (test_all_bits(sctx->master_access, DB_ACLS)) - db_access=DB_ACLS; - else - db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, - db_name.str, 0) | - sctx->master_access); - if (!(db_access & DB_ACLS) && (!grant_option || - check_grant_db(thd, db_name.str))) + db_access= (test_all_bits(sctx->master_access, DB_ACLS) ? + DB_ACLS : + acl_get(sctx->host, + sctx->ip, + sctx->priv_user, + new_db_file_name.str, + FALSE) | sctx->master_access); + + if (!force_switch && + !(db_access & DB_ACLS) && + (!grant_option || check_grant_db(thd, new_db_file_name.str))) { my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), sctx->priv_user, sctx->priv_host, - db_name.str); - general_log_print(thd, COM_INIT_DB, ER(ER_DBACCESS_DENIED_ERROR), - sctx->priv_user, sctx->priv_host, db_name.str); - my_free(db_name.str, MYF(0)); - DBUG_RETURN(1); + new_db_file_name.str); + mysql_log.write(thd, COM_INIT_DB, ER(ER_DBACCESS_DENIED_ERROR), + sctx->priv_user, sctx->priv_host, new_db_file_name.str); + my_free(new_db_file_name.str, MYF(0)); + DBUG_RETURN(TRUE); } } #endif - if (check_db_dir_existence(db_name.str)) + if (check_db_dir_existence(new_db_file_name.str)) { - my_error(ER_BAD_DB_ERROR, MYF(0), db_name.str); - my_free(db_name.str, MYF(0)); - DBUG_RETURN(1); - } + if (force_switch) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_BAD_DB_ERROR, ER(ER_BAD_DB_ERROR), + new_db_file_name.str); -end: - x_free(thd->db); - DBUG_ASSERT(db_name.str == NULL || db_name.str[0] != '\0'); - thd->reset_db(db_name.str, db_name.length); // THD::~THD will free this -#ifndef NO_EMBEDDED_ACCESS_CHECKS - if (!no_access_check) - sctx->db_access= db_access; -#endif - if (system_db) - { - thd->db_charset= system_charset_info; - thd->variables.collation_database= system_charset_info; + my_free(new_db_file_name.str, MYF(0)); + + /* Change db to NULL. */ + + mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server); + + DBUG_RETURN(FALSE); + } + else + { + my_error(ER_BAD_DB_ERROR, MYF(0), new_db_file_name.str); + my_free(new_db_file_name.str, MYF(0)); + DBUG_RETURN(TRUE); + } } - else + + /* + NOTE: in mysql_change_db_impl() new_db_file_name is assigned to THD + attributes and will be freed in THD::~THD(). + */ + { - HA_CREATE_INFO create; + HA_CREATE_INFO db_options; - load_db_opt_by_name(thd, db_name.str, &create); + load_db_opt_by_name(thd, new_db_name->str, &db_options); - thd->db_charset= create.default_table_charset ? - create.default_table_charset : - thd->variables.collation_server; - thd->variables.collation_database= thd->db_charset; + mysql_change_db_impl(thd, &new_db_file_name, db_access, + db_options.default_table_charset ? + db_options.default_table_charset : + thd->variables.collation_server); } - DBUG_RETURN(0); + + DBUG_RETURN(FALSE); } @@ -1581,8 +1679,8 @@ bool mysql_rename_db(THD *thd, LEX_STRING *old_db, LEX_STRING *new_db) Failed to move all tables from the old database to the new one. In the best case mysql_rename_tables() moved all tables back to the old database. In the worst case mysql_rename_tables() moved some tables - to the new database, then failed, then started to move the tables back, and - then failed again. In this situation we have some tables in the + to the new database, then failed, then started to move the tables back, + and then failed again. In this situation we have some tables in the old database and some tables in the new database. Let's delete the option file, and then the new database directory. If some tables were left in the new directory, rmdir() will fail. @@ -1718,6 +1816,8 @@ exit: DBUG_RETURN(error); } + + /* Check if there is directory for the database name. diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 0ff5c4e5b50..ab491c732c3 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -335,7 +335,7 @@ cleanup: } } if (!transactional_table) - thd->options|=OPTION_STATUS_NO_TRANS_UPDATE; + thd->no_trans_update.all= TRUE; } free_underlaid_joins(thd, select_lex); if (transactional_table) @@ -827,7 +827,7 @@ bool multi_delete::send_eof() } } if (!transactional_tables) - thd->options|=OPTION_STATUS_NO_TRANS_UPDATE; + thd->no_trans_update.all= TRUE; } /* Commit or rollback the current SQL statement */ if (transactional_tables) diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 773383c2c2d..4eff7e4edeb 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -570,7 +570,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, if (lock_type != TL_WRITE_DELAYED && !thd->prelocked_mode) table->file->ha_start_bulk_insert(values_list.elements); - thd->no_trans_update= 0; + thd->no_trans_update.stmt= FALSE; thd->abort_on_warning= (!ignore && (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES))); @@ -1119,7 +1119,7 @@ static int last_uniq_key(TABLE *table,uint keynr) then both on update triggers will work instead. Similarly both on delete triggers will be invoked if we will delete conflicting records. - Sets thd->no_trans_update if table which is updated didn't have + Sets thd->no_trans_update.stmt to TRUE if table which is updated didn't have transactions. RETURN VALUE @@ -1363,7 +1363,7 @@ ok_or_after_trg_err: if (key) my_safe_afree(key,table->s->max_unique_length,MAX_KEY_LENGTH); if (!table->file->has_transactions()) - thd->no_trans_update= 1; + thd->no_trans_update.stmt= TRUE; DBUG_RETURN(trg_error); err: @@ -2818,7 +2818,7 @@ void select_insert::send_error(uint errcode,const char *err) table->file->has_transactions(), FALSE); if (!thd->current_stmt_binlog_row_based && !table->s->tmp_table && !can_rollback_data()) - thd->options|= OPTION_STATUS_NO_TRANS_UPDATE; + thd->no_trans_update.all= TRUE; query_cache_invalidate3(thd, table, 1); } } @@ -2859,7 +2859,7 @@ bool select_insert::send_eof() */ if (!trans_table && (!table->s->tmp_table || !thd->current_stmt_binlog_row_based)) - thd->options|= OPTION_STATUS_NO_TRANS_UPDATE; + thd->no_trans_update.all= TRUE; } /* @@ -3166,7 +3166,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE); if (!thd->prelocked_mode) table->file->ha_start_bulk_insert((ha_rows) 0); - thd->no_trans_update= 0; + thd->no_trans_update.stmt= FALSE; thd->abort_on_warning= (!info.ignore && (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | diff --git a/sql/sql_load.cc b/sql/sql_load.cc index cf356a4b336..36b648e3aaf 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -376,7 +376,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, table->file->ha_start_bulk_insert((ha_rows) 0); table->copy_blobs=1; - thd->no_trans_update= 0; + thd->no_trans_update.stmt= FALSE; thd->abort_on_warning= (!ignore && (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | @@ -470,7 +470,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, (ulong) (info.records - info.copied), (ulong) thd->cuted_fields); if (!transactional_table) - thd->options|=OPTION_STATUS_NO_TRANS_UPDATE; + thd->no_trans_update.all= TRUE; #ifndef EMBEDDED_LIBRARY if (mysql_bin_log.is_open()) { @@ -551,7 +551,7 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, Item_field *sql_field; TABLE *table= table_list->table; ulonglong id; - bool no_trans_update; + bool no_trans_update_stmt; DBUG_ENTER("read_fixed_length"); id= 0; @@ -579,7 +579,7 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, #ifdef HAVE_purify read_info.row_end[0]=0; #endif - no_trans_update= !table->file->has_transactions(); + no_trans_update_stmt= !table->file->has_transactions(); restore_record(table, s->default_values); /* @@ -647,7 +647,7 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, if (write_record(thd, table, &info)) DBUG_RETURN(1); - thd->no_trans_update= no_trans_update; + thd->no_trans_update.stmt= no_trans_update_stmt; /* We don't need to reset auto-increment field since we are restoring @@ -682,12 +682,12 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, TABLE *table= table_list->table; uint enclosed_length; ulonglong id; - bool no_trans_update; + bool no_trans_update_stmt; DBUG_ENTER("read_sep_field"); enclosed_length=enclosed.length(); id= 0; - no_trans_update= !table->file->has_transactions(); + no_trans_update_stmt= !table->file->has_transactions(); for (;;it.rewind()) { @@ -823,7 +823,7 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, We don't need to reset auto-increment field since we are restoring its default value at the beginning of each loop iteration. */ - thd->no_trans_update= no_trans_update; + thd->no_trans_update.stmt= no_trans_update_stmt; if (read_info.next_line()) // Skip to next line break; if (read_info.line_cuted) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 7e7e814a833..ff7e06e1875 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -119,8 +119,8 @@ bool end_active_trans(THD *thd) if (ha_commit(thd)) error=1; } - thd->options&= ~(OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE | - OPTION_KEEP_LOG); + thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG); + thd->no_trans_update.all= FALSE; DBUG_RETURN(error); } @@ -546,8 +546,8 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion) */ thd->server_status&= ~SERVER_STATUS_IN_TRANS; res= ha_commit(thd); - thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE | - OPTION_KEEP_LOG); + thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_KEEP_LOG); + thd->no_trans_update.all= FALSE; break; case COMMIT_RELEASE: do_release= 1; /* fall through */ @@ -564,8 +564,8 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion) thd->server_status&= ~SERVER_STATUS_IN_TRANS; if (ha_rollback(thd)) res= -1; - thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE | - OPTION_KEEP_LOG); + thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_KEEP_LOG); + thd->no_trans_update.all= FALSE; if (!res && (completion == ROLLBACK_AND_CHAIN)) res= begin_trans(thd); break; @@ -961,7 +961,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, packet= arg_end + 1; if (!my_strcasecmp(system_charset_info, table_list.db, - information_schema_name.str)) + INFORMATION_SCHEMA_NAME.str)) { ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, table_list.alias); if (schema_table) @@ -2814,7 +2814,7 @@ end_with_restore_list: we silently add IF EXISTS if TEMPORARY was used. */ if (thd->slave_thread) - lex->drop_if_exists= 1; + lex->drop_if_exists= 1; /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */ thd->options|= OPTION_KEEP_LOG; @@ -2871,9 +2871,14 @@ end_with_restore_list: } #endif case SQLCOM_CHANGE_DB: - if (!mysql_change_db(thd,select_lex->db,FALSE)) + { + LEX_STRING db_str= { (char *) select_lex->db, strlen(select_lex->db) }; + + if (!mysql_change_db(thd, &db_str, FALSE)) send_ok(thd); + break; + } case SQLCOM_LOAD: { @@ -3536,9 +3541,8 @@ end_with_restore_list: res= TRUE; // cannot happen else { - if ((thd->options & - (OPTION_STATUS_NO_TRANS_UPDATE | OPTION_KEEP_LOG)) && - !thd->slave_thread) + if ((thd->options & OPTION_KEEP_LOG) && + thd->no_trans_update.all && !thd->slave_thread) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARNING_NOT_COMPLETE_ROLLBACK, ER(ER_WARNING_NOT_COMPLETE_ROLLBACK)); @@ -4110,9 +4114,8 @@ create_sp_error: thd->transaction.xid_state.xa_state=XA_ACTIVE; thd->transaction.xid_state.xid.set(thd->lex->xid); xid_cache_insert(&thd->transaction.xid_state); - thd->options= ((thd->options & ~(OPTION_STATUS_NO_TRANS_UPDATE | - OPTION_KEEP_LOG)) | - OPTION_BEGIN); + thd->options= ((thd->options & ~(OPTION_KEEP_LOG)) | OPTION_BEGIN); + thd->no_trans_update.all= FALSE; thd->server_status|= SERVER_STATUS_IN_TRANS; send_ok(thd); break; @@ -4236,8 +4239,8 @@ create_sp_error: my_error(ER_XAER_RMERR, MYF(0)); else send_ok(thd); - thd->options&= ~(OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE | - OPTION_KEEP_LOG); + thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG); + thd->no_trans_update.all= FALSE; thd->server_status&= ~SERVER_STATUS_IN_TRANS; xid_cache_delete(&thd->transaction.xid_state); thd->transaction.xid_state.xa_state=XA_NOTR; @@ -4732,7 +4735,7 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, if (!no_errors) my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), sctx->priv_user, sctx->priv_host, - information_schema_name.str); + INFORMATION_SCHEMA_NAME.str); return TRUE; } /* @@ -5519,7 +5522,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES); ptr->derived= table->sel; if (!ptr->derived && !my_strcasecmp(system_charset_info, ptr->db, - information_schema_name.str)) + INFORMATION_SCHEMA_NAME.str)) { ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, ptr->table_name); if (!schema_table || @@ -5527,7 +5530,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0)) { my_error(ER_UNKNOWN_TABLE, MYF(0), - ptr->table_name, information_schema_name.str); + ptr->table_name, INFORMATION_SCHEMA_NAME.str); DBUG_RETURN(0); } ptr->schema_table_name= ptr->table_name; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 37a6f68cfe8..7af891ec2d6 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1670,7 +1670,7 @@ static bool check_prepared_statement(Prepared_statement *stmt, enum enum_sql_command sql_command= lex->sql_command; int res= 0; DBUG_ENTER("check_prepared_statement"); - DBUG_PRINT("enter",("command: %d, param_count: %u", + DBUG_PRINT("enter",("command: %d param_count: %u", sql_command, stmt->param_count)); lex->first_lists_tables_same(); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 5558b02ad78..3ff24112f5e 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -714,9 +714,9 @@ bool mysqld_show_create_db(THD *thd, char *dbname, } #endif if (!my_strcasecmp(system_charset_info, dbname, - information_schema_name.str)) + INFORMATION_SCHEMA_NAME.str)) { - dbname= information_schema_name.str; + dbname= INFORMATION_SCHEMA_NAME.str; create.default_table_charset= system_charset_info; } else @@ -2196,7 +2196,7 @@ LEX_STRING *make_lex_string(THD *thd, LEX_STRING *lex_str, /* INFORMATION_SCHEMA name */ -LEX_STRING information_schema_name= { C_STRING_WITH_LEN("information_schema")}; +LEX_STRING INFORMATION_SCHEMA_NAME= { C_STRING_WITH_LEN("information_schema")}; /* This is only used internally, but we need it here as a forward reference */ extern ST_SCHEMA_TABLE schema_tables[]; @@ -2412,11 +2412,11 @@ int make_db_list(THD *thd, List<char> *files, */ if (!idx_field_vals->db_value || !wild_case_compare(system_charset_info, - information_schema_name.str, + INFORMATION_SCHEMA_NAME.str, idx_field_vals->db_value)) { *with_i_schema= 1; - if (files->push_back(thd->strdup(information_schema_name.str))) + if (files->push_back(thd->strdup(INFORMATION_SCHEMA_NAME.str))) return 1; } return (find_files(thd, files, NullS, mysql_data_home, @@ -2430,11 +2430,11 @@ int make_db_list(THD *thd, List<char> *files, */ if (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) { - if (!my_strcasecmp(system_charset_info, information_schema_name.str, + if (!my_strcasecmp(system_charset_info, INFORMATION_SCHEMA_NAME.str, idx_field_vals->db_value)) { *with_i_schema= 1; - return files->push_back(thd->strdup(information_schema_name.str)); + return files->push_back(thd->strdup(INFORMATION_SCHEMA_NAME.str)); } return files->push_back(thd->strdup(idx_field_vals->db_value)); } @@ -2443,7 +2443,7 @@ int make_db_list(THD *thd, List<char> *files, Create list of existing databases. It is used in case of select from information schema table */ - if (files->push_back(thd->strdup(information_schema_name.str))) + if (files->push_back(thd->strdup(INFORMATION_SCHEMA_NAME.str))) return 1; *with_i_schema= 1; return (find_files(thd, files, NullS, @@ -5036,8 +5036,8 @@ int make_schema_select(THD *thd, SELECT_LEX *sel, We have to make non const db_name & table_name because of lower_case_table_names */ - make_lex_string(thd, &db, information_schema_name.str, - information_schema_name.length, 0); + make_lex_string(thd, &db, INFORMATION_SCHEMA_NAME.str, + INFORMATION_SCHEMA_NAME.length, 0); make_lex_string(thd, &table, schema_table->table_name, strlen(schema_table->table_name), 0); if (schema_table->old_format(thd, schema_table) || /* Handle old syntax */ diff --git a/sql/sql_table.cc b/sql/sql_table.cc index bb3f293941e..d1dcecfe6a1 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -6751,7 +6751,7 @@ copy_data_between_tables(TABLE *from,TABLE *to, alter_table_manage_keys(to, from->file->indexes_are_disabled(), keys_onoff); /* We can abort alter table for any table type */ - thd->no_trans_update= 0; + thd->no_trans_update.stmt= FALSE; thd->abort_on_warning= !ignore && test(thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 0b4632edfbe..f438e04e6c9 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -447,7 +447,7 @@ int mysql_update(THD *thd, thd->proc_info="Updating"; transactional_table= table->file->has_transactions(); - thd->no_trans_update= 0; + thd->no_trans_update.stmt= FALSE; thd->abort_on_warning= test(!ignore && (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | @@ -474,7 +474,7 @@ int mysql_update(THD *thd, if (fill_record_n_invoke_before_triggers(thd, fields, values, 0, table->triggers, TRG_EVENT_UPDATE)) - break; /* purecov: inspected */ + break; /* purecov: inspected */ found++; @@ -661,11 +661,11 @@ int mysql_update(THD *thd, transactional_table, FALSE) && transactional_table) { - error=1; // Rollback update + error=1; // Rollback update } } if (!transactional_table) - thd->options|=OPTION_STATUS_NO_TRANS_UPDATE; + thd->no_trans_update.all= TRUE; } free_underlaid_joins(thd, select_lex); if (transactional_table) @@ -1030,7 +1030,7 @@ bool mysql_multi_update(THD *thd, handle_duplicates, ignore))) DBUG_RETURN(TRUE); - thd->no_trans_update= 0; + thd->no_trans_update.stmt= FALSE; thd->abort_on_warning= test(thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)); @@ -1344,7 +1344,7 @@ multi_update::~multi_update() delete [] copy_field; thd->count_cuted_fields= CHECK_FIELD_IGNORE; // Restore this setting if (!trans_safe) - thd->options|=OPTION_STATUS_NO_TRANS_UPDATE; + thd->no_trans_update.all= TRUE; } @@ -1405,40 +1405,40 @@ bool multi_update::send_data(List<Item> ¬_used_values) else if (error == VIEW_CHECK_ERROR) DBUG_RETURN(1); } - if (!updated++) - { - /* - Inform the main table that we are going to update the table even - while we may be scanning it. This will flush the read cache - if it's used. - */ - main_table->file->extra(HA_EXTRA_PREPARE_FOR_UPDATE); - } - if ((error=table->file->ha_update_row(table->record[1], - table->record[0]))) - { - updated--; + if (!updated++) + { + /* + Inform the main table that we are going to update the table even + while we may be scanning it. This will flush the read cache + if it's used. + */ + main_table->file->extra(HA_EXTRA_PREPARE_FOR_UPDATE); + } + if ((error=table->file->ha_update_row(table->record[1], + table->record[0]))) + { + updated--; if (!ignore || table->file->is_fatal_error(error, HA_CHECK_DUP_KEY)) - { + { /* If (ignore && error == is ignorable) we don't have to do anything; otherwise... */ if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY)) thd->fatal_error(); /* Other handler errors are fatal */ - table->file->print_error(error,MYF(0)); - DBUG_RETURN(1); - } - } + table->file->print_error(error,MYF(0)); + DBUG_RETURN(1); + } + } else { if (!table->file->has_transactions()) - thd->no_trans_update= 1; + thd->no_trans_update.stmt= TRUE; if (table->triggers && table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, TRG_ACTION_AFTER, TRUE)) - DBUG_RETURN(1); + DBUG_RETURN(1); } } } @@ -1674,7 +1674,7 @@ bool multi_update::send_eof() } } if (!transactional_tables) - thd->options|=OPTION_STATUS_NO_TRANS_UPDATE; + thd->no_trans_update.all= TRUE; } if (transactional_tables) diff --git a/sql/sql_view.cc b/sql/sql_view.cc index ee0e5e5a386..4f6084e79fd 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -496,35 +496,46 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, /* Compare/check grants on view with grants of underlying tables */ + + fill_effective_table_privileges(thd, &view->grant, view->db, + view->table_name); + + { + Item *report_item= NULL; + uint final_priv= VIEW_ANY_ACL; + for (sl= select_lex; sl; sl= sl->next_select()) { DBUG_ASSERT(view->db); /* Must be set in the parser */ List_iterator_fast<Item> it(sl->item_list); Item *item; - fill_effective_table_privileges(thd, &view->grant, view->db, - view->table_name); while ((item= it++)) { - Item_field *fld; + Item_field *fld= item->filed_for_view_update(); uint priv= (get_column_grant(thd, &view->grant, view->db, view->table_name, item->name) & VIEW_ANY_ACL); - if ((fld= item->filed_for_view_update())) + + if (fld && !fld->field->table->s->tmp_table) { - /* - Do we have more privileges on view field then underlying table field? - */ - if (!fld->field->table->s->tmp_table && (~fld->have_privileges & priv)) + final_priv&= fld->have_privileges; + + if (~fld->have_privileges & priv) + report_item= item; + } + } + } + + if (!final_priv) { - /* VIEW column has more privileges */ + DBUG_ASSERT(report_item); + my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), "create view", thd->security_ctx->priv_user, - thd->security_ctx->priv_host, item->name, + thd->security_ctx->priv_host, report_item->name, view->table_name); res= TRUE; goto err; - } - } } } #endif |