diff --git a/mysql-test/r/func_misc.result b/mysql-test/r/func_misc.result index 1d9b813e68a..5e74e6fa68a 100644 --- a/mysql-test/r/func_misc.result +++ b/mysql-test/r/func_misc.result @@ -51,3 +51,11 @@ select a from t1 where mid(a+0,6,3) = ( mid(20040106123400,6,3) ); a 2004-01-06 12:34:00 drop table t1; +create table t1 as select uuid(), length(uuid()); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `uuid()` varchar(36) character set utf8 NOT NULL default '', + `length(uuid())` int(10) NOT NULL default '0' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; diff --git a/mysql-test/r/sp-security.result b/mysql-test/r/sp-security.result index d7078d5087d..ee72fde7324 100644 --- a/mysql-test/r/sp-security.result +++ b/mysql-test/r/sp-security.result @@ -23,10 +23,10 @@ root@localhost 1 select db(); db() db1_secret -grant execute on db1_secret.stamp to user1@'%'; -grant execute on db1_secret.db to user1@'%'; -grant execute on db1_secret.stamp to ''@'%'; -grant execute on db1_secret.db to ''@'%'; +grant execute on procedure db1_secret.stamp to user1@'%'; +grant execute on function db1_secret.db to user1@'%'; +grant execute on procedure db1_secret.stamp to ''@'%'; +grant execute on function db1_secret.db to ''@'%'; call db1_secret.stamp(2); select db1_secret.db(); db1_secret.db() @@ -105,8 +105,8 @@ select * from t2; s1 0 2 -grant usage on db2.q to user2@localhost with grant option; -grant execute on db2.q to user1@localhost; +grant usage on procedure db2.q to user2@localhost with grant option; +grant execute on procedure db2.q to user1@localhost; use db2; call q(); select * from t2; @@ -117,9 +117,9 @@ s1 alter procedure p modifies sql data; drop procedure p; alter procedure q modifies sql data; -ERROR 42000: alter procedure command denied to user 'user1'@'localhost' for routine 'db2.q' +ERROR 42000: alter routine command denied to user 'user1'@'localhost' for routine 'db2.q' drop procedure q; -ERROR 42000: alter procedure command denied to user 'user1'@'localhost' for routine 'db2.q' +ERROR 42000: alter routine command denied to user 'user1'@'localhost' for routine 'db2.q' use db2; alter procedure q modifies sql data; drop procedure q; @@ -141,52 +141,52 @@ create database sptest; create table t1 ( u varchar(64), i int ); create procedure sptest.p1(i int) insert into test.t1 values (user(), i); grant insert on t1 to usera@localhost; -grant execute on sptest.p1 to usera@localhost; +grant execute on procedure sptest.p1 to usera@localhost; show grants for usera@localhost; Grants for usera@localhost GRANT USAGE ON *.* TO 'usera'@'localhost' GRANT INSERT ON `test`.`t1` TO 'usera'@'localhost' -GRANT EXECUTE ON `sptest`.`p1` TO 'usera'@'localhost' -grant execute on sptest.p1 to userc@localhost with grant option; +GRANT EXECUTE ON PROCEDURE `sptest`.`p1` TO 'usera'@'localhost' +grant execute on procedure sptest.p1 to userc@localhost with grant option; show grants for userc@localhost; Grants for userc@localhost GRANT USAGE ON *.* TO 'userc'@'localhost' -GRANT EXECUTE ON `sptest`.`p1` TO 'userc'@'localhost' WITH GRANT OPTION +GRANT EXECUTE ON PROCEDURE `sptest`.`p1` TO 'userc'@'localhost' WITH GRANT OPTION call sptest.p1(1); -grant execute on sptest.p1 to userb@localhost; +grant execute on procedure sptest.p1 to userb@localhost; ERROR 42000: grant command denied to user 'usera'@'localhost' for routine 'sptest.p1' drop procedure sptest.p1; -ERROR 42000: alter procedure command denied to user 'usera'@'localhost' for routine 'sptest.p1' +ERROR 42000: alter routine command denied to user 'usera'@'localhost' for routine 'sptest.p1' call sptest.p1(2); ERROR 42000: execute command denied to user 'userb'@'localhost' for routine 'sptest.p1' -grant execute on sptest.p1 to userb@localhost; +grant execute on procedure sptest.p1 to userb@localhost; ERROR 42000: execute command denied to user 'userb'@'localhost' for routine 'sptest.p1' drop procedure sptest.p1; -ERROR 42000: alter procedure command denied to user 'userb'@'localhost' for routine 'sptest.p1' +ERROR 42000: alter routine command denied to user 'userb'@'localhost' for routine 'sptest.p1' call sptest.p1(3); -grant execute on sptest.p1 to userb@localhost; +grant execute on procedure sptest.p1 to userb@localhost; drop procedure sptest.p1; -ERROR 42000: alter procedure command denied to user 'userc'@'localhost' for routine 'sptest.p1' +ERROR 42000: alter routine command denied to user 'userc'@'localhost' for routine 'sptest.p1' call sptest.p1(4); -grant execute on sptest.p1 to userb@localhost; +grant execute on procedure sptest.p1 to userb@localhost; ERROR 42000: grant command denied to user 'userb'@'localhost' for routine 'sptest.p1' drop procedure sptest.p1; -ERROR 42000: alter procedure command denied to user 'userb'@'localhost' for routine 'sptest.p1' +ERROR 42000: alter routine command denied to user 'userb'@'localhost' for routine 'sptest.p1' select * from t1; u i usera@localhost 1 userc@localhost 3 userb@localhost 4 -grant all privileges on sptest.p1 to userc@localhost; +grant all privileges on procedure sptest.p1 to userc@localhost; show grants for userc@localhost; Grants for userc@localhost GRANT USAGE ON *.* TO 'userc'@'localhost' -GRANT EXECUTE, ALTER ROUTINE ON `sptest`.`p1` TO 'userc'@'localhost' WITH GRANT OPTION +GRANT EXECUTE, ALTER ROUTINE ON PROCEDURE `sptest`.`p1` TO 'userc'@'localhost' WITH GRANT OPTION show grants for userb@localhost; Grants for userb@localhost GRANT USAGE ON *.* TO 'userb'@'localhost' -GRANT EXECUTE ON `sptest`.`p1` TO 'userb'@'localhost' -revoke all privileges on sptest.p1 from userb@localhost; +GRANT EXECUTE ON PROCEDURE `sptest`.`p1` TO 'userb'@'localhost' +revoke all privileges on procedure sptest.p1 from userb@localhost; show grants for userb@localhost; Grants for userb@localhost GRANT USAGE ON *.* TO 'userb'@'localhost' diff --git a/mysql-test/r/system_mysql_db.result b/mysql-test/r/system_mysql_db.result index f3f019e43ba..159e9d15f29 100644 --- a/mysql-test/r/system_mysql_db.result +++ b/mysql-test/r/system_mysql_db.result @@ -152,10 +152,11 @@ procs_priv CREATE TABLE `procs_priv` ( `Db` char(64) collate utf8_bin NOT NULL default '', `User` char(16) collate utf8_bin NOT NULL default '', `Routine_name` char(64) collate utf8_bin NOT NULL default '', + `Routine_type` enum('FUNCTION','PROCEDURE') collate utf8_bin NOT NULL default 'FUNCTION', `Grantor` char(77) collate utf8_bin NOT NULL default '', - `Timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, `Proc_priv` set('Execute','Alter Routine','Grant') character set utf8 NOT NULL default '', - PRIMARY KEY (`Host`,`Db`,`User`,`Routine_name`), + `Timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, + PRIMARY KEY (`Host`,`Db`,`User`,`Routine_name`,`Routine_type`), KEY `Grantor` (`Grantor`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Procedure privileges' show create table proc; diff --git a/mysql-test/t/func_misc.test b/mysql-test/t/func_misc.test index 89aba7ee583..78ff0907b39 100644 --- a/mysql-test/t/func_misc.test +++ b/mysql-test/t/func_misc.test @@ -38,3 +38,11 @@ select a from t1 where mid(a+0,6,3) = ( mid(20040106123400,6,3) ); drop table t1; +# Test for BUG#9535 +create table t1 as select uuid(), length(uuid()); +show create table t1; +drop table t1; + + + + diff --git a/mysql-test/t/sp-security.test b/mysql-test/t/sp-security.test index 5a8dfc54920..e1d8043ccda 100644 --- a/mysql-test/t/sp-security.test +++ b/mysql-test/t/sp-security.test @@ -43,10 +43,10 @@ call stamp(1); select * from t1; select db(); -grant execute on db1_secret.stamp to user1@'%'; -grant execute on db1_secret.db to user1@'%'; -grant execute on db1_secret.stamp to ''@'%'; -grant execute on db1_secret.db to ''@'%'; +grant execute on procedure db1_secret.stamp to user1@'%'; +grant execute on function db1_secret.db to user1@'%'; +grant execute on procedure db1_secret.stamp to ''@'%'; +grant execute on function db1_secret.db to ''@'%'; connect (con2user1,localhost,user1,,); connect (con3anon,localhost,anon,,); @@ -183,10 +183,10 @@ call q(); select * from t2; connection con1root; -grant usage on db2.q to user2@localhost with grant option; +grant usage on procedure db2.q to user2@localhost with grant option; connection con4user2; -grant execute on db2.q to user1@localhost; +grant execute on procedure db2.q to user1@localhost; connection con2user1; use db2; @@ -245,9 +245,9 @@ create database sptest; create table t1 ( u varchar(64), i int ); create procedure sptest.p1(i int) insert into test.t1 values (user(), i); grant insert on t1 to usera@localhost; -grant execute on sptest.p1 to usera@localhost; +grant execute on procedure sptest.p1 to usera@localhost; show grants for usera@localhost; -grant execute on sptest.p1 to userc@localhost with grant option; +grant execute on procedure sptest.p1 to userc@localhost with grant option; show grants for userc@localhost; connect (con2usera,localhost,usera,,); @@ -257,7 +257,7 @@ connect (con4userc,localhost,userc,,); connection con2usera; call sptest.p1(1); --error 1370 -grant execute on sptest.p1 to userb@localhost; +grant execute on procedure sptest.p1 to userb@localhost; --error 1370 drop procedure sptest.p1; @@ -265,32 +265,32 @@ connection con3userb; --error 1370 call sptest.p1(2); --error 1370 -grant execute on sptest.p1 to userb@localhost; +grant execute on procedure sptest.p1 to userb@localhost; --error 1370 drop procedure sptest.p1; connection con4userc; call sptest.p1(3); -grant execute on sptest.p1 to userb@localhost; +grant execute on procedure sptest.p1 to userb@localhost; --error 1370 drop procedure sptest.p1; connection con3userb; call sptest.p1(4); --error 1370 -grant execute on sptest.p1 to userb@localhost; +grant execute on procedure sptest.p1 to userb@localhost; --error 1370 drop procedure sptest.p1; connection con1root; select * from t1; -grant all privileges on sptest.p1 to userc@localhost; +grant all privileges on procedure sptest.p1 to userc@localhost; show grants for userc@localhost; show grants for userb@localhost; connection con4userc; -revoke all privileges on sptest.p1 from userb@localhost; +revoke all privileges on procedure sptest.p1 from userb@localhost; connection con1root; show grants for userb@localhost; diff --git a/scripts/mysql_create_system_tables.sh b/scripts/mysql_create_system_tables.sh index 0eb14cd5e65..a8f6c02b057 100644 --- a/scripts/mysql_create_system_tables.sh +++ b/scripts/mysql_create_system_tables.sh @@ -255,10 +255,11 @@ then c_pp="$c_pp Db char(64) binary DEFAULT '' NOT NULL," c_pp="$c_pp User char(16) binary DEFAULT '' NOT NULL," c_pp="$c_pp Routine_name char(64) binary DEFAULT '' NOT NULL," + c_pp="$c_pp Routine_type enum('FUNCTION','PROCEDURE') NOT NULL," c_pp="$c_pp Grantor char(77) DEFAULT '' NOT NULL," - c_pp="$c_pp Timestamp timestamp(14)," c_pp="$c_pp Proc_priv set('Execute','Alter Routine','Grant') COLLATE utf8_general_ci DEFAULT '' NOT NULL," - c_pp="$c_pp PRIMARY KEY (Host,Db,User,Routine_name)," + c_pp="$c_pp Timestamp timestamp(14)," + c_pp="$c_pp PRIMARY KEY (Host,Db,User,Routine_name,Routine_type)," c_pp="$c_pp KEY Grantor (Grantor)" c_pp="$c_pp ) engine=MyISAM" c_pp="$c_pp CHARACTER SET utf8 COLLATE utf8_bin" diff --git a/scripts/mysql_fix_privilege_tables.sql b/scripts/mysql_fix_privilege_tables.sql index 209a2424eb9..7956287b6c2 100644 --- a/scripts/mysql_fix_privilege_tables.sql +++ b/scripts/mysql_fix_privilege_tables.sql @@ -67,6 +67,10 @@ ALTER TABLE tables_priv ALTER TABLE procs_priv ENGINE=MyISAM, CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin; ALTER TABLE procs_priv modify Proc_priv set('Execute','Alter Routine','Grant') COLLATE utf8_general_ci DEFAULT '' NOT NULL; +ALTER TABLE procs_priv + add Routine_type enum('FUNCTION','PROCEDURE') COLLATE utf8_general_ci NOT NULL AFTER Routine_name; +ALTER TABLE procs_priv + modify Timestamp timestamp(14) AFTER Proc_priv; CREATE TABLE IF NOT EXISTS columns_priv ( Host char(60) DEFAULT '' NOT NULL, @@ -315,10 +319,11 @@ Host char(60) binary DEFAULT '' NOT NULL, Db char(64) binary DEFAULT '' NOT NULL, User char(16) binary DEFAULT '' NOT NULL, Routine_name char(64) binary DEFAULT '' NOT NULL, +Routine_type enum('FUNCTION','PROCEDURE') NOT NULL, Grantor char(77) DEFAULT '' NOT NULL, -Timestamp timestamp(14), Proc_priv set('Execute','Alter Routine','Grant') COLLATE utf8_general_ci DEFAULT '' NOT NULL, -PRIMARY KEY (Host,Db,User,Routine_name), +Timestamp timestamp(14), +PRIMARY KEY (Host,Db,User,Routine_name,Routine_type), KEY Grantor (Grantor) ) CHARACTER SET utf8 COLLATE utf8_bin comment='Procedure privileges'; diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 7b915a93abc..cc7a6dbacb3 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -3171,12 +3171,28 @@ no_commit: prebuilt->sql_stat_start = TRUE; } - /* - We must use the handler code to update the auto-increment - value to be sure that increment it correctly. - */ + /* We have to use the transactional lock mechanism on the + auto-inc counter of the table to ensure that replication and + roll-forward of the binlog exactly imitates also the given + auto-inc values. The lock is released at each SQL statement's + end. This lock also prevents a race where two threads would + call ::get_auto_increment() simultaneously. */ + + error = row_lock_table_autoinc_for_mysql(prebuilt); + + if (error != DB_SUCCESS) { + /* Deadlock or lock wait timeout */ + + error = convert_error_code_to_mysql(error, user_thd); + + goto func_exit; + } + + /* We must use the handler code to update the auto-increment + value to be sure that we increment it correctly. */ + update_auto_increment(); - auto_inc_used= 1; + auto_inc_used = 1; } @@ -3199,24 +3215,9 @@ no_commit: auto_inc = table->next_number_field->val_int(); if (auto_inc != 0) { - /* This call will calculate the max of the current - value and the value supplied by the user and - update the counter accordingly */ + /* This call will update the counter according to the + value that was inserted in the table */ - /* We have to use the transactional lock mechanism - on the auto-inc counter of the table to ensure - that replication and roll-forward of the binlog - exactly imitates also the given auto-inc values. - The lock is released at each SQL statement's - end. */ - - error = row_lock_table_autoinc_for_mysql(prebuilt); - - if (error != DB_SUCCESS) { - error = convert_error_code_to_mysql(error, - user_thd); - goto func_exit; - } dict_table_autoinc_update(prebuilt->table, auto_inc); } } @@ -5796,7 +5797,6 @@ ha_innobase::start_stmt( read_view_close_for_mysql(trx); } - auto_inc_counter_for_this_stat = 0; prebuilt->sql_stat_start = TRUE; prebuilt->hint_need_to_fetch_extra_cols = 0; prebuilt->read_just_key = 0; @@ -5986,7 +5986,7 @@ ha_innobase::external_lock( trx->n_mysql_tables_in_use--; prebuilt->mysql_has_locked = FALSE; - auto_inc_counter_for_this_stat = 0; + if (trx->n_lock_table_exp) { row_unlock_tables_for_mysql(trx); } @@ -6506,7 +6506,7 @@ ha_innobase::store_lock( /*********************************************************************** This function initializes the auto-inc counter if it has not been initialized yet. This function does not change the value of the auto-inc -counter if it already has been initialized. In paramete ret returns +counter if it already has been initialized. In parameter ret returns the value of the auto-inc counter. */ int @@ -6625,7 +6625,14 @@ ha_innobase::get_auto_increment() error = innobase_read_and_init_auto_inc(&nr); if (error) { - + /* This should never happen in the current (5.0.6) code, since + we call this function only after the counter has been + initialized. */ + + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: Error: error %lu in ::get_auto_increment()\n", + (ulong)error); return(~(ulonglong) 0); } diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index 0b81794e54b..f18d527e6b3 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -70,7 +70,6 @@ class ha_innobase: public handler ROW_SEL_EXACT, ROW_SEL_EXACT_PREFIX, or undefined */ uint num_write_row; /* number of write_row() calls */ - longlong auto_inc_counter_for_this_stat; ulong max_supported_row_length(const byte *buf); uint store_key_val_for_row(uint keynr, char* buff, uint buff_len, diff --git a/sql/item_func.cc b/sql/item_func.cc index 2d537b1cccf..0934f7844d5 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4771,13 +4771,13 @@ Item_func_sp::execute(Item **itp) #endif #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (check_procedure_access(thd, EXECUTE_ACL, - m_sp->m_db.str, m_sp->m_name.str, 0)) + if (check_routine_access(thd, EXECUTE_ACL, + m_sp->m_db.str, m_sp->m_name.str, 0, 0)) DBUG_RETURN(-1); sp_change_security_context(thd, m_sp, &save_ctx); if (save_ctx.changed && - check_procedure_access(thd, EXECUTE_ACL, - m_sp->m_db.str, m_sp->m_name.str, 0)) + check_routine_access(thd, EXECUTE_ACL, + m_sp->m_db.str, m_sp->m_name.str, 0, 0)) { sp_restore_security_context(thd, m_sp, &save_ctx); thd->client_capabilities|= old_client_capabilites & CLIENT_MULTI_RESULTS; diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 4c44db49489..95979408ccb 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -726,7 +726,12 @@ public: Item_func_uuid(): Item_str_func() {} void fix_length_and_dec() { collation.set(system_charset_info); - max_length= UUID_LENGTH; + /* + NOTE! uuid() should be changed to use 'ascii' + charset when hex(), format(), md5(), etc, and implicit + number-to-string conversion will use 'ascii' + */ + max_length= UUID_LENGTH * system_charset_info->mbmaxlen; } const char *func_name() const{ return "uuid"; } String *val_str(String *); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index e513a1c6056..a39331b2556 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -477,12 +477,12 @@ void close_thread_tables(THD *thd, bool locked=0, bool skip_derived=0, TABLE *stopper= 0); bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *tables); -bool check_procedure_access(THD *thd,ulong want_access,char *db,char *name, - bool no_errors); +bool check_routine_access(THD *thd,ulong want_access,char *db,char *name, + bool is_proc, bool no_errors); bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table); bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *table_list); -bool check_some_routine_access(THD *thd, const char *db, const char *name); +bool check_some_routine_access(THD *thd, const char *db, const char *name, bool is_proc); bool multi_update_precheck(THD *thd, TABLE_LIST *tables); bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count); bool mysql_multi_update_prepare(THD *thd); diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 2f65a446ae8..ca2ec6d0acf 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1111,7 +1111,8 @@ bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access) (!strcmp(sp->m_definer_user.str, thd->priv_user) && !strcmp(sp->m_definer_host.str, thd->priv_host))); if (!*full_access) - return check_some_routine_access(thd, sp->m_db.str, sp->m_name.str); + return check_some_routine_access(thd, sp->m_db.str, sp->m_name.str, + sp->m_type == TYPE_ENUM_PROCEDURE); return 0; } diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index ef0f35c7e09..d10f20caf87 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -59,7 +59,7 @@ static DYNAMIC_ARRAY acl_hosts,acl_users,acl_dbs; static MEM_ROOT mem, memex; static bool initialized=0; static bool allow_all_hosts=1; -static HASH acl_check_hosts, column_priv_hash, proc_priv_hash; +static HASH acl_check_hosts, column_priv_hash, proc_priv_hash, func_priv_hash; static DYNAMIC_ARRAY acl_wild_hosts; static hash_filo *acl_cache; static uint grant_version=0; /* Version of priv tables. incremented by acl_init */ @@ -2135,11 +2135,12 @@ static GRANT_NAME *name_hash_search(HASH *name_hash, inline GRANT_NAME * -proc_hash_search(const char *host, const char *ip, const char *db, - const char *user, const char *tname, bool exact) +routine_hash_search(const char *host, const char *ip, const char *db, + const char *user, const char *tname, bool proc, bool exact) { - return (GRANT_TABLE*) name_hash_search(&proc_priv_hash, host, ip, db, - user, tname, exact); + return (GRANT_TABLE*) + name_hash_search(proc ? &proc_priv_hash : &func_priv_hash, + host, ip, db, user, tname, exact); } @@ -2465,16 +2466,17 @@ table_error: } -static int replace_proc_table(THD *thd, GRANT_NAME *grant_name, +static int replace_routine_table(THD *thd, GRANT_NAME *grant_name, TABLE *table, const LEX_USER &combo, - const char *db, const char *proc_name, - ulong rights, bool revoke_grant) + const char *db, const char *routine_name, + bool is_proc, ulong rights, bool revoke_grant) { char grantor[HOSTNAME_LENGTH+USERNAME_LENGTH+2]; int old_row_exists= 1; int error=0; ulong store_proc_rights; - DBUG_ENTER("replace_proc_table"); + byte *key; + DBUG_ENTER("replace_routine_table"); if (!initialized) { @@ -2498,7 +2500,10 @@ static int replace_proc_table(THD *thd, GRANT_NAME *grant_name, table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1); table->field[1]->store(db,(uint) strlen(db), &my_charset_latin1); table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1); - table->field[3]->store(proc_name,(uint) strlen(proc_name), &my_charset_latin1); + table->field[3]->store(routine_name,(uint) strlen(routine_name), + &my_charset_latin1); + table->field[4]->store((longlong)(is_proc ? + TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION)); store_record(table,record[1]); // store at pos 1 if (table->file->index_read_idx(table->record[0],0, @@ -2513,7 +2518,7 @@ static int replace_proc_table(THD *thd, GRANT_NAME *grant_name, if (revoke_grant) { // no row, no revoke my_error(ER_NONEXISTING_PROC_GRANT, MYF(0), - combo.user.str, combo.host.str, proc_name); + combo.user.str, combo.host.str, routine_name); DBUG_RETURN(-1); } old_row_exists= 0; @@ -2538,7 +2543,7 @@ static int replace_proc_table(THD *thd, GRANT_NAME *grant_name, } } - table->field[4]->store(grantor,(uint) strlen(grantor), &my_charset_latin1); + table->field[5]->store(grantor,(uint) strlen(grantor), &my_charset_latin1); table->field[6]->store((longlong) store_proc_rights); rights=fix_rights_for_procedure(store_proc_rights); @@ -2565,7 +2570,7 @@ static int replace_proc_table(THD *thd, GRANT_NAME *grant_name, } else { - hash_delete(&proc_priv_hash,(byte*) grant_name); + hash_delete(is_proc ? &proc_priv_hash : &func_priv_hash,(byte*) grant_name); } DBUG_RETURN(0); @@ -2841,12 +2846,13 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list, /* - Store procedure level grants in the privilege tables + Store routine level grants in the privilege tables SYNOPSIS - mysql_procedure_grant() + mysql_routine_grant() thd Thread handle - table_list List of procedures to give grant + table_list List of routines to give grant + is_proc true indicates routine list are procedures user_list List of users to give grant rights Table level grant revoke_grant Set to 1 if this is a REVOKE command @@ -2856,16 +2862,16 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list, 1 error */ -bool mysql_procedure_grant(THD *thd, TABLE_LIST *table_list, - List &user_list, ulong rights, - bool revoke_grant, bool no_error) +bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, + List &user_list, ulong rights, + bool revoke_grant, bool no_error) { List_iterator str_list (user_list); LEX_USER *Str; TABLE_LIST tables[2]; bool create_new_users=0, result=0; char *db_name, *table_name; - DBUG_ENTER("mysql_procedure_grant"); + DBUG_ENTER("mysql_routine_grant"); if (!initialized) { @@ -2884,7 +2890,7 @@ bool mysql_procedure_grant(THD *thd, TABLE_LIST *table_list, if (!revoke_grant) { - if (sp_exists_routine(thd, table_list, 0, no_error)<0) + if (sp_exists_routine(thd, table_list, is_proc, no_error)<0) DBUG_RETURN(TRUE); } @@ -2957,8 +2963,8 @@ bool mysql_procedure_grant(THD *thd, TABLE_LIST *table_list, db_name= table_list->db; table_name= table_list->table_name; - grant_name= proc_hash_search(Str->host.str, NullS, db_name, - Str->user.str, table_name, 1); + grant_name= routine_hash_search(Str->host.str, NullS, db_name, + Str->user.str, table_name, is_proc, 1); if (!grant_name) { if (revoke_grant) @@ -2977,11 +2983,11 @@ bool mysql_procedure_grant(THD *thd, TABLE_LIST *table_list, result= TRUE; continue; } - my_hash_insert(&proc_priv_hash,(byte*) grant_name); + my_hash_insert(is_proc ? &proc_priv_hash : &func_priv_hash,(byte*) grant_name); } - if (replace_proc_table(thd, grant_name, tables[1].table, *Str, - db_name, table_name, rights, revoke_grant)) + if (replace_routine_table(thd, grant_name, tables[1].table, *Str, + db_name, table_name, is_proc, rights, revoke_grant)) { result= TRUE; continue; @@ -3133,6 +3139,9 @@ my_bool grant_init(THD *org_thd) (void) hash_init(&proc_priv_hash,system_charset_info, 0,0,0, (hash_get_key) get_grant_table, 0,0); + (void) hash_init(&func_priv_hash,system_charset_info, + 0,0,0, (hash_get_key) get_grant_table, + 0,0); init_sql_alloc(&memex, ACL_ALLOC_BLOCK_SIZE, 0); /* Don't do anything if running with --skip-grant */ @@ -3206,6 +3215,8 @@ my_bool grant_init(THD *org_thd) do { GRANT_NAME *mem_check; + longlong proc_type; + HASH *hash; if (!(mem_check=new GRANT_NAME(p_table))) { /* This could only happen if we are out memory */ @@ -3224,11 +3235,27 @@ my_bool grant_init(THD *org_thd) continue; } } + if (p_table->field[4]->val_int() == TYPE_ENUM_PROCEDURE) + { + hash= &proc_priv_hash; + } + else + if (p_table->field[4]->val_int() == TYPE_ENUM_FUNCTION) + { + hash= &func_priv_hash; + } + else + { + sql_print_warning("'procs_priv' entry '%s' " + "ignored, bad routine type", + mem_check->tname); + continue; + } mem_check->privs= fix_rights_for_procedure(mem_check->privs); if (! mem_check->ok()) delete mem_check; - else if (my_hash_insert(&proc_priv_hash,(byte*) mem_check)) + else if (my_hash_insert(hash, (byte*) mem_check)) { delete mem_check; grant_option= FALSE; @@ -3272,7 +3299,7 @@ end: void grant_reload(THD *thd) { - HASH old_column_priv_hash, old_proc_priv_hash; + HASH old_column_priv_hash, old_proc_priv_hash, old_func_priv_hash; bool old_grant_option; MEM_ROOT old_mem; DBUG_ENTER("grant_reload"); @@ -3281,6 +3308,7 @@ void grant_reload(THD *thd) grant_version++; old_column_priv_hash= column_priv_hash; old_proc_priv_hash= proc_priv_hash; + old_func_priv_hash= func_priv_hash; old_grant_option= grant_option; old_mem= memex; @@ -3290,6 +3318,7 @@ void grant_reload(THD *thd) grant_free(); /* purecov: deadcode */ column_priv_hash= old_column_priv_hash; /* purecov: deadcode */ proc_priv_hash= old_proc_priv_hash; + func_priv_hash= old_func_priv_hash; grant_option= old_grant_option; /* purecov: deadcode */ memex= old_mem; /* purecov: deadcode */ } @@ -3297,6 +3326,7 @@ void grant_reload(THD *thd) { hash_free(&old_column_priv_hash); hash_free(&old_proc_priv_hash); + hash_free(&old_func_priv_hash); free_root(&old_mem,MYF(0)); } rw_unlock(&LOCK_grant); @@ -3540,13 +3570,14 @@ bool check_grant_db(THD *thd,const char *db) /**************************************************************************** - Check procedure level grants + Check routine level grants SYNPOSIS - bool check_grant_procedure() + bool check_grant_routine() thd Thread handler want_access Bits of privileges user needs to have - procs List of procedures to check. The user should have 'want_access' + procs List of routines to check. The user should have 'want_access' + is_proc True if the list is all procedures, else functions no_errors If 0 then we write an error. The error is sent directly to the client @@ -3555,13 +3586,13 @@ bool check_grant_db(THD *thd,const char *db) 1 Error: User did not have the requested privielges ****************************************************************************/ -bool check_grant_procedure(THD *thd, ulong want_access, - TABLE_LIST *procs, bool no_errors) +bool check_grant_routine(THD *thd, ulong want_access, + TABLE_LIST *procs, bool is_proc, bool no_errors) { TABLE_LIST *table; char *user= thd->priv_user; char *host= thd->priv_host; - DBUG_ENTER("check_grant_procedure"); + DBUG_ENTER("check_grant_routine"); want_access&= ~thd->master_access; if (!want_access) @@ -3571,8 +3602,8 @@ bool check_grant_procedure(THD *thd, ulong want_access, for (table= procs; table; table= table->next_global) { GRANT_NAME *grant_proc; - if ((grant_proc= proc_hash_search(host,thd->ip, - table->db, user, table->table_name, 0))) + if ((grant_proc= routine_hash_search(host,thd->ip, table->db, user, + table->table_name, is_proc, 0))) table->grant.privilege|= grant_proc->privs; if (want_access & ~table->grant.privilege) @@ -3594,7 +3625,7 @@ err: if (want_access & EXECUTE_ACL) command= "execute"; else if (want_access & ALTER_PROC_ACL) - command= "alter procedure"; + command= "alter routine"; else if (want_access & GRANT_ACL) command= "grant"; my_error(ER_PROCACCESS_DENIED_ERROR, MYF(0), @@ -3606,7 +3637,7 @@ err: /* Check if routine has any of the - procedure level grants + routine level grants SYNPOSIS bool check_routine_level_acl() @@ -3619,15 +3650,15 @@ err: 1 error */ -bool check_routine_level_acl(THD *thd, const char *db, const char *name) +bool check_routine_level_acl(THD *thd, const char *db, const char *name, bool is_proc) { bool no_routine_acl= 1; if (grant_option) { GRANT_NAME *grant_proc; rw_rdlock(&LOCK_grant); - if ((grant_proc= proc_hash_search(thd->priv_host, thd->ip, db, - thd->priv_user, name, 0))) + if ((grant_proc= routine_hash_search(thd->priv_host, thd->ip, db, + thd->priv_user, name, is_proc, 0))) no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS); rw_unlock(&LOCK_grant); } @@ -3730,6 +3761,11 @@ static uint command_lengths[]= }; +static int show_routine_grants(THD *thd, LEX_USER *lex_user, HASH *hash, + const char *type, int typelen, + char *buff, int buffsize); + + /* SHOW GRANTS; Send grants for a user to the client @@ -4076,12 +4112,40 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) } } - /* Add procedure access */ - for (index=0 ; index < proc_priv_hash.records ; index++) + if (show_routine_grants(thd, lex_user, &proc_priv_hash, + "PROCEDURE", 9, buff, sizeof(buff))) + { + error= -1; + goto end; + } + + if (show_routine_grants(thd, lex_user, &func_priv_hash, + "FUNCTION", 8, buff, sizeof(buff))) + { + error= -1; + goto end; + } + +end: + VOID(pthread_mutex_unlock(&acl_cache->lock)); + rw_unlock(&LOCK_grant); + + send_eof(thd); + DBUG_RETURN(error); +} + +static int show_routine_grants(THD* thd, LEX_USER *lex_user, HASH *hash, + const char *type, int typelen, + char *buff, int buffsize) +{ + uint counter, index; + int error= 0; + Protocol *protocol= thd->protocol; + /* Add routine access */ + for (index=0 ; index < hash->records ; index++) { const char *user; - GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(&proc_priv_hash, - index); + GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(hash, index); if (!(user=grant_proc->user)) user= ""; @@ -4093,7 +4157,7 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) ulong proc_access= grant_proc->privs; if (proc_access != 0) { - String global(buff, sizeof(buff), system_charset_info); + String global(buff, buffsize, system_charset_info); ulong test_access= proc_access & ~GRANT_ACL; global.length(0); @@ -4119,6 +4183,8 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) } } global.append(" ON ",4); + global.append(type,typelen); + global.append(' '); append_identifier(thd, &global, grant_proc->db, strlen(grant_proc->db)); global.append('.'); @@ -4143,15 +4209,9 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) } } } -end: - VOID(pthread_mutex_unlock(&acl_cache->lock)); - rw_unlock(&LOCK_grant); - - send_eof(thd); - DBUG_RETURN(error); + return error; } - /* Make a clear-text version of the requested privilege. */ @@ -4977,7 +5037,7 @@ bool mysql_rename_user(THD *thd, List &list) bool mysql_revoke_all(THD *thd, List &list) { - uint counter, revoked; + uint counter, revoked, is_proc; int result; ACL_DB *acl_db; TABLE_LIST tables[GRANT_TABLES]; @@ -5092,12 +5152,12 @@ bool mysql_revoke_all(THD *thd, List &list) } while (revoked); /* Remove procedure access */ - do { - for (counter= 0, revoked= 0 ; counter < proc_priv_hash.records ; ) + for (is_proc=0; is_proc<2; is_proc++) do { + HASH *hash= is_proc ? &proc_priv_hash : &func_priv_hash; + for (counter= 0, revoked= 0 ; counter < hash->records ; ) { const char *user,*host; - GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(&proc_priv_hash, - counter); + GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(hash, counter); if (!(user=grant_proc->user)) user= ""; if (!(host=grant_proc->host.hostname)) @@ -5106,9 +5166,10 @@ bool mysql_revoke_all(THD *thd, List &list) if (!strcmp(lex_user->user.str,user) && !my_strcasecmp(system_charset_info, lex_user->host.str, host)) { - if (!replace_proc_table(thd,grant_proc,tables[4].table,*lex_user, + if (!replace_routine_table(thd,grant_proc,tables[4].table,*lex_user, grant_proc->db, grant_proc->tname, + is_proc, ~0, 1)) { revoked= 1; @@ -5146,11 +5207,13 @@ bool mysql_revoke_all(THD *thd, List &list) < 0 Error. Error message not yet sent. */ -bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name) +bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name, + bool is_proc) { uint counter, revoked; int result; TABLE_LIST tables[GRANT_TABLES]; + HASH *hash= is_proc ? &proc_priv_hash : &func_priv_hash; DBUG_ENTER("sp_revoke_privileges"); if ((result= open_grant_tables(thd, tables))) @@ -5162,10 +5225,9 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name) /* Remove procedure access */ do { - for (counter= 0, revoked= 0 ; counter < proc_priv_hash.records ; ) + for (counter= 0, revoked= 0 ; counter < hash->records ; ) { - GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(&proc_priv_hash, - counter); + GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(hash, counter); if (!my_strcasecmp(system_charset_info, grant_proc->db, sp_db) && !my_strcasecmp(system_charset_info, grant_proc->tname, sp_name)) { @@ -5174,8 +5236,9 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name) lex_user.user.length= strlen(grant_proc->user); lex_user.host.str= grant_proc->host.hostname; lex_user.host.length= strlen(grant_proc->host.hostname); - if (!replace_proc_table(thd,grant_proc,tables[4].table,lex_user, - grant_proc->db, grant_proc->tname, ~0, 1)) + if (!replace_routine_table(thd,grant_proc,tables[4].table,lex_user, + grant_proc->db, grant_proc->tname, + is_proc, ~0, 1)) { revoked= 1; continue; @@ -5211,7 +5274,8 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name) < 0 Error. Error message not yet sent. */ -bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name) +bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name, + bool is_proc) { LEX_USER *combo; TABLE_LIST tables[1]; @@ -5249,7 +5313,7 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name) thd->lex->ssl_type= SSL_TYPE_NOT_SPECIFIED; bzero((char*) &thd->lex->mqh, sizeof(thd->lex->mqh)); - result= mysql_procedure_grant(thd, tables, user_list, + result= mysql_routine_grant(thd, tables, is_proc, user_list, DEFAULT_CREATE_PROC_ACLS, 0, 1); DBUG_RETURN(result); } diff --git a/sql/sql_acl.h b/sql/sql_acl.h index 2bc7c45907c..87280c4e9ba 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -186,9 +186,9 @@ bool mysql_grant(THD *thd, const char *db, List &user_list, bool mysql_table_grant(THD *thd, TABLE_LIST *table, List &user_list, List &column_list, ulong rights, bool revoke); -bool mysql_procedure_grant(THD *thd, TABLE_LIST *table, - List &user_list, ulong rights, - bool revoke, bool no_error); +bool mysql_routine_grant(THD *thd, TABLE_LIST *table, bool is_proc, + List &user_list, ulong rights, + bool revoke, bool no_error); ACL_USER *check_acl_user(LEX_USER *user_name, uint *acl_acl_userdx); my_bool grant_init(THD *thd); void grant_free(void); @@ -201,8 +201,8 @@ bool check_grant_column (THD *thd, GRANT_INFO *grant, bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant, const char* db_name, const char *table_name, Field_iterator *fields); -bool check_grant_procedure(THD *thd, ulong want_access, - TABLE_LIST *procs, bool no_error); +bool check_grant_routine(THD *thd, ulong want_access, + TABLE_LIST *procs, bool is_proc, bool no_error); bool check_grant_db(THD *thd,const char *db); ulong get_table_grant(THD *thd, TABLE_LIST *table); ulong get_column_grant(THD *thd, GRANT_INFO *grant, @@ -217,9 +217,12 @@ bool mysql_rename_user(THD *thd, List &list); bool mysql_revoke_all(THD *thd, List &list); void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant, const char *db, const char *table); -bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name); -bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name); -bool check_routine_level_acl(THD *thd, const char *db, const char *name); +bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name, + bool is_proc); +bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name, + bool is_proc); +bool check_routine_level_acl(THD *thd, const char *db, const char *name, + bool is_proc); #ifdef NO_EMBEDDED_ACCESS_CHECKS #define check_grant(A,B,C,D,E,F) 0 diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ce0dbd33054..1f3f2f4927b 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3673,17 +3673,20 @@ unsent_create_error: } if (first_table) { - if (!lex->columns.elements && - sp_exists_routine(thd, all_tables, 1, 1)) + if (lex->type == TYPE_ENUM_PROCEDURE || + lex->type == TYPE_ENUM_FUNCTION) { uint grants= lex->all_privileges ? (PROC_ACLS & ~GRANT_ACL) | (lex->grant & GRANT_ACL) : lex->grant; if (grant_option && - check_grant_procedure(thd, grants | GRANT_ACL, all_tables, 0)) + check_grant_routine(thd, grants | GRANT_ACL, all_tables, + lex->type == TYPE_ENUM_PROCEDURE, 0)) goto error; - res= mysql_procedure_grant(thd, all_tables, lex->users_list, - grants, lex->sql_command == SQLCOM_REVOKE,0); + res= mysql_routine_grant(thd, all_tables, + lex->type == TYPE_ENUM_PROCEDURE, + lex->users_list, grants, + lex->sql_command == SQLCOM_REVOKE, 0); } else { @@ -3705,7 +3708,7 @@ unsent_create_error: } else { - if (lex->columns.elements) + if (lex->columns.elements || lex->type) { my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE), MYF(0)); @@ -3987,11 +3990,13 @@ unsent_create_error: #ifndef NO_EMBEDDED_ACCESS_CHECKS /* only add privileges if really neccessary */ if (sp_automatic_privileges && - check_procedure_access(thd, DEFAULT_CREATE_PROC_ACLS, - db, name, 1)) + check_routine_access(thd, DEFAULT_CREATE_PROC_ACLS, + db, name, + lex->sql_command == SQLCOM_CREATE_PROCEDURE, 1)) { close_thread_tables(thd); - if (sp_grant_privileges(thd, db, name)) + if (sp_grant_privileges(thd, db, name, + lex->sql_command == SQLCOM_CREATE_PROCEDURE)) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_PROC_AUTO_GRANT_FAIL, ER(ER_PROC_AUTO_GRANT_FAIL)); @@ -4076,8 +4081,8 @@ unsent_create_error: } #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (check_procedure_access(thd, EXECUTE_ACL, - sp->m_db.str, sp->m_name.str, 0)) + if (check_routine_access(thd, EXECUTE_ACL, + sp->m_db.str, sp->m_name.str, TRUE, 0)) { #ifndef EMBEDDED_LIBRARY thd->net.no_send_ok= nsok; @@ -4086,8 +4091,8 @@ unsent_create_error: } sp_change_security_context(thd, sp, &save_ctx); if (save_ctx.changed && - check_procedure_access(thd, EXECUTE_ACL, - sp->m_db.str, sp->m_name.str, 0)) + check_routine_access(thd, EXECUTE_ACL, + sp->m_db.str, sp->m_name.str, TRUE, 0)) { #ifndef EMBEDDED_LIBRARY thd->net.no_send_ok= nsok; @@ -4189,8 +4194,9 @@ unsent_create_error: } else { - if (check_procedure_access(thd, ALTER_PROC_ACL, sp->m_db.str, - sp->m_name.str, 0)) + if (check_routine_access(thd, ALTER_PROC_ACL, sp->m_db.str, + sp->m_name.str, + lex->sql_command == SQLCOM_ALTER_PROCEDURE, 0)) goto error; memcpy(&lex->sp_chistics, &chistics, sizeof(lex->sp_chistics)); if (!trust_routine_creators && mysql_bin_log.is_open() && @@ -4248,11 +4254,13 @@ unsent_create_error: { db= thd->strdup(sp->m_db.str); name= thd->strdup(sp->m_name.str); - if (check_procedure_access(thd, ALTER_PROC_ACL, db, name, 0)) + if (check_routine_access(thd, ALTER_PROC_ACL, db, name, + lex->sql_command == SQLCOM_DROP_PROCEDURE, 0)) goto error; #ifndef NO_EMBEDDED_ACCESS_CHECKS if (sp_automatic_privileges && - sp_revoke_privileges(thd, db, name)) + sp_revoke_privileges(thd, db, name, + lex->sql_command == SQLCOM_DROP_PROCEDURE)) { push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_PROC_AUTO_REVOKE_FAIL, @@ -4836,8 +4844,8 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, bool -check_procedure_access(THD *thd, ulong want_access,char *db, char *name, - bool no_errors) +check_routine_access(THD *thd, ulong want_access,char *db, char *name, + bool is_proc, bool no_errors) { TABLE_LIST tables[1]; @@ -4853,7 +4861,7 @@ check_procedure_access(THD *thd, ulong want_access,char *db, char *name, #ifndef NO_EMBEDDED_ACCESS_CHECKS if (grant_option) - return check_grant_procedure(thd, want_access, tables, no_errors); + return check_grant_routine(thd, want_access, tables, is_proc, no_errors); #endif return FALSE; @@ -4874,7 +4882,8 @@ check_procedure_access(THD *thd, ulong want_access,char *db, char *name, 1 error */ -bool check_some_routine_access(THD *thd, const char *db, const char *name) +bool check_some_routine_access(THD *thd, const char *db, const char *name, + bool is_proc) { ulong save_priv; if (thd->master_access & SHOW_PROC_ACLS) @@ -4882,7 +4891,7 @@ bool check_some_routine_access(THD *thd, const char *db, const char *name) if (!check_access(thd, SHOW_PROC_ACLS, db, &save_priv, 0, 1) || (save_priv & SHOW_PROC_ACLS)) return FALSE; - return check_routine_level_acl(thd, db, name); + return check_routine_level_acl(thd, db, name, is_proc); } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 686060d1740..1160267732b 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2625,7 +2625,8 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table, definer= get_field(thd->mem_root, proc_table->field[11]); if (!full_access) full_access= !strcmp(sp_user, definer); - if (!full_access && check_some_routine_access(thd, sp_db, sp_name)) + if (!full_access && check_some_routine_access(thd, sp_db, sp_name, + proc_table->field[2]->val_int() == TYPE_ENUM_PROCEDURE)) return 0; if (lex->orig_sql_command == SQLCOM_SHOW_STATUS_PROC && diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index a8f945e8dd6..fa765cdc19a 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -804,7 +804,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); opt_delete_options opt_delete_option varchar nchar nvarchar opt_outer table_list table_name opt_option opt_place opt_attribute opt_attribute_list attribute column_list column_list_id - opt_column_list grant_privileges opt_table grant_list grant_option + opt_column_list grant_privileges grant_ident grant_list grant_option object_privilege object_privilege_list user_list rename_list clear_privileges flush_options flush_option equal optional_braces opt_key_definition key_usage_list2 @@ -7907,9 +7907,36 @@ revoke: ; revoke_command: - grant_privileges ON opt_table FROM grant_list + grant_privileges ON opt_table grant_ident FROM grant_list { - Lex->sql_command = SQLCOM_REVOKE; + LEX *lex= Lex; + lex->sql_command= SQLCOM_REVOKE; + lex->type= 0; + } + | + grant_privileges ON FUNCTION_SYM grant_ident FROM grant_list + { + LEX *lex= Lex; + if (lex->columns.elements) + { + yyerror(ER(ER_SYNTAX_ERROR)); + YYABORT; + } + lex->sql_command= SQLCOM_REVOKE; + lex->type= TYPE_ENUM_FUNCTION; + + } + | + grant_privileges ON PROCEDURE grant_ident FROM grant_list + { + LEX *lex= Lex; + if (lex->columns.elements) + { + yyerror(ER(ER_SYNTAX_ERROR)); + YYABORT; + } + lex->sql_command= SQLCOM_REVOKE; + lex->type= TYPE_ENUM_PROCEDURE; } | ALL opt_privileges ',' GRANT OPTION FROM grant_list @@ -7919,11 +7946,50 @@ revoke_command: ; grant: - GRANT clear_privileges grant_privileges ON opt_table TO_SYM grant_list - require_clause grant_options - { Lex->sql_command= SQLCOM_GRANT; } - ; + GRANT clear_privileges grant_command + {} + ; +grant_command: + grant_privileges ON opt_table grant_ident TO_SYM grant_list + require_clause grant_options + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_GRANT; + lex->type= 0; + } + | + grant_privileges ON FUNCTION_SYM grant_ident TO_SYM grant_list + require_clause grant_options + { + LEX *lex= Lex; + if (lex->columns.elements) + { + yyerror(ER(ER_SYNTAX_ERROR)); + YYABORT; + } + lex->sql_command= SQLCOM_GRANT; + lex->type= TYPE_ENUM_FUNCTION; + } + | + grant_privileges ON PROCEDURE grant_ident TO_SYM grant_list + require_clause grant_options + { + LEX *lex= Lex; + if (lex->columns.elements) + { + yyerror(ER(ER_SYNTAX_ERROR)); + YYABORT; + } + lex->sql_command= SQLCOM_GRANT; + lex->type= TYPE_ENUM_PROCEDURE; + } + ; + +opt_table: + /* Empty */ + | TABLE_SYM ; + grant_privileges: object_privilege_list { } | ALL opt_privileges @@ -8016,7 +8082,7 @@ require_list_element: } ; -opt_table: +grant_ident: '*' { LEX *lex= Lex;