MySQL Blog Archive
For the latest blogs go to blogs.oracle.com/mysql
Migrate Ownership of your stored routines, views and triggers for MySQL in 2021

Yesterday my friend and ex-colleague Sveta published a blog post on how to migrate ownership of stored routines, views and triggers in MySQL.

I usually agree a lot with her and even if I agree with what she wrote, there is one single point I would like to comment: use MySQL Shell !

In the blog post, Sveta recommends the use of mysqldump which I don’t. For any logical dump & load operations, I really recommend the use of MySQL Shell’s Dump & Load Utility ! It’s much faster, it has many nice options like hidden Primary Key creation, and is compatible with OCI.

And of course, MySQL Shell also provides a solution for the problem exposed in the blog post.

Let’s see MySQL Shell in action with the exact same example:

First, using my own user (fred), I create a database and a view:

mysql> create database definers;
mysql> use definers;
mysql> CREATE VIEW large_tables AS 
       SELECT * FROM information_schema.tables 
       WHERE DATA_LENGTH > 100000000;
mysql> SELECT DEFINER, TABLE_SCHEMA, TABLE_NAME 
       FROM information_schema.views 
       WHERE TABLE_NAME='large_tables';
 +---------+--------------+--------------+
 | DEFINER | TABLE_SCHEMA | TABLE_NAME   |
 +---------+--------------+--------------+
 | fred@%  | definers     | large_tables |
 +---------+--------------+--------------+

Now, I create the production user, for obvious security reasons, I assign a password to it:

mysql> CREATE USER production identified by '********';
mysql> GRANT ALL ON definers.* TO production@'%';
mysql> GRANT SESSION_VARIABLES_ADMIN ON <em>.</em> TO production@'%';

We can now dump the definers schema using MySQL Shell where I will use fred to connect:

[fred@imac ~] $ mysqlsh fred@localhost
MySQL  localhost:33060+   2021-07-08 07:41:47  
JS  util.dumpSchemas(['definers'], '/tmp/dump')
Acquiring global read lock
Global read lock acquired
Gathering information - done
All transactions have been started
Locking instance for backup
Global read lock has been released
Writing global DDL files
Running data dump using 4 threads.
NOTE: Progress information uses estimated values and may not be accurate.
Writing DDL for schema definers
Writing DDL for view definers.large_tables
?% (0 rows / ?), 0.00 rows/s, 0.00 B/s uncompressed, 0.00 B/s compressed
Duration: 00:00:00s 
Schemas dumped: 1 
Tables dumped: 0 
Uncompressed data size: 0 bytes 
Compressed data size: 0 bytes 
Compression ratio: 0.0 
Rows written: 0 
Bytes written: 0 bytes 
Average uncompressed throughput: 0.00 B/s 
Average compressed throughput: 0.00 B/s

And now I will load it (the view needs to be removed first if you load it on the same server) using the production user:

