#At file:///C:/source/bzr/mysql-6.0-wl-4073/
2676 Chuck Bell 2008-08-07
WL#4073 : Online Backup: backup and restore database object permissions
This patch adds the ability to backup privileges (grants) for databases.
added:
mysql-test/r/backup_db_grants.result
mysql-test/t/backup_db_grants.test
modified:
mysql-test/lib/mtr_report.pl
mysql-test/r/backup_ddl_blocker.result
mysql-test/r/backup_no_data.result
mysql-test/r/backup_views.result
mysql-test/t/backup_ddl_blocker.test
mysql-test/t/backup_no_data.test
mysql-test/t/backup_views.test
sql/backup/backup_aux.h
sql/backup/backup_info.cc
sql/backup/backup_info.h
sql/backup/backup_test.cc
sql/backup/image_info.cc
sql/backup/image_info.h
sql/backup/kernel.cc
sql/share/errmsg.txt
sql/si_objects.cc
sql/si_objects.h
per-file messages:
mysql-test/lib/mtr_report.pl
Added warning suppression for backup_db_grants test.
mysql-test/r/backup_db_grants.result
New result file.
mysql-test/r/backup_ddl_blocker.result
New result file with changes for added drop user commands.
mysql-test/r/backup_no_data.result
New result file with changes for added drop user commands.
mysql-test/r/backup_views.result
New result file with changes correct error message.
mysql-test/t/backup_db_grants.test
New test for testing backup and restore of grants.
mysql-test/t/backup_ddl_blocker.test
Added drop user ''@'%' commands to suppress warnings for anonymous user.
mysql-test/t/backup_no_data.test
Added drop user ''@'%' commands to suppress warnings for anonymous user.
mysql-test/t/backup_views.test
Corrected error message returned on restore.
sql/backup/backup_aux.h
Added defines for uniqueness values of grantee strings in the backup catalog.
sql/backup/backup_info.cc
Added code to include grants in the output stream.
sql/backup/backup_info.h
Added new pointer to locate end of list of events and beginning of
privileges (in memory).
sql/backup/backup_test.cc
Added testing code for low-level developer testing.
sql/backup/image_info.cc
Added case to include privileges (grants) in restore.
sql/backup/image_info.h
Added new case to materialize a grant after stripping off uniqueness
value for grantee.
sql/backup/kernel.cc
Added case statements to include privileges (grants) in the backup and restore.
sql/share/errmsg.txt
Added error messages for processing privileges and issuing warnings and errors
during backup and restore.
sql/si_objects.cc
Added new classes to manage database-, table-, column-, and routine-level grants.
sql/si_objects.h
New definitions of methods to backup and restore grants.
Helper methods added to check to see if grantee exists and iterate
over all grants found.
Corrected comment about user name for get_name() method.
=== modified file 'mysql-test/lib/mtr_report.pl'
--- a/mysql-test/lib/mtr_report.pl 2008-08-05 08:04:30 +0000
+++ b/mysql-test/lib/mtr_report.pl 2008-08-07 14:53:39 +0000
@@ -334,6 +334,12 @@ sub mtr_report_stats ($) {
/Backup:/ or /Restore:/ or /Can't open the online backup progress tables/
) or
+ # backup_db_grants test is supposed to trigger lots of restore warnings
+ ($testname eq 'main.backup_db_grants') and
+ (
+ /Restore:/ or /was skipped because the user does not exist/
+ ) or
+
# The tablespace test triggers error below on purpose
($testname eq 'main.backup_tablespace') and
(
=== added file 'mysql-test/r/backup_db_grants.result'
--- a/mysql-test/r/backup_db_grants.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/backup_db_grants.result 2008-08-07 14:53:39 +0000
@@ -0,0 +1,132 @@
+DROP DATABASE IF EXISTS bup_db_grants;
+DROP DATABASE IF EXISTS db2;
+Create two databases and two tables.
+CREATE DATABASE bup_db_grants;
+CREATE TABLE bup_db_grants.t1(a INT);
+CREATE TABLE bup_db_grants.s1(b INT);
+INSERT INTO bup_db_grants.t1 VALUES (1), (2), (3), (4);
+INSERT INTO bup_db_grants.s1 VALUES (10), (20), (30), (40);
+Now create users and assign various rights to the databases
+CREATE USER 'bup_user1'@'%';
+CREATE USER 'bup_user2'@'%';
+CREATE USER 'bup_user3'@'%';
+REVOKE ALL ON *.* FROM 'bup_user1'@'%';
+REVOKE ALL ON *.* FROM 'bup_user2'@'%';
+GRANT ALL ON db2.* TO 'bup_user1'@'%';
+GRANT SELECT ON bup_db_grants.* TO 'bup_user1'@'%';
+GRANT INSERT ON bup_db_grants.* TO 'bup_user2'@'%';
+GRANT ALL ON bup_db_grants.* TO 'no_user'@'%';
+GRANT SELECT (a) ON bup_db_grants.t1 TO 'bup_user1'@'%';
+GRANT SELECT (b), INSERT (b) ON bup_db_grants.s1 TO 'bup_user2'@'%';
+FLUSH PRIVILEGES;
+Demonstrate rights of the users.
+SHOW GRANTS FOR 'bup_user1'@'%';
+Grants for bup_user1@%
+GRANT USAGE ON *.* TO 'bup_user1'@'%'
+GRANT ALL PRIVILEGES ON `db2`.* TO 'bup_user1'@'%'
+GRANT SELECT ON `bup_db_grants`.* TO 'bup_user1'@'%'
+GRANT SELECT (a) ON `bup_db_grants`.`t1` TO 'bup_user1'@'%'
+SHOW GRANTS FOR 'bup_user2'@'%';
+Grants for bup_user2@%
+GRANT USAGE ON *.* TO 'bup_user2'@'%'
+GRANT INSERT ON `bup_db_grants`.* TO 'bup_user2'@'%'
+GRANT SELECT (b), INSERT (b) ON `bup_db_grants`.`s1` TO 'bup_user2'@'%'
+SHOW GRANTS FOR 'bup_user3'@'%';
+Grants for bup_user3@%
+GRANT USAGE ON *.* TO 'bup_user3'@'%'
+SHOW GRANTS FOR 'no_user'@'%';
+Grants for no_user@%
+GRANT USAGE ON *.* TO 'no_user'@'%'
+GRANT ALL PRIVILEGES ON `bup_db_grants`.* TO 'no_user'@'%'
+Run backup
+BACKUP DATABASE bup_db_grants TO 'bup_db_grants.bak';
+backup_id
+#
+Drop users and recreate them (removes grants completely).
+DROP USER 'bup_user1'@'%';
+DROP USER 'bup_user2'@'%';
+DROP USER 'bup_user3'@'%';
+DROP USER 'no_user'@'%';
+FLUSH PRIVILEGES;
+CREATE USER 'bup_user1'@'%';
+CREATE USER 'bup_user2'@'%';
+CREATE USER 'bup_user3'@'%';
+FLUSH PRIVILEGES;
+Demonstrate rights of the users.
+SHOW GRANTS FOR 'bup_user1'@'%';
+Grants for bup_user1@%
+GRANT USAGE ON *.* TO 'bup_user1'@'%'
+SHOW GRANTS FOR 'bup_user2'@'%';
+Grants for bup_user2@%
+GRANT USAGE ON *.* TO 'bup_user2'@'%'
+SHOW GRANTS FOR 'bup_user3'@'%';
+Grants for bup_user3@%
+GRANT USAGE ON *.* TO 'bup_user3'@'%'
+Run Restore
+RESTORE FROM 'bup_db_grants.bak';
+backup_id
+#
+SHOW TABLES FROM bup_db_grants;
+Tables_in_bup_db_grants
+s1
+t1
+Demonstrate rights of the users.
+SHOW GRANTS FOR 'bup_user1'@'%';
+Grants for bup_user1@%
+GRANT USAGE ON *.* TO 'bup_user1'@'%'
+GRANT SELECT ON `bup_db_grants`.* TO 'bup_user1'@'%'
+GRANT SELECT (a) ON `bup_db_grants`.`t1` TO 'bup_user1'@'%'
+SHOW GRANTS FOR 'bup_user2'@'%';
+Grants for bup_user2@%
+GRANT USAGE ON *.* TO 'bup_user2'@'%'
+GRANT INSERT ON `bup_db_grants`.* TO 'bup_user2'@'%'
+GRANT SELECT (b), INSERT (b) ON `bup_db_grants`.`s1` TO 'bup_user2'@'%'
+SHOW GRANTS FOR 'bup_user3'@'%';
+Grants for bup_user3@%
+GRANT USAGE ON *.* TO 'bup_user3'@'%'
+SHOW GRANTS FOR 'no_user'@'%';
+ERROR 42000: There is no such grant defined for user 'no_user' on host '%'
+Now test what happens on backup if users are deleted.
+Drop users and recreate one of them (removes grants completely).
+DROP USER 'bup_user1'@'%';
+DROP USER 'bup_user2'@'%';
+DROP USER 'bup_user3'@'%';
+FLUSH PRIVILEGES;
+CREATE USER 'bup_user1'@'%';
+CREATE USER 'bup_user1'@'nosuchhost';
+Run Restore
+RESTORE FROM 'bup_db_grants.bak';
+backup_id
+#
+SHOW TABLES FROM bup_db_grants;
+Tables_in_bup_db_grants
+s1
+t1
+Demonstrate rights of the users.
+SHOW GRANTS FOR 'bup_user1'@'%';
+Grants for bup_user1@%
+GRANT USAGE ON *.* TO 'bup_user1'@'%'
+GRANT SELECT ON `bup_db_grants`.* TO 'bup_user1'@'%'
+GRANT SELECT (a) ON `bup_db_grants`.`t1` TO 'bup_user1'@'%'
+SHOW GRANTS FOR 'bup_user2'@'%';
+ERROR 42000: There is no such grant defined for user 'bup_user2' on host '%'
+SHOW GRANTS FOR 'bup_user3'@'%';
+ERROR 42000: There is no such grant defined for user 'bup_user3' on host '%'
+SHOW GRANTS FOR 'no_user'@'%';
+ERROR 42000: There is no such grant defined for user 'no_user' on host '%'
+Now demonstrate what happens when grants are altered in backup image.
+Run Restore
+RESTORE FROM 'bup_db_grants.bad';
+ERROR HY000: The grant 'GRANT SELECT(a) ON boo_db_grants.t1 TO 'bup_user1'@'%' failed. Database not included in the backup image.
+FLUSH PRIVILEGES;
+Cleanup
+DROP USER 'bup_user1'@'%';
+DROP USER 'bup_user1'@'nosuchhost';
+DROP USER 'bup_user2'@'%';
+ERROR HY000: Operation DROP USER failed for 'bup_user2'@'%'
+DROP USER 'bup_user3'@'%';
+ERROR HY000: Operation DROP USER failed for 'bup_user3'@'%'
+DROP USER 'no_user'@'%';
+ERROR HY000: Operation DROP USER failed for 'no_user'@'%'
+FLUSH PRIVILEGES;
+DROP DATABASE bup_db_grants;
=== modified file 'mysql-test/r/backup_ddl_blocker.result'
--- a/mysql-test/r/backup_ddl_blocker.result 2008-06-25 13:39:04 +0000
+++ b/mysql-test/r/backup_ddl_blocker.result 2008-08-07 14:53:39 +0000
@@ -33,6 +33,7 @@ con3: Activate synchronization point for
SET DEBUG_SYNC= 'after_start_ddl SIGNAL con3_started WAIT_FOR status_shown';
con3: Get a DDL going and stop in the middle
ALTER TABLE bup_ddl_blocker.t2 ADD COLUMN col_b int;
+DROP USER ''@'%';
con1: Wait for con3 to reach its synchronization point.
SET DEBUG_SYNC= 'now WAIT_FOR con3_started';
con1: Activate synchronization points for backup.
@@ -276,6 +277,7 @@ con3: Activate synchronization point for
SET DEBUG_SYNC= 'after_start_ddl SIGNAL con3_started WAIT_FOR status_shown';
con3: Get a DDL going and stop in the middle
REPAIR TABLE bup_ddl_blocker.t2;
+DROP USER ''@'%';
con1: Wait for con3 to reach its synchronization point.
SET DEBUG_SYNC= 'now WAIT_FOR con3_started';
con1: Activate synchronization points for backup.
@@ -506,6 +508,7 @@ con3: Activate synchronization point for
SET DEBUG_SYNC= 'after_start_ddl SIGNAL con3_started WAIT_FOR status_shown';
con3: Get a DDL going and stop in the middle
DROP TABLE bup_ddl_blocker.t2;
+DROP USER ''@'%';
con1: Wait for con3 to reach its synchronization point.
SET DEBUG_SYNC= 'now WAIT_FOR con3_started';
con1: Activate synchronization points for backup.
@@ -732,6 +735,7 @@ con3: Activate synchronization point for
SET DEBUG_SYNC= 'after_start_ddl SIGNAL con3_started WAIT_FOR status_shown';
con3: Get a DDL going and stop in the middle
DROP DATABASE bup_ddl_blocker_2;
+DROP USER ''@'%';
con1: Wait for con3 to reach its synchronization point.
SET DEBUG_SYNC= 'now WAIT_FOR con3_started';
con1: Activate synchronization points for backup.
@@ -953,6 +957,7 @@ con3: Activate synchronization point for
SET DEBUG_SYNC= 'after_start_ddl SIGNAL con3_started WAIT_FOR status_shown';
con3: Get a DDL going and stop in the middle
ALTER DATABASE bup_ddl_blocker_2 CHARACTER SET latin2;
+DROP USER ''@'%';
con1: Wait for con3 to reach its synchronization point.
SET DEBUG_SYNC= 'now WAIT_FOR con3_started';
con1: Activate synchronization points for backup.
@@ -1227,6 +1232,7 @@ con3: Activate synchronization point for
SET DEBUG_SYNC= 'after_start_ddl SIGNAL con3_started WAIT_FOR status_shown';
con3: Get a DDL going and stop in the middle
DROP INDEX 2t1col_b ON bup_ddl_blocker_2.t1;
+DROP USER ''@'%';
con1: Wait for con3 to reach its synchronization point.
SET DEBUG_SYNC= 'now WAIT_FOR con3_started';
con1: Activate synchronization points for backup.
=== modified file 'mysql-test/r/backup_no_data.result'
--- a/mysql-test/r/backup_no_data.result 2008-02-13 11:40:39 +0000
+++ b/mysql-test/r/backup_no_data.result 2008-08-07 14:53:39 +0000
@@ -2,6 +2,7 @@ DROP DATABASE IF EXISTS empty_db;
DROP DATABASE IF EXISTS other_db;
CREATE DATABASE empty_db;
CREATE DATABASE other_db;
+DROP USER ''@'%';
BACKUP DATABASE empty_db TO 'empty_db.bak';
backup_id
#
=== modified file 'mysql-test/r/backup_views.result'
--- a/mysql-test/r/backup_views.result 2008-08-05 08:04:30 +0000
+++ b/mysql-test/r/backup_views.result 2008-08-07 14:53:39 +0000
@@ -239,10 +239,10 @@ DROP DATABASE bup_db1;
DROP DATABASE bup_db2;
restore database with view dependency to other, non-existing db
RESTORE FROM 'bup_objectview1.bak';
-ERROR 42S02: Table 'bup_db2.t2' doesn't exist
+ERROR HY000: Could not restore view `bup_db1`.`v5`
DROP DATABASE bup_db1;
RESTORE FROM 'bup_objectview2.bak';
-ERROR 42S02: Table 'bup_db1.t3' doesn't exist
+ERROR HY000: Could not restore view `bup_db2`.`student_details`
DROP DATABASE bup_db2;
RESTORE FROM 'bup_objectview.bak';
backup_id
=== added file 'mysql-test/t/backup_db_grants.test'
--- a/mysql-test/t/backup_db_grants.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/backup_db_grants.test 2008-08-07 14:53:39 +0000
@@ -0,0 +1,132 @@
+#
+# Test the backup of database grants
+#
+
+--source include/not_embedded.inc
+
+--disable_warnings
+DROP DATABASE IF EXISTS bup_db_grants;
+DROP DATABASE IF EXISTS db2;
+--enable_warnings
+
+--echo Create two databases and two tables.
+CREATE DATABASE bup_db_grants;
+CREATE TABLE bup_db_grants.t1(a INT);
+CREATE TABLE bup_db_grants.s1(b INT);
+INSERT INTO bup_db_grants.t1 VALUES (1), (2), (3), (4);
+INSERT INTO bup_db_grants.s1 VALUES (10), (20), (30), (40);
+
+--echo Now create users and assign various rights to the databases
+CREATE USER 'bup_user1'@'%';
+CREATE USER 'bup_user2'@'%';
+CREATE USER 'bup_user3'@'%';
+REVOKE ALL ON *.* FROM 'bup_user1'@'%';
+REVOKE ALL ON *.* FROM 'bup_user2'@'%';
+GRANT ALL ON db2.* TO 'bup_user1'@'%';
+GRANT SELECT ON bup_db_grants.* TO 'bup_user1'@'%';
+GRANT INSERT ON bup_db_grants.* TO 'bup_user2'@'%';
+GRANT ALL ON bup_db_grants.* TO 'no_user'@'%';
+GRANT SELECT (a) ON bup_db_grants.t1 TO 'bup_user1'@'%';
+GRANT SELECT (b), INSERT (b) ON bup_db_grants.s1 TO 'bup_user2'@'%';
+FLUSH PRIVILEGES;
+
+--echo Demonstrate rights of the users.
+SHOW GRANTS FOR 'bup_user1'@'%';
+SHOW GRANTS FOR 'bup_user2'@'%';
+SHOW GRANTS FOR 'bup_user3'@'%';
+SHOW GRANTS FOR 'no_user'@'%';
+
+--echo Run backup
+--replace_column 1 #
+BACKUP DATABASE bup_db_grants TO 'bup_db_grants.bak';
+
+--echo Drop users and recreate them (removes grants completely).
+DROP USER 'bup_user1'@'%';
+DROP USER 'bup_user2'@'%';
+DROP USER 'bup_user3'@'%';
+DROP USER 'no_user'@'%';
+
+FLUSH PRIVILEGES;
+
+CREATE USER 'bup_user1'@'%';
+CREATE USER 'bup_user2'@'%';
+CREATE USER 'bup_user3'@'%';
+
+FLUSH PRIVILEGES;
+
+--echo Demonstrate rights of the users.
+SHOW GRANTS FOR 'bup_user1'@'%';
+SHOW GRANTS FOR 'bup_user2'@'%';
+SHOW GRANTS FOR 'bup_user3'@'%';
+
+--echo Run Restore
+--replace_column 1 #
+RESTORE FROM 'bup_db_grants.bak';
+
+SHOW TABLES FROM bup_db_grants;
+
+--echo Demonstrate rights of the users.
+# Note: Since db2 was not in the backup and the user was deleted prior to
+# the backup, that privilege will not appear here.
+SHOW GRANTS FOR 'bup_user1'@'%';
+SHOW GRANTS FOR 'bup_user2'@'%';
+SHOW GRANTS FOR 'bup_user3'@'%';
+--error ER_NONEXISTING_GRANT
+SHOW GRANTS FOR 'no_user'@'%';
+
+--echo Now test what happens on backup if users are deleted.
+
+--echo Drop users and recreate one of them (removes grants completely).
+DROP USER 'bup_user1'@'%';
+DROP USER 'bup_user2'@'%';
+DROP USER 'bup_user3'@'%';
+
+FLUSH PRIVILEGES;
+
+CREATE USER 'bup_user1'@'%';
+CREATE USER 'bup_user1'@'nosuchhost';
+
+--echo Run Restore
+--replace_column 1 #
+RESTORE FROM 'bup_db_grants.bak';
+
+SHOW TABLES FROM bup_db_grants;
+
+--echo Demonstrate rights of the users.
+SHOW GRANTS FOR 'bup_user1'@'%';
+--error ER_NONEXISTING_GRANT
+SHOW GRANTS FOR 'bup_user2'@'%';
+--error ER_NONEXISTING_GRANT
+SHOW GRANTS FOR 'bup_user3'@'%';
+--error ER_NONEXISTING_GRANT
+SHOW GRANTS FOR 'no_user'@'%';
+
+--echo Now demonstrate what happens when grants are altered in backup image.
+
+--exec sed 's/(a) ON bup/(a) ON boo/' $MYSQLTEST_VARDIR/master-data/bup_db_grants.bak > $MYSQLTEST_VARDIR/master-data/bup_db_grants.bad
+--echo Run Restore
+--error ER_BACKUP_GRANT_WRONG_DB
+RESTORE FROM 'bup_db_grants.bad';
+
+FLUSH PRIVILEGES;
+
+--echo Cleanup
+
+DROP USER 'bup_user1'@'%';
+DROP USER 'bup_user1'@'nosuchhost';
+--error ER_CANNOT_USER
+DROP USER 'bup_user2'@'%';
+--error ER_CANNOT_USER
+DROP USER 'bup_user3'@'%';
+--error ER_CANNOT_USER
+DROP USER 'no_user'@'%';
+
+FLUSH PRIVILEGES;
+
+DROP DATABASE bup_db_grants;
+
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/bup_db_grants.bak
+
+--error 0,1
+--remove_file $MYSQLTEST_VARDIR/master-data/bup_db_grants.bad
=== modified file 'mysql-test/t/backup_ddl_blocker.test'
--- a/mysql-test/t/backup_ddl_blocker.test 2008-06-25 13:39:04 +0000
+++ b/mysql-test/t/backup_ddl_blocker.test 2008-08-07 14:53:39 +0000
@@ -146,6 +146,10 @@ send ALTER TABLE bup_ddl_blocker.t2 ADD
connection con1;
+#Drop of the user ''@'%' if it exists.
+--error 0,ER_CANNOT_USER
+DROP USER ''@'%';
+
--echo con1: Wait for con3 to reach its synchronization point.
SET DEBUG_SYNC= 'now WAIT_FOR con3_started';
--echo con1: Activate synchronization points for backup.
@@ -419,6 +423,10 @@ send REPAIR TABLE bup_ddl_blocker.t2;
connection con1;
+#Drop of the user ''@'%' if it exists.
+--error 0,ER_CANNOT_USER
+DROP USER ''@'%';
+
--echo con1: Wait for con3 to reach its synchronization point.
SET DEBUG_SYNC= 'now WAIT_FOR con3_started';
--echo con1: Activate synchronization points for backup.
@@ -680,6 +688,10 @@ send DROP TABLE bup_ddl_blocker.t2;
connection con1;
+#Drop of the user ''@'%' if it exists.
+--error 0,ER_CANNOT_USER
+DROP USER ''@'%';
+
--echo con1: Wait for con3 to reach its synchronization point.
SET DEBUG_SYNC= 'now WAIT_FOR con3_started';
--echo con1: Activate synchronization points for backup.
@@ -965,6 +977,10 @@ send DROP DATABASE bup_ddl_blocker_2;
connection con1;
+#Drop of the user ''@'%' if it exists.
+--error 0,ER_CANNOT_USER
+DROP USER ''@'%';
+
--echo con1: Wait for con3 to reach its synchronization point.
SET DEBUG_SYNC= 'now WAIT_FOR con3_started';
--echo con1: Activate synchronization points for backup.
@@ -1279,6 +1295,10 @@ send ALTER DATABASE bup_ddl_blocker_2 CH
connection con1;
+#Drop of the user ''@'%' if it exists.
+--error 0,ER_CANNOT_USER
+DROP USER ''@'%';
+
--echo con1: Wait for con3 to reach its synchronization point.
SET DEBUG_SYNC= 'now WAIT_FOR con3_started';
--echo con1: Activate synchronization points for backup.
@@ -1628,6 +1648,10 @@ send DROP INDEX 2t1col_b ON bup_ddl_bloc
# Start the backup and allow it to break on lock.
connection con1;
+
+#Drop of the user ''@'%' if it exists.
+--error 0,ER_CANNOT_USER
+DROP USER ''@'%';
--echo con1: Wait for con3 to reach its synchronization point.
SET DEBUG_SYNC= 'now WAIT_FOR con3_started';
=== modified file 'mysql-test/t/backup_no_data.test'
--- a/mysql-test/t/backup_no_data.test 2008-02-14 20:57:18 +0000
+++ b/mysql-test/t/backup_no_data.test 2008-08-07 14:53:39 +0000
@@ -8,6 +8,10 @@ DROP DATABASE IF EXISTS other_db;
CREATE DATABASE empty_db;
CREATE DATABASE other_db;
+#Drop of the user ''@'%' if it exists.
+--error 0,ER_CANNOT_USER
+DROP USER ''@'%';
+
--error 0,1
--remove_file $MYSQLTEST_VARDIR/master-data/empty_db.bak
--replace_column 1 #
=== modified file 'mysql-test/t/backup_views.test'
--- a/mysql-test/t/backup_views.test 2008-08-05 08:04:30 +0000
+++ b/mysql-test/t/backup_views.test 2008-08-07 14:53:39 +0000
@@ -188,14 +188,14 @@ DROP DATABASE bup_db2;
#Individual databases cannot be restored because of VIEW DEPENDENCY
--echo restore database with view dependency to other, non-existing db
---error ER_NO_SUCH_TABLE
+--error ER_BACKUP_CANT_RESTORE_VIEW
RESTORE FROM 'bup_objectview1.bak';
# An incomplete bup_db1 was created by the failing restore operation.
# Remove it before trying restore of bup_db2.
DROP DATABASE bup_db1;
---error ER_NO_SUCH_TABLE
+--error ER_BACKUP_CANT_RESTORE_VIEW
RESTORE FROM 'bup_objectview2.bak';
# An incomplete bup_db2 was created by the failing restore operation.
=== modified file 'sql/backup/backup_aux.h'
--- a/sql/backup/backup_aux.h 2008-07-31 10:45:02 +0000
+++ b/sql/backup/backup_aux.h 2008-08-07 14:53:39 +0000
@@ -47,6 +47,12 @@ storage_engine_ref get_se_by_name(const
namespace backup {
/**
+ Constants for appending uniqueness to privileges in backup catalog.
+*/
+#define UNIQUE_PRIV_KEY_LEN 9
+#define UNIQUE_PRIV_KEY_FORMAT "%08d"
+
+/**
Local version of LEX_STRING structure.
Defines various constructors for convenience.
=== modified file 'sql/backup/backup_info.cc'
--- a/sql/backup/backup_info.cc 2008-08-05 08:04:30 +0000
+++ b/sql/backup/backup_info.cc 2008-08-07 14:53:39 +0000
@@ -309,7 +309,7 @@ Backup_info::Dep_node::get_key(const uch
Backup_info::Backup_info(Backup_restore_ctx &ctx)
:m_ctx(ctx), m_state(Backup_info::ERROR), native_snapshots(8),
m_dep_list(NULL), m_dep_end(NULL),
- m_srout_end(NULL), m_view_end(NULL), m_trigger_end(NULL)
+ m_srout_end(NULL), m_view_end(NULL), m_trigger_end(NULL), m_event_end(NULL)
{
using namespace backup;
@@ -786,6 +786,18 @@ int Backup_info::add_db_items(Db &db)
if (add_objects(db, BSTREAM_IT_TRIGGER, *it))
goto error;
+ delete it;
+ it= get_all_db_grants(m_ctx.m_thd, &db.name());
+
+ if (!it)
+ {
+ m_ctx.fatal_error(ER_BACKUP_LIST_DB_PRIV, db.name().ptr());
+ goto error;
+ }
+
+ if (add_objects(db, BSTREAM_IT_PRIVILEGE, *it))
+ goto error;
+
goto finish;
error:
@@ -1002,7 +1014,7 @@ Backup_info::add_db_object(Db &db, const
ulong pos= db.obj_count();
DBUG_ASSERT(obj);
- const ::String *name= obj->get_name();
+ String *name= (String *)obj->get_name();
DBUG_ASSERT(name);
switch (type) {
@@ -1016,12 +1028,29 @@ Backup_info::add_db_object(Db &db, const
case BSTREAM_IT_SFUNC: error= ER_BACKUP_CATALOG_ADD_SROUT; break;
case BSTREAM_IT_EVENT: error= ER_BACKUP_CATALOG_ADD_EVENT; break;
case BSTREAM_IT_TRIGGER: error= ER_BACKUP_CATALOG_ADD_TRIGGER; break;
+ case BSTREAM_IT_PRIVILEGE: error= ER_BACKUP_CATALOG_ADD_PRIV; break;
// Only known types of objects should be added to the catalogue.
default: DBUG_ASSERT(FALSE);
}
+ /*
+ Generate a unique name for the privilege (grant) objects.
+ Note: this name does not alter the mechanics of the
+ grant objects in si_objects.cc
+ */
+ if (type == BSTREAM_IT_PRIVILEGE)
+ {
+ String new_name;
+ char buff[10];
+ sprintf(buff, UNIQUE_PRIV_KEY_FORMAT, pos);
+ new_name.append(*name);
+ new_name.append(" ");
+ new_name.append(buff);
+ name->copy(new_name);
+ }
+
/*
Add new object to the dependency list. If it is a view, add its
dependencies first.
@@ -1068,9 +1097,8 @@ Backup_info::add_db_object(Db &db, const
objects.
*/
- // Add object to catalogue
Dbobj *o= Image_info::add_db_object(db, type, *name, pos);
-
+
if (!o)
{
m_ctx.fatal_error(error, db.name().ptr(), name->ptr());
@@ -1199,6 +1227,12 @@ int Backup_info::add_to_dep_list(const o
break;
case BSTREAM_IT_EVENT:
+ end= &m_event_end;
+ if (!m_event_end)
+ m_event_end= m_trigger_end ? m_trigger_end : m_view_end ? m_view_end : m_srout_end;
+ break;
+
+ case BSTREAM_IT_PRIVILEGE:
end= &m_dep_end;
break;
=== modified file 'sql/backup/backup_info.h'
--- a/sql/backup/backup_info.h 2008-05-17 15:54:19 +0000
+++ b/sql/backup/backup_info.h 2008-08-07 14:53:39 +0000
@@ -141,6 +141,12 @@ class Backup_info: public backup::Image_
*/
Dep_node *m_trigger_end;
+ /**
+ Points at the last event on the dependency list. NULL if events section
+ is empty.
+ */
+ Dep_node *m_event_end;
+
/**
Hash keeping all elements stored in the dependency list.
=== modified file 'sql/backup/backup_test.cc'
--- a/sql/backup/backup_test.cc 2008-06-25 13:39:04 +0000
+++ b/sql/backup/backup_test.cc 2008-08-07 14:53:39 +0000
@@ -45,14 +45,20 @@ int execute_backup_test_command(THD *thd
field_list.push_back(new Item_empty_string("serialization", 13));
protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
- obs::ObjIterator *it= obs::get_databases(thd);
-
- if (it)
+ //obs::ObjIterator *it= obs::get_databases(thd);
+ List_iterator<LEX_STRING> it(*db_list);
+
+ //if (it)
{
obs::Obj *db;
- while ((db= it->next()))
+ //while ((db= it->next()))
+ LEX_STRING *dbname;
+ while ((dbname= it++))
{
+ String dir;
+ dir.copy(dbname->str, dbname->length, system_charset_info);
+ db= get_database(&dir);
if (is_internal_db_name(db->get_db_name()))
continue;
@@ -224,20 +230,49 @@ int execute_backup_test_command(THD *thd
delete event;
}
+ }
- delete tit;
+ //
+ // List db grants.
+ //
+ tit= obs::get_all_db_grants(thd, db->get_name());
+
+ if (tit)
+ {
+ obs::Obj *grant;
+
+ while ((grant= tit->next()))
+ {
+ String serial;
+ serial.length(0);
+ protocol->prepare_for_resend();
+ protocol->store(const_cast<String*>(db->get_name()));
+ protocol->store(const_cast<String*>(grant->get_name()));
+ String user;
+ String host;
+ String *user_host= (String *)grant->get_name();
+ user_exists(thd, user_host);
+ protocol->store(C_STRING_WITH_LEN("GRANT"),
+ system_charset_info);
+ grant->serialize(thd, &serial);
+ protocol->store(&serial);
+ protocol->write();
+
+ delete grant;
+ }
+
+ delete tit;
}
- // That's it.
+ // // That's it.
- delete db;
+ // delete db;
}
}
-
- delete it;
+ thd->main_da.reset_diagnostics_area();
+// delete it;
my_eof(thd);
-// delete i;
DBUG_RETURN(res);
}
=== modified file 'sql/backup/image_info.cc'
--- a/sql/backup/image_info.cc 2008-07-31 10:45:02 +0000
+++ b/sql/backup/image_info.cc 2008-08-07 14:53:39 +0000
@@ -384,6 +384,7 @@ Image_info::Obj *find_obj(const Image_in
case BSTREAM_IT_SFUNC:
case BSTREAM_IT_EVENT:
case BSTREAM_IT_TRIGGER:
+ case BSTREAM_IT_PRIVILEGE:
{
const st_bstream_dbitem_info &it=
reinterpret_cast<const st_bstream_dbitem_info&>(item);
=== modified file 'sql/backup/image_info.h'
--- a/sql/backup/image_info.h 2008-07-31 10:45:02 +0000
+++ b/sql/backup/image_info.h 2008-08-07 14:53:39 +0000
@@ -1012,6 +1012,17 @@ obs::Obj* Image_info::Dbobj::materialize
case BSTREAM_IT_TRIGGER:
m_obj_ptr= obs::materialize_trigger(db_name, name, ver, &sdata);
break;
+ case BSTREAM_IT_PRIVILEGE:
+ {
+ /*
+ Here we undo the uniqueness suffix for grants.
+ */
+ String new_name;
+ new_name.copy(*name);
+ new_name.length(new_name.length() - UNIQUE_PRIV_KEY_LEN);
+ m_obj_ptr= obs::materialize_db_grant(db_name, &new_name, ver, &sdata);
+ break;
+ }
default: m_obj_ptr= NULL;
}
=== modified file 'sql/backup/kernel.cc'
--- a/sql/backup/kernel.cc 2008-07-31 10:45:02 +0000
+++ b/sql/backup/kernel.cc 2008-08-07 14:53:39 +0000
@@ -1016,6 +1016,10 @@ int Backup_restore_ctx::do_restore()
if (read_meta_data(info, s))
{
+ // FIXME: detect errors.
+ // FIXME: error logging.
+ m_thd->main_da.reset_diagnostics_area();
+
fatal_error(ER_BACKUP_READ_META);
DBUG_RETURN(m_error);
}
@@ -1388,6 +1392,7 @@ int bcat_add_item(st_bstream_image_heade
case BSTREAM_IT_SFUNC:
case BSTREAM_IT_EVENT:
case BSTREAM_IT_TRIGGER:
+ case BSTREAM_IT_PRIVILEGE:
{
st_bstream_dbitem_info *it= (st_bstream_dbitem_info*)item;
@@ -1399,7 +1404,6 @@ int bcat_add_item(st_bstream_image_heade
Image_info::Dbobj *it1= info->add_db_object(*db, item->type, name_str,
item->pos);
-
if (!it1)
return BSTREAM_ERROR;
@@ -1650,6 +1654,7 @@ int bcat_create_item(st_bstream_image_he
case BSTREAM_IT_EVENT: create_err= ER_BACKUP_CANT_RESTORE_EVENT; break;
case BSTREAM_IT_TRIGGER: create_err= ER_BACKUP_CANT_RESTORE_TRIGGER; break;
case BSTREAM_IT_TABLESPACE: create_err= ER_BACKUP_CANT_RESTORE_TS; break;
+ case BSTREAM_IT_PRIVILEGE: create_err= ER_BACKUP_CANT_RESTORE_PRIV; break;
/*
TODO: Decide what to do when we come across unknown item:
@@ -1736,6 +1741,48 @@ int bcat_create_item(st_bstream_image_he
// Create the object.
+ /*
+ We need to check to see if the user exists (grantee) and if not,
+ do not execute the grant.
+ */
+ if (item->type == BSTREAM_IT_PRIVILEGE)
+ {
+ /*
+ Issue warning to the user that grant was skipped.
+
+ @todo Replace write_message() call with the result of the revised
+ error handling work in WL#4384 with possible implementation
+ via a related bug report.
+ */
+ if (!obs::user_exists(thd, sobj->get_name()))
+ {
+ info->m_ctx.write_message(log_level::WARNING,
+ ER(ER_BACKUP_GRANT_SKIPPED),
+ create_stmt);
+ return BSTREAM_OK;
+ }
+ /*
+ We need to check the grant against the database list to ensure the
+ grants have not been altered to apply to another database.
+ */
+ ::String db_name; // db name extracted from grant statement
+ char *start;
+ char *end;
+ int size= 0;
+
+ start= strstr((char *)create_stmt.begin, "ON ") + 3;
+ end= strstr(start, ".");
+ size= end - start;
+ db_name.alloc(size);
+ db_name.length(0);
+ db_name.append(start, size);
+ if (!info->has_db(db_name))
+ {
+ info->m_ctx.fatal_error(ER_BACKUP_GRANT_WRONG_DB, create_stmt);
+ return BSTREAM_ERROR;
+ }
+ }
+
if (sobj->execute(thd))
{
info->m_ctx.fatal_error(create_err, desc);
@@ -1781,6 +1828,7 @@ int bcat_get_item_create_query(st_bstrea
case BSTREAM_IT_EVENT: meta_err= ER_BACKUP_GET_META_EVENT; break;
case BSTREAM_IT_TRIGGER: meta_err= ER_BACKUP_GET_META_TRIGGER; break;
case BSTREAM_IT_TABLESPACE: meta_err= ER_BACKUP_GET_META_TS; break;
+ case BSTREAM_IT_PRIVILEGE: meta_err= ER_BACKUP_GET_META_PRIV; break;
/*
This can't happen - the item was obtained from the backup kernel.
=== modified file 'sql/share/errmsg.txt'
--- a/sql/share/errmsg.txt 2008-07-09 07:12:43 +0000
+++ b/sql/share/errmsg.txt 2008-08-07 14:53:39 +0000
@@ -6372,3 +6372,15 @@ ER_BACKUP_OBTAIN_NAME_LOCK_FAILED
eng "Restore failed to obtain the name locks on the tables."
ER_BACKUP_RELEASE_NAME_LOCK_FAILED
eng "Restore failed to release the name locks on the tables."
+ER_BACKUP_LIST_DB_PRIV
+ eng "Can't enumerate grants in database %-.64s"
+ER_BACKUP_CATALOG_ADD_PRIV
+ eng "Failed to add grant `%-.64s` to the catalog"
+ER_BACKUP_GET_META_PRIV
+ eng "Failed to obtain meta-data for grant %-.64s."
+ER_BACKUP_CANT_RESTORE_PRIV
+ eng "Could not execute grant %-.64s."
+ER_BACKUP_GRANT_SKIPPED
+ eng "The grant '%-.64s' was skipped because the user does not exist."
+ER_BACKUP_GRANT_WRONG_DB
+ eng "The grant '%-.64s' failed. Database not included in the backup image."
=== modified file 'sql/si_objects.cc'
--- a/sql/si_objects.cc 2008-07-09 07:12:43 +0000
+++ b/sql/si_objects.cc 2008-08-07 14:53:39 +0000
@@ -759,6 +759,123 @@ private:
String m_create_stmt;
};
+/**
+ @class DbGrantObj
+
+ This class provides an abstraction to database-level grants.
+ This class will permit the recording and replaying of these
+ grants.
+*/
+class DbGrantObj : public Obj
+{
+public:
+ DbGrantObj(const String *grantee,
+ const String *db_name,
+ const String *priv_type);
+
+public:
+ virtual bool materialize(uint serialization_version,
+ const String *serialization);
+
+ const String* get_name()
+ {
+ return &m_name;
+ }
+
+ const String *get_db_name()
+ {
+ return &m_db_name;
+ }
+
+ const String *get_priv_type()
+ {
+ return &m_priv_type;
+ }
+
+protected:
+ // These attributes are to be used only for serialization.
+ String m_db_name; ///< corresponds with TABLE_SCHEMA in IS tables.
+ String m_name; ///< name used to list in catalog.
+ String m_grantee; ///< corresponds with GRANTEE in IS tables.
+ String m_priv_type; ///< corresponds with PRIVILEGE_TYPE in IS tables.
+
+ bool drop(THD *thd) { return 0; }; // Drop not supported.
+ virtual bool do_execute(THD *thd);
+
+private:
+ virtual bool do_serialize(THD *thd, String *serialization);
+ // These attributes are to be used only for materialization.
+ String m_grant_stmt;
+};
+
+/**
+ @class TblGrantObj
+
+ This class provides an abstraction to table-level and routine-level grants.
+ This class will permit the recording and replaying of these
+ grants.
+*/
+class TblGrantObj : public DbGrantObj
+{
+public:
+ TblGrantObj(const String *grantee,
+ const String *db_name,
+ const String *table_name,
+ const String *priv_type);
+
+public:
+
+ const String *get_table_name()
+ {
+ return &m_table_name;
+ }
+
+protected:
+ // These attributes are to be used only for serialization.
+ String m_table_name; ///< corresponds with TABLE_NAME in IS tables.
+
+
+private:
+ virtual bool do_serialize(THD *thd, String *serialization);
+
+ // These attributes are to be used only for materialization.
+ String m_grant_stmt;
+};
+
+/**
+ @class ColGrantObj
+
+ This class provides an abstraction to column-level grants.
+ This class will permit the recording and replaying of these
+ grants.
+*/
+class ColGrantObj : public TblGrantObj
+{
+public:
+ ColGrantObj(const String *grantee,
+ const String *db_name,
+ const String *table_name,
+ const String *col_name,
+ const String *priv_type);
+
+public:
+
+ const String *get_col_name()
+ {
+ return &m_col_name;
+ }
+
+protected:
+ // These attributes are to be used only for serialization.
+ String m_col_name; ///< corresponds with COLUMN_NAME in IS tables.
+
+private:
+ virtual bool do_serialize(THD *thd, String *serialization);
+
+ // These attributes are to be used only for materialization.
+ String m_grant_stmt;
+};
+
///////////////////////////////////////////////////////////////////////////
//
@@ -938,6 +1055,67 @@ private:
String m_db_name;
};
+class DbGrantIterator : public InformationSchemaIterator
+{
+public:
+ DbGrantIterator(THD *thd,
+ const String *db_name,
+ TABLE *is_table,
+ handler *ha,
+ my_bitmap_map *orig_columns) :
+ InformationSchemaIterator(thd, is_table, ha, orig_columns)
+ {
+ m_db_name.copy(*db_name);
+ }
+
+protected:
+ virtual DbGrantObj *create_obj(TABLE *t);
+
+private:
+ String m_db_name;
+};
+
+class TblGrantIterator : public InformationSchemaIterator
+{
+public:
+ TblGrantIterator(THD *thd,
+ const String *db_name,
+ TABLE *is_table,
+ handler *ha,
+ my_bitmap_map *orig_columns) :
+ InformationSchemaIterator(thd, is_table, ha, orig_columns)
+ {
+ m_db_name.copy(*db_name);
+ }
+
+protected:
+ virtual TblGrantObj *create_obj(TABLE *t);
+
+private:
+ String m_db_name;
+};
+
+class ColGrantIterator : public InformationSchemaIterator
+{
+public:
+ ColGrantIterator(THD *thd,
+ const String *db_name,
+ TABLE *is_table,
+ handler *ha,
+ my_bitmap_map *orig_columns) :
+ InformationSchemaIterator(thd, is_table, ha, orig_columns)
+ {
+ m_db_name.copy(*db_name);
+ }
+
+protected:
+ virtual ColGrantObj *create_obj(TABLE *t);
+
+private:
+ String m_db_name;
+};
+
+
///////////////////////////////////////////////////////////////////////////
class DbStoredFuncIterator : public DbStoredProcIterator
@@ -1055,6 +1233,24 @@ bool InformationSchemaIterator::prepare_
*is_table= open_schema_table(thd, st, NULL);
break;
}
+ case SCH_SCHEMA_PRIVILEGES:
+ {
+ st= find_schema_table(thd, "SCHEMA_PRIVILEGES");
+ *is_table= open_schema_table(thd, st, NULL);
+ break;
+ }
+ case SCH_TABLE_PRIVILEGES:
+ {
+ st= find_schema_table(thd, "TABLE_PRIVILEGES");
+ *is_table= open_schema_table(thd, st, NULL);
+ break;
+ }
+ case SCH_COLUMN_PRIVILEGES:
+ {
+ st= find_schema_table(thd, "COLUMN_PRIVILEGES");
+ *is_table= open_schema_table(thd, st, NULL);
+ break;
+ }
default:
{
st= get_schema_table(is_table_idx);
@@ -1320,6 +1516,123 @@ EventObj *DbEventIterator::create_obj(TA
return new EventObj(&db_name, &event_name);
}
#endif
+
+///////////////////////////////////////////////////////////////////////////
+
+//
+// Implementation: DbGrantIterator class.
+//
+
+///////////////////////////////////////////////////////////////////////////
+
+DbGrantObj* DbGrantIterator::create_obj(TABLE *t)
+{
+ String grantee; // corresponds with GRANTEE
+ String db_name; // corresponds with TABLE_SCHEMA
+ String priv_type; // corresponds with PRIVILEGE_TYPE
+
+ t->field[0]->val_str(&grantee);
+ t->field[2]->val_str(&db_name);
+ t->field[3]->val_str(&priv_type);
+
+ /*
+ The fill method for SCHEMA_PRIVILEGES does not use the COND portion
+ of the generic fill() method. Thus, we have to do the restriction here.
+
+ Ensure the only rows sent back from iterator are the ones that match the
+ database specified.
+ */
+ if (db_name == m_db_name)
+ {
+ DBUG_PRINT("DbGrantIterator::create", (" Found grant %s %s %s",
+ db_name.ptr(), grantee.ptr(), priv_type.ptr()));
+
+ return new DbGrantObj(&grantee, &db_name, &priv_type);
+ }
+ else
+ return NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+//
+// Implementation: TblGrantIterator class.
+//
+
+///////////////////////////////////////////////////////////////////////////
+
+TblGrantObj* TblGrantIterator::create_obj(TABLE *t)
+{
+ String grantee; // corresponds with GRANTEE
+ String db_name; // corresponds with TABLE_SCHEMA
+ String tbl_name; // corresponds with TABLE_NAME
+ String priv_type; // corresponds with PRIVILEGE_TYPE
+
+ t->field[0]->val_str(&grantee);
+ t->field[2]->val_str(&db_name);
+ t->field[3]->val_str(&tbl_name);
+ t->field[4]->val_str(&priv_type);
+
+ /*
+ The fill method for TABLE_PRIVILEGES does not use the COND portion
+ of the generic fill() method. Thus, we have to do the restriction here.
+
+ Ensure the only rows sent back from iterator are the ones that match the
+ database specified.
+ */
+ if (db_name == m_db_name)
+ {
+ DBUG_PRINT("TblGrantIterator::create", (" Found grant %s %s %s %s",
+ db_name.ptr(), grantee.ptr(), tbl_name.ptr(), priv_type.ptr()));
+
+ return new TblGrantObj(&grantee, &db_name, &tbl_name, &priv_type);
+ }
+ else
+ return NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+//
+// Implementation: ColGrantIterator class.
+//
+
+///////////////////////////////////////////////////////////////////////////
+
+ColGrantObj* ColGrantIterator::create_obj(TABLE *t)
+{
+ String grantee; // corresponds with GRANTEE
+ String db_name; // corresponds with TABLE_SCHEMA
+ String tbl_name; // corresponds with TABLE_NAME
+ String col_name; // corresponds with COLUMN_NAME
+ String priv_type; // corresponds with PRIVILEGE_TYPE
+
+ t->field[0]->val_str(&grantee);
+ t->field[2]->val_str(&db_name);
+ t->field[3]->val_str(&tbl_name);
+ t->field[4]->val_str(&col_name);
+ t->field[5]->val_str(&priv_type);
+
+ /*
+ The fill method for COLUMN_PRIVILEGES does not use the COND portion
+ of the generic fill() method. Thus, we have to do the restriction here.
+
+ Ensure the only rows sent back from iterator are the ones that match the
+ database specified.
+ */
+ if (db_name == m_db_name)
+ {
+ DBUG_PRINT("ColGrantIterator::create", (" Found grant %s %s %s %s %s",
+ db_name.ptr(), grantee.ptr(), tbl_name.ptr(), col_name.ptr(),
+ priv_type.ptr()));
+
+ return new ColGrantObj(&grantee, &db_name, &tbl_name,
+ &col_name, &priv_type);
+ }
+ else
+ return NULL;
+}
+
///////////////////////////////////////////////////////////////////////////
//
@@ -1502,6 +1815,18 @@ DbEventIterator *
create_is_iterator<DbEventIterator>(THD *, enum_schema_tables, const String *);
#endif
+template
+DbGrantIterator *
+create_is_iterator<DbGrantIterator>(THD *, enum_schema_tables, const String *);
+
+template
+TblGrantIterator *
+create_is_iterator<TblGrantIterator>(THD *, enum_schema_tables, const String *);
+
+template
+ColGrantIterator *
+create_is_iterator<ColGrantIterator>(THD *, enum_schema_tables, const String *);
+
ObjIterator *get_db_tables(THD *thd, const String *db_name)
{
return create_is_iterator<DbTablesIterator>(thd, SCH_TABLES, db_name);
@@ -1536,6 +1861,56 @@ ObjIterator *get_db_events(THD *thd, con
#endif
}
+/**
+ GrantObjIterator constructor
+
+ This constructor initializes iterators for the grants supported.
+ These include database-, table- and routine-, and column-level grants.
+ The iterators return all of the grants for the database specified.
+*/
+GrantObjIterator::GrantObjIterator(THD *thd, const String *db_name)
+: ObjIterator()
+{
+ db_grants= create_is_iterator<DbGrantIterator>(thd,
+ SCH_SCHEMA_PRIVILEGES,
+ db_name);
+ tbl_grants= create_is_iterator<TblGrantIterator>(thd,
+ SCH_TABLE_PRIVILEGES,
+ db_name);
+ col_grants= create_is_iterator<ColGrantIterator>(thd,
+ SCH_COLUMN_PRIVILEGES,
+ db_name);
+}
+
+Obj *GrantObjIterator::next()
+{
+ Obj *obj= 0;
+ obj= db_grants->next();
+ if (!obj)
+ obj= tbl_grants->next();
+ if (!obj)
+ obj= col_grants->next();
+ return obj;
+}
+
+/**
+ Creates a high-level iterator that iterates over database-, table-,
+ routine-, and column-level privileges which shall permit a single
+ iterator from the si_objects to retrieve all of the privileges for
+ a given database.
+
+ @param[IN] thd Current THD object
+ @param[IN] db_name Name of database to get grants
+
+ @Note The client is responsible for destroying the returned iterator.
+
+ @return a pointer to an iterator object.
+ @retval NULL in case of error.
+*/
+ObjIterator *get_all_db_grants(THD *thd, const String *db_name)
+{
+ return new GrantObjIterator(thd, db_name);
+}
///////////////////////////////////////////////////////////////////////////
@@ -2581,6 +2956,191 @@ bool TablespaceObj::do_execute(THD *thd)
}
///////////////////////////////////////////////////////////////////////////
+//
+// Implementation: DbGrantObj class.
+//
+/////////////////////////////////////////////////////////////////////////////
+
+DbGrantObj::DbGrantObj(const String *grantee,
+ const String *db_name,
+ const String *priv_type)
+{
+ // copy strings to newly allocated memory
+ m_db_name.copy(*db_name);
+ m_grantee.copy(*grantee);
+ m_name.copy(*grantee);
+ m_priv_type.copy(*priv_type);
+}
+
+/**
+ Serialize the object.
+
+ This method produces the data necessary for materializing the object
+ on restore (creates object).
+
+ @param[in] thd Thread context.
+ @param[out] serialization The data needed to recreate this object.
+
+ @note this method will return an error if the db_name is either
+ mysql or information_schema as these are not objects that
+ should be recreated using this interface.
+
+ @returns Error status.
+ @retval FALSE on success
+ @retval TRUE on error
+*/
+bool DbGrantObj::do_serialize(THD *thd, String *serialization)
+{
+ DBUG_ENTER("DbGrantObj::do_serialize()");
+ serialization->length(0);
+ serialization->append("GRANT ");
+ serialization->append(m_priv_type);
+ serialization->append(" ON ");
+ serialization->append(m_db_name);
+ serialization->append(".* TO ");
+ serialization->append(m_grantee);
+ DBUG_RETURN(0);
+}
+
+/**
+ Materialize the serialization string.
+
+ This method saves serialization string into a member variable.
+
+ @param[in] serialization_version version number of this interface
+ @param[in] serialization the string from serialize()
+
+ @todo take serialization_version into account
+
+ @returns Error status.
+ @retval FALSE on success
+ @retval TRUE on error
+*/
+bool DbGrantObj::materialize(uint serialization_version,
+ const String *serialization)
+{
+ DBUG_ENTER("DbGrantObj::materialize()");
+ m_grant_stmt.copy(*serialization);
+ DBUG_RETURN(0);
+}
+
+/**
+ Create the object.
+
+ This method uses serialization string in a query and executes it.
+
+ @param[in] thd Thread context.
+
+ @returns Error status.
+ @retval FALSE on success
+ @retval TRUE on error
+*/
+bool DbGrantObj::do_execute(THD *thd)
+{
+ DBUG_ENTER("DbGrantObj::do_execute()");
+ DBUG_RETURN(execute_with_ctx(thd, &m_grant_stmt, true));
+}
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Implementation: TblGrantObj class.
+//
+/////////////////////////////////////////////////////////////////////////////
+
+TblGrantObj::TblGrantObj(const String *grantee,
+ const String *db_name,
+ const String *table_name,
+ const String *priv_type)
+: DbGrantObj(grantee, db_name, priv_type)
+{
+ // copy strings to newly allocated memory
+ m_table_name.copy(*table_name);
+}
+
+/**
+ Serialize the object.
+
+ This method produces the data necessary for materializing the object
+ on restore (creates object).
+
+ @param[in] thd Thread context.
+ @param[out] serialization The data needed to recreate this object.
+
+ @note this method will return an error if the db_name is either
+ mysql or information_schema as these are not objects that
+ should be recreated using this interface.
+
+ @returns Error status.
+ @retval FALSE on success
+ @retval TRUE on error
+*/
+bool TblGrantObj::do_serialize(THD *thd, String *serialization)
+{
+ DBUG_ENTER("TblGrantObj::do_serialize()");
+ serialization->length(0);
+ serialization->append("GRANT ");
+ serialization->append(m_priv_type);
+ serialization->append(" ON ");
+ serialization->append(m_db_name);
+ serialization->append(".");
+ serialization->append(m_table_name);
+ serialization->append(" TO ");
+ serialization->append(m_grantee);
+ DBUG_RETURN(0);
+}
+
+///////////////////////////////////////////////////////////////////////////
+//
+// Implementation: ColGrantObj class.
+//
+/////////////////////////////////////////////////////////////////////////////
+
+ColGrantObj::ColGrantObj(const String *grantee,
+ const String *db_name,
+ const String *table_name,
+ const String *col_name,
+ const String *priv_type)
+: TblGrantObj(grantee, db_name, table_name, priv_type)
+{
+ // copy strings to newly allocated memory
+ m_col_name.copy(*col_name);
+}
+
+/**
+ Serialize the object.
+
+ This method produces the data necessary for materializing the object
+ on restore (creates object).
+
+ @param[in] thd Thread context.
+ @param[out] serialization The data needed to recreate this object.
+
+ @note this method will return an error if the db_name is either
+ mysql or information_schema as these are not objects that
+ should be recreated using this interface.
+
+ @returns Error status.
+ @retval FALSE on success
+ @retval TRUE on error
+*/
+bool ColGrantObj::do_serialize(THD *thd, String *serialization)
+{
+ DBUG_ENTER("ColGrantObj::do_serialize()");
+ serialization->length(0);
+ serialization->append("GRANT ");
+ serialization->append(m_priv_type);
+ serialization->append("(");
+ serialization->append(m_col_name);
+ serialization->append(") ON ");
+ serialization->append(m_db_name);
+ serialization->append(".");
+ serialization->append(m_table_name);
+ serialization->append(" TO ");
+ serialization->append(m_grantee);
+ DBUG_RETURN(0);
+}
+
+///////////////////////////////////////////////////////////////////////////
Obj *get_database(const String *db_name)
{
@@ -2718,6 +3278,33 @@ Obj *materialize_tablespace(const String
return obj;
}
+Obj *get_db_grant(const String *grantee,
+ const String *db_name)
+{
+ String priv_type;
+ priv_type.length(0);
+
+ return new DbGrantObj(grantee, db_name, &priv_type);
+}
+
+Obj *materialize_db_grant(const String *db_name,
+ const String *grantee,
+ uint serialization_version,
+ const String *serialization)
+{
+ /*
+ Here we create a grant for the purposes of applying the
+ grants. We use DbGrantObj for all types of grants because
+ we only have the GRANT statement in the serialization
+ string and therefore do not that the 'parts' to create
+ the specific types.
+ */
+ Obj *obj= get_db_grant(grantee, db_name);
+ obj->materialize(serialization_version, serialization);
+
+ return obj;
+}
+
///////////////////////////////////////////////////////////////////////////
bool is_internal_db_name(const String *db_name)
@@ -2739,6 +3326,76 @@ bool is_internal_db_name(const String *d
bool check_db_existence(const String *db_name)
{
return check_db_dir_existence(((String *) db_name)->c_ptr_safe());
+}
+
+/*
+ Splits grantee clause into user and host portions. Needed for checking
+ to see if user exists on system.
+*/
+int split_user_host(String *grantee, String *user, String *host)
+{
+ int len= 0;
+ int tics= 0;
+ char *ptr= strchr(grantee->c_ptr(), '@');
+
+ if (ptr == 0)
+ return -1;
+ len= ptr - grantee->c_ptr();
+ user->length(0);
+ char *cptr= grantee->c_ptr();
+
+ /*
+ String ' from strings.
+ */
+ if (strncmp(cptr, "'", 1) == 0)
+ {
+ cptr++;
+ len--;
+ tics++;
+ }
+ user->append(cptr, len - tics);
+ len= grantee->length() - len - 1 - tics;
+ host->length(0);
+
+ /*
+ String ' from strings.
+ */
+ cptr= ptr + 1;
+ tics= 0;
+ if (strncmp(cptr, "'", 1) == 0)
+ {
+ cptr++;
+ len--;
+ }
+ if (strncmp(cptr+len-1, "'", 1) == 0)
+ tics++;
+ host->append(cptr, len - tics);
+ return 0;
+}
+
+/*
+ Returns TRUE if user is defined on the system.
+*/
+bool user_exists(THD *thd, const String *grantee)
+{
+ String user;
+ String host;
+ bool user_exists= FALSE;
+
+ user.length(0);
+ host.length(0);
+ if (grantee)
+ {
+#ifndef EMBEDDED_LIBRARY
+ split_user_host((String *)grantee, &user, &host);
+ if (!user.ptr())
+ user.append("''");
+ user_exists= is_acl_user(host.ptr(), user.ptr());
+#else
+ user_exists= TRUE;
+#endif
+ }
+ return user_exists;
}
/**
=== modified file 'sql/si_objects.h'
--- a/sql/si_objects.h 2008-07-05 08:41:26 +0000
+++ b/sql/si_objects.h 2008-08-07 14:53:39 +0000
@@ -115,6 +115,12 @@ private:
friend Obj *materialize_tablespace(const String *,
uint,
const String *);
+
+ friend Obj *materialize_db_grant(const String *,
+ const String *,
+ uint,
+ const String *);
+
};
@@ -222,6 +228,39 @@ public:
};
+/**
+ GrantObjIternator is an encapsulation of the three iterators for each level
+ of grant supported: database-, table- and routine-, and column-level.
+*/
+class GrantObjIterator : public ObjIterator
+{
+public:
+ GrantObjIterator(THD *thd, const String *db_name);
+
+ ~GrantObjIterator()
+ {
+ delete db_grants;
+ delete tbl_grants;
+ delete col_grants;
+ }
+
+ /**
+ This operation returns a pointer to the next object in an enumeration.
+ It returns NULL if there is no more objects.
+
+ The client is responsible to destroy the returned object.
+
+ @return a pointer to the object
+ @retval NULL if there is no more objects in an enumeration.
+ */
+ Obj *next();
+
+private:
+ ObjIterator *db_grants; ///< database-level grants
+ ObjIterator *tbl_grants; ///< table- and routine-level grants
+ ObjIterator *col_grants; ///< column-level grants
+};
+
///////////////////////////////////////////////////////////////////////////
// The functions in this section are intended to construct an instance of
@@ -429,6 +468,14 @@ ObjIterator *get_db_stored_functions(THD
ObjIterator *get_db_events(THD *thd, const String *db_name);
+/*
+ Creates a high-level iterator that iterates over database-, table-,
+ routine-, and column-level privileges which shall permit a single
+ iterator from the si_objects to retrieve all of the privileges for
+ a given database.
+*/
+ObjIterator *get_all_db_grants(THD *thd, const String *db_name);
+
///////////////////////////////////////////////////////////////////////////
// The functions are intended to enumerate dependent objects.
@@ -506,6 +553,11 @@ Obj *materialize_tablespace(const String
uint serialization_version,
const String *serialialization);
+Obj *materialize_db_grant(const String *grantee,
+ const String *db_name,
+ uint serialization_version,
+ const String *serialization);
+
///////////////////////////////////////////////////////////////////////////
bool is_internal_db_name(const String *db_name);
@@ -520,6 +572,11 @@ bool is_internal_db_name(const String *d
@retval TRUE on error (the database either not exists, or not accessible).
*/
bool check_db_existence(const String *db_name);
+
+/*
+ Returns TRUE if user is defined on the system.
+*/
+bool user_exists(THD *thd, const String *grantee);
/*
This method returns a @c TablespaceObj object if the table has a tablespace.