[fred@imac ~] $ mysqlsh production@localhost
MySQL  localhost:33060+   2021-07-08 07:42:53 
JS  util.loadDump('/tmp/dump')
Loading DDL and Data from '/tmp/dump' using 4 threads.
Opening dump…
Target is MySQL 8.0.25. Dump was produced from MySQL 8.0.25
Checking for pre-existing objects…
Executing common preamble SQL
Executing DDL script for schema definers
[Worker002] Executing DDL script for definers.large_tables (placeholder for view)
Executing DDL script for view definers.large_tables
ERROR: Error executing DDL script for view definers.large_tables: MySQL Error 1227 (42000): Access denied; you need (at least one of) the SUPER or SET_USER_ID privilege(s) for this operation: /*!50001 CREATE ALGORITHM=UNDEFINED DEFINER=fred@% SQL SECURITY DEFINER VIEW large_tables AS select information_schema.tables.TABLE_CATALOG AS TABLE_CATALOG,information_schema.tables.TABLE_SCHEMA AS TABLE_SCHEMA,information_schema.tables.TABLE_NAME AS TABLE_NAME,information_schema.tables.TABLE_TYPE AS TABLE_TYPE,information_schema.tables.ENGINE AS ENGINE,information_schema.tables.VERSION AS VERSION,information_schema.tables.ROW_FORMAT AS ROW_FORMAT,information_schema.tables.TABLE_ROWS AS TABLE_ROWS,information_schema.tables.AVG_ROW_LENGTH AS AVG_ROW_LENGTH,information_schema.tables.DATA_LENGTH AS DATA_LENGTH,information_schema.tables.MAX_DATA_LENGTH AS MAX_DATA_LENGTH,information_schema.tables.INDEX_LENGTH AS INDEX_LENGTH,information_schema.tables.DATA_FREE AS DATA_FREE,information_schema.tables.AUTO_INCREMENT AS AUTO_INCREMENT,information_schema.tables.CREATE_TIME AS CREATE_TIME,information_schema.tables.UPDATE_TIME AS UPDATE_TIME,information_schema.tables.CHECK_TIME AS CHECK_TIME,information_schema.tables.TABLE_COLLATION AS TABLE_COLLATION,information_schema.tables.CHECKSUM AS CHECKSUM,information_schema.tables.CREATE_OPTIONS AS CREATE_OPTIONS,information_schema.tables.TABLE_COMMENT AS TABLE_COMMENT from information_schema.TABLES tables where (information_schema.tables.DATA_LENGTH > 100000000) */
<strong>Util.loadDump: Access denied; you need (at least one of) the SUPER or SET_USER_ID privilege(s) for this operation (MYSQLSH 1227)</strong>

As you can see, it failed the exact same way as it happened with mysqldump and this is because by default we don’t enable the strip_definers option.

Now we will do the dump again enabling the option this time:

JS  util.dumpSchemas(['definers'], '/tmp/dump', <strong>{compatibility:["strip_definers"]}</strong>)
Acquiring global read lock
Global read lock acquired
Gathering information - done
All transactions have been started
Locking instance for backup
Global read lock has been released
Writing global DDL files
Running data dump using 4 threads.
NOTE: Progress information uses estimated values and may not be accurate.
Writing DDL for schema definers
Writing DDL for view definers.large_tables
NOTE: View definers.large_tables had definer clause removed and SQL SECURITY characteristic set to INVOKER
 ?% (0 rows / ?), 0.00 rows/s, 0.00 B/s uncompressed, 0.00 B/s compressed
Duration: 00:00:00s 
Schemas dumped: 1 
Tables dumped: 0 
Uncompressed data size: 0 bytes 
Compressed data size: 0 bytes 
Compression ratio: 0.0 
Rows written: 0 
Bytes written: 0 bytes 
Average uncompressed throughput: 0.00 B/s 
Average compressed throughput: 0.00 B/s

And we can see that the dump is now working as expected:

JS  util.loadDump('/tmp/dump')
Loading DDL and Data from '/tmp/dump' using 4 threads.
Opening dump…
Target is MySQL 8.0.25. Dump was produced from MySQL 8.0.25
Checking for pre-existing objects…
Executing common preamble SQL
Executing DDL script for schema definers
[Worker002] Executing DDL script for definers.large_tables (placeholder for view)
Executing DDL script for view definers.large_tables
Executing common postamble SQL               
No data loaded.
0 warnings were reported during the load.

And if we check the definer this time of the loaded view:

mysql> SELECT DEFINER, TABLE_SCHEMA, TABLE_NAME 
       FROM information_schema.views 
       WHERE TABLE_NAME='large_tables';
 +--------------+--------------+--------------+
 | DEFINER      | TABLE_SCHEMA | TABLE_NAME   |
 +--------------+--------------+--------------+
 | production@% | definers     | large_tables |
 +--------------+--------------+--------------+
 1 row in set (0.00 sec)

As you can see, MySQL Shell Dump & Load Utility is the way to go for any logical dump and load: faster and powerful !

Thank you for using MySQL !