From: Date: December 2 2008 1:06pm Subject: bzr commit into mysql-6.0-runtime branch (alik:2756) WL#4264 List-Archive: http://lists.mysql.com/commits/60372 Message-Id: <20081202120650.072CB1D48F3@quad.opbmk> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit #At file:///mnt/raid/alik/MySQL/bzr/wl4264/6.0-rt-wl4264/ 2756 Alexander Nozdrin 2008-12-02 [merge] Patch for WL#4264: Backup: Stabilize Service Interface. This patch consists of two major parts: - Implementing "execute direct" technique -- a way to execute arbitrary SQL statement from within the server and get the results without involving transport layer. - Implementing Service Interface on top of the execute direct technique. modified: libmysql/libmysql.c mysql-test/suite/backup/r/backup_db_grants.result mysql-test/suite/backup/r/backup_errors.result mysql-test/suite/backup/r/backup_lock_myisam.result mysql-test/suite/backup/r/backup_views.result mysql-test/suite/backup/t/backup_db_grants.test mysql-test/suite/backup/t/backup_errors.test mysql-test/suite/backup/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.h sql/backup/kernel.cc sql/backup/logger.cc sql/debug_sync.cc sql/mysql_priv.h sql/mysql_priv.h.pp sql/protocol.cc sql/protocol.h sql/share/errmsg.txt sql/si_objects.cc sql/si_objects.h sql/sql_cache.cc sql/sql_error.h sql/sql_lex.cc sql/sql_lex.h sql/sql_prepare.cc sql/sql_string.h sql/sql_yacc.yy per-file messages: libmysql/libmysql.c Preserve error message. mysql-test/suite/backup/r/backup_db_grants.result Update result file. mysql-test/suite/backup/r/backup_errors.result Update result file. mysql-test/suite/backup/r/backup_lock_myisam.result Update result file. mysql-test/suite/backup/r/backup_views.result Update result file. mysql-test/suite/backup/t/backup_db_grants.test Add additional check to the test case. mysql-test/suite/backup/t/backup_errors.test Error code has been changed. mysql-test/suite/backup/t/backup_views.test Error code has been changed. sql/backup/backup_aux.h Remove unused defines. sql/backup/backup_info.cc Use new SI. sql/backup/backup_info.h Use new SI. sql/backup/backup_test.cc Use new SI. sql/backup/image_info.h Use new SI. sql/backup/kernel.cc Use new SI. sql/backup/logger.cc Fix a subtle bug: if a warning or an error contained '%', the log output was invalid. sql/debug_sync.cc Eliminate compiler warning. sql/mysql_priv.h Introduce execute direct technique: - Server_runnable -- an "executable" inteface. - mysql_execute_direct() -- functions to execute arbitrary code in the current THD context with proper cleanup. sql/mysql_priv.h.pp Update mysql_priv.h.pp. sql/protocol.cc In order to support getting results in mysql_execute_direct() the following classes were added: - Protocol_local - Protocol_void - Ed_result - Ed_result_set - Ed_result_set_metadata - Ed_row - Ed_column sql/protocol.h In order to support getting results in mysql_execute_direct() the following classes were added: - Protocol_local - Protocol_void - Ed_result - Ed_result_set - Ed_result_set_metadata - Ed_row - Ed_column sql/share/errmsg.txt Update error message. sql/si_objects.cc Refactor SI implementation basing on mysql_execute_direct(). sql/si_objects.h Refactor SI implementation basing on mysql_execute_direct(). sql/sql_cache.cc Support execute direct technique. sql/sql_error.h Remove default constructor. Warning_info must be initialized properly. sql/sql_lex.cc Introduce a new flag -- multi_statement. It determines if multiple statements are allowed in the input. stmt_prepare_mode flag was used previously for that purpose. However, after introduction of mysql_execute_direct() (which is not a prepare statement, but multiple statements are prohibitted) that needs to be changed. sql/sql_prepare.cc Implement execute direct technique. sql/sql_string.h Add an utility method. sql/sql_yacc.yy Introduce a new flag -- multi_statement. It determines if multiple statements are allowed in the input. stmt_prepare_mode flag was used previously for that purpose. However, after introduction of mysql_execute_direct() (which is not a prepare statement, but multiple statements are prohibitted) that needs to be changed. === modified file 'libmysql/libmysql.c' --- a/libmysql/libmysql.c 2008-10-22 11:51:28 +0000 +++ b/libmysql/libmysql.c 2008-11-19 16:32:01 +0000 @@ -4863,7 +4863,10 @@ int STDCALL mysql_stmt_next_result(MYSQL rc= mysql_next_result(mysql); if (rc) + { + set_stmt_errmsg(stmt, &mysql->net); DBUG_RETURN(rc); + } stmt->state= MYSQL_STMT_EXECUTE_DONE; stmt->bind_result_done= FALSE; === modified file 'mysql-test/suite/backup/r/backup_db_grants.result' --- a/mysql-test/suite/backup/r/backup_db_grants.result 2008-10-07 17:15:44 +0000 +++ b/mysql-test/suite/backup/r/backup_db_grants.result 2008-11-19 16:32:01 +0000 @@ -63,10 +63,31 @@ GRANT USAGE ON *.* 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 '%' Run Restore RESTORE FROM 'bup_db_grants.bak'; backup_id # +Warnings: +# 1737 The grant 'ALTER ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'ALTER ROUTINE ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'CREATE ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'CREATE ROUTINE ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'CREATE TEMPORARY TABLES ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'CREATE VIEW ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'DELETE ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'DROP ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'EVENT ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'EXECUTE ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'INDEX ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'INSERT ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'LOCK TABLES ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'REFERENCES ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'SELECT ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'SHOW VIEW ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'TRIGGER ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'UPDATE ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. SHOW TABLES FROM bup_db_grants; Tables_in_bup_db_grants s1 @@ -99,6 +120,28 @@ Run Restore RESTORE FROM 'bup_db_grants.bak'; backup_id # +Warnings: +# 1737 The grant 'INSERT ON bup_db_grants.*' for the user 'bup_user2'@'%' was skipped because the user does not exist. +# 1737 The grant 'INSERT(b) ON bup_db_grants.s1' for the user 'bup_user2'@'%' was skipped because the user does not exist. +# 1737 The grant 'SELECT(b) ON bup_db_grants.s1' for the user 'bup_user2'@'%' was skipped because the user does not exist. +# 1737 The grant 'ALTER ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'ALTER ROUTINE ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'CREATE ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'CREATE ROUTINE ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'CREATE TEMPORARY TABLES ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'CREATE VIEW ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'DELETE ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'DROP ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'EVENT ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'EXECUTE ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'INDEX ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'INSERT ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'LOCK TABLES ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'REFERENCES ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'SELECT ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'SHOW VIEW ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'TRIGGER ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. +# 1737 The grant 'UPDATE ON bup_db_grants.*' for the user 'no_user'@'%' was skipped because the user does not exist. SHOW TABLES FROM bup_db_grants; Tables_in_bup_db_grants s1 === modified file 'mysql-test/suite/backup/r/backup_errors.result' --- a/mysql-test/suite/backup/r/backup_errors.result 2008-10-07 17:15:44 +0000 +++ b/mysql-test/suite/backup/r/backup_errors.result 2008-11-19 16:32:01 +0000 @@ -110,7 +110,7 @@ delete database files so that check_db_d si_objects.cc @ DatabaseObj::do_serialize SET DEBUG_SYNC='now SIGNAL db_will_fail'; Database has been deleted, backup will fail -ERROR 42000: Unknown database 'db1' +ERROR HY000: Failed to obtain meta-data for database `db1` Test that backup fails with error if a table used by a trigger cannot be opened === modified file 'mysql-test/suite/backup/r/backup_lock_myisam.result' --- a/mysql-test/suite/backup/r/backup_lock_myisam.result 2008-10-07 17:15:44 +0000 +++ b/mysql-test/suite/backup/r/backup_lock_myisam.result 2008-11-28 21:35:11 +0000 @@ -61,6 +61,10 @@ SET DEBUG_SYNC= 'now WAIT_FOR wait_for_r breakpoints: Show process list. SELECT id, command, state, info FROM INFORMATION_SCHEMA.PROCESSLIST WHERE info LIKE "RESTORE%"; +id # +command Query +state debug sync point: restore_in_progress +info RESTORE FROM 'db1.bak' From con2: Now do the insert while restore is running. INSERT INTO db2.t2 VALUES (0); @@ -99,6 +103,10 @@ SET DEBUG_SYNC= 'now WAIT_FOR wait_for_r breakpoints: Show process list. SELECT id, command, state, info FROM INFORMATION_SCHEMA.PROCESSLIST WHERE info LIKE "RESTORE%"; +id # +command Query +state debug sync point: restore_in_progress +info RESTORE FROM 'db1.bak' From con2: Now do the select while restore is running. SELECT * FROM db1.t1 limit 10; === modified file 'mysql-test/suite/backup/r/backup_views.result' --- a/mysql-test/suite/backup/r/backup_views.result 2008-10-07 17:15:44 +0000 +++ b/mysql-test/suite/backup/r/backup_views.result 2008-11-26 13:46:42 +0000 @@ -584,7 +584,7 @@ Testing view selecting from altered view SELECT * FROM alter2; ERROR HY000: View 'bup_db1.alter2' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them BACKUP DATABASE bup_db1 TO 'bup_alterview.bak'; -ERROR HY000: View 'bup_db1.alter2' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +ERROR HY000: Failed to obtain meta-data for view `bup_db1`.`alter2` *** EXIT Backup of database with altered view === modified file 'mysql-test/suite/backup/t/backup_db_grants.test' --- a/mysql-test/suite/backup/t/backup_db_grants.test 2008-10-07 17:15:44 +0000 +++ b/mysql-test/suite/backup/t/backup_db_grants.test 2008-11-19 16:32:01 +0000 @@ -60,6 +60,8 @@ FLUSH PRIVILEGES; 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 Run Restore --replace_column 1 # === modified file 'mysql-test/suite/backup/t/backup_errors.test' --- a/mysql-test/suite/backup/t/backup_errors.test 2008-10-07 17:15:44 +0000 +++ b/mysql-test/suite/backup/t/backup_errors.test 2008-11-19 16:32:01 +0000 @@ -251,7 +251,7 @@ SET DEBUG_SYNC='now SIGNAL db_will_fail' connection con2; --echo Database has been deleted, backup will fail ---error ER_BAD_DB_ERROR +--error ER_BACKUP_GET_META_DB reap; --echo === modified file 'mysql-test/suite/backup/t/backup_views.test' --- a/mysql-test/suite/backup/t/backup_views.test 2008-10-07 17:15:44 +0000 +++ b/mysql-test/suite/backup/t/backup_views.test 2008-11-26 13:46:42 +0000 @@ -353,7 +353,7 @@ ALTER VIEW alter1 AS SELECT 6; SELECT * FROM alter2; #fails ---error ER_VIEW_INVALID +--error ER_BACKUP_GET_META_VIEW BACKUP DATABASE bup_db1 TO 'bup_alterview.bak'; --echo === modified file 'sql/backup/backup_aux.h' --- a/sql/backup/backup_aux.h 2008-10-14 12:08:56 +0000 +++ b/sql/backup/backup_aux.h 2008-11-19 16:32:01 +0000 @@ -42,12 +42,6 @@ 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 "%08lu" - -/** 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-10-27 13:06:21 +0000 +++ b/sql/backup/backup_info.cc 2008-11-25 16:37:46 +0000 @@ -532,7 +532,7 @@ backup::Image_info::Db* Backup_info::add @returns 0 on success, error code otherwise. */ -int Backup_info::add_dbs(List< ::LEX_STRING > &dbs) +int Backup_info::add_dbs(THD *thd, List< ::LEX_STRING > &dbs) { using namespace obs; @@ -550,9 +550,9 @@ int Backup_info::add_dbs(List< ::LEX_STR goto error; } - obs::Obj *obj= get_database(&db_name); // reports errors + obs::Obj *obj= get_database_stub(&db_name); // reports errors - if (obj && !check_db_existence(&db_name)) + if (obj && !check_db_existence(thd, &db_name)) { if (!unknown_dbs.is_empty()) // we just compose unknown_dbs list { @@ -727,7 +727,7 @@ int Backup_info::add_db_items(Db &db) // If this table uses a tablespace, add this tablespace to the catalogue. - obj= get_tablespace_for_table(m_ctx.m_thd, &db.name(), &tbl->name()); + obj= find_tablespace_for_table(m_ctx.m_thd, &db.name(), &tbl->name()); if (obj) { @@ -1031,8 +1031,7 @@ Backup_info::add_db_object(Db &db, const ulong pos= db.obj_count(); DBUG_ASSERT(obj); - String *name= (String *)obj->get_name(); - DBUG_ASSERT(name); + DBUG_ASSERT(obj->get_name()); switch (type) { @@ -1052,22 +1051,6 @@ Backup_info::add_db_object(Db &db, const } - /* - 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. @@ -1078,11 +1061,11 @@ Backup_info::add_db_object(Db &db, const // Get a dep. list node for the object. - int res= get_dep_node(db.name(), *name, type, n); + int res= get_dep_node(db.name(), *obj->get_name(), type, n); if (res == get_dep_node_res::ERROR) { - m_ctx.fatal_error(error, db.name().ptr(), name->ptr()); + m_ctx.fatal_error(error, db.name().ptr(), obj->get_name()->ptr()); return NULL; } @@ -1097,7 +1080,7 @@ Backup_info::add_db_object(Db &db, const if (type == BSTREAM_IT_VIEW) if (add_view_deps(*obj)) { - m_ctx.fatal_error(error, db.name().ptr(), name->ptr()); + m_ctx.fatal_error(error, db.name().ptr(), obj->get_name()->ptr()); return NULL; } @@ -1114,11 +1097,11 @@ Backup_info::add_db_object(Db &db, const objects. */ - Dbobj *o= Image_info::add_db_object(db, type, *name, pos); + Dbobj *o= Image_info::add_db_object(db, type, *obj->get_name(), pos); if (!o) { - m_ctx.fatal_error(error, db.name().ptr(), name->ptr()); + m_ctx.fatal_error(error, db.name().ptr(), obj->get_name()->ptr()); return NULL; } @@ -1134,7 +1117,7 @@ Backup_info::add_db_object(Db &db, const n->obj= o; DBUG_PRINT("backup",("Added object %s of type %d from database %s (pos=%lu)", - name->ptr(), type, db.name().ptr(), pos)); + obj->get_name()->ptr(), type, db.name().ptr(), pos)); return o; } === modified file 'sql/backup/backup_info.h' --- a/sql/backup/backup_info.h 2008-10-27 13:06:21 +0000 +++ b/sql/backup/backup_info.h 2008-11-19 16:32:01 +0000 @@ -38,7 +38,7 @@ class Backup_info: public backup::Image_ bool is_valid(); - int add_dbs(List< ::LEX_STRING >&); + int add_dbs(THD *thd, List< ::LEX_STRING >&); int add_all_dbs(); int close(); === modified file 'sql/backup/backup_test.cc' --- a/sql/backup/backup_test.cc 2008-10-17 11:28:25 +0000 +++ b/sql/backup/backup_test.cc 2008-11-25 16:37:46 +0000 @@ -32,7 +32,7 @@ int execute_backup_test_command(THD *thd { String tmp_db_name("qqq", 3, system_charset_info); - DBUG_ASSERT(obs::check_db_existence(&tmp_db_name)); + DBUG_ASSERT(obs::check_db_existence(thd, &tmp_db_name)); } /* @@ -57,12 +57,12 @@ int execute_backup_test_command(THD *thd { String dir; dir.copy(dbname->str, dbname->length, system_charset_info); - db= get_database(&dir); + db= get_database_stub(&dir); if (is_internal_db_name(db->get_db_name())) continue; - DBUG_ASSERT(!obs::check_db_existence(db->get_db_name())); + DBUG_ASSERT(!obs::check_db_existence(thd, db->get_db_name())); // // List tables.. @@ -247,10 +247,7 @@ int execute_backup_test_command(THD *thd protocol->prepare_for_resend(); protocol->store(const_cast(db->get_name())); protocol->store(const_cast(grant->get_name())); - String user; - String host; - String *user_host= (String *)grant->get_name(); - check_user_existence(thd, user_host); + check_user_existence(thd, grant); protocol->store(C_STRING_WITH_LEN("GRANT"), system_charset_info); grant->serialize(thd, &serial); === modified file 'sql/backup/image_info.h' --- a/sql/backup/image_info.h 2008-10-15 15:38:28 +0000 +++ b/sql/backup/image_info.h 2008-11-25 16:37:46 +0000 @@ -1021,7 +1021,7 @@ inline obs::Obj* Image_info::Ts::materialize(uint ver, const ::String &sdata) { delete m_obj_ptr; - return m_obj_ptr= obs::materialize_tablespace(&m_name, ver, &sdata); + return m_obj_ptr= obs::get_tablespace(&m_name, ver, &sdata); } /// Implementation of @c Image_info::Obj virtual method. @@ -1029,7 +1029,7 @@ inline obs::Obj* Image_info::Db::materialize(uint ver, const ::String &sdata) { delete m_obj_ptr; - return m_obj_ptr= obs::materialize_database(&name(), ver, &sdata); + return m_obj_ptr= obs::get_database(&name(), ver, &sdata); } /// Implementation of @c Image_info::Obj virtual method. @@ -1037,7 +1037,7 @@ inline obs::Obj* Image_info::Table::materialize(uint ver, const ::String &sdata) { delete m_obj_ptr; - return m_obj_ptr= obs::materialize_table(&db().name(), &name(), ver, &sdata); + return m_obj_ptr= obs::get_table(&db().name(), &name(), ver, &sdata); } inline @@ -1050,31 +1050,23 @@ obs::Obj* Image_info::Dbobj::materialize switch (base.type) { case BSTREAM_IT_VIEW: - m_obj_ptr= obs::materialize_view(db_name, name, ver, &sdata); + m_obj_ptr= obs::get_view(db_name, name, ver, &sdata); break; case BSTREAM_IT_SPROC: - m_obj_ptr= obs::materialize_stored_procedure(db_name, name, ver, &sdata); + m_obj_ptr= obs::get_stored_procedure(db_name, name, ver, &sdata); break; case BSTREAM_IT_SFUNC: - m_obj_ptr= obs::materialize_stored_function(db_name, name, ver, &sdata); + m_obj_ptr= obs::get_stored_function(db_name, name, ver, &sdata); break; case BSTREAM_IT_EVENT: - m_obj_ptr= obs::materialize_event(db_name, name, ver, &sdata); + m_obj_ptr= obs::get_event(db_name, name, ver, &sdata); break; case BSTREAM_IT_TRIGGER: - m_obj_ptr= obs::materialize_trigger(db_name, name, ver, &sdata); + m_obj_ptr= obs::get_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); + m_obj_ptr= obs::get_db_grant(db_name, name, ver, &sdata); break; - } default: m_obj_ptr= NULL; } === modified file 'sql/backup/kernel.cc' --- a/sql/backup/kernel.cc 2008-11-18 19:41:51 +0000 +++ b/sql/backup/kernel.cc 2008-11-25 16:37:46 +0000 @@ -185,7 +185,8 @@ execute_backup_command(THD *thd, LEX *le else { context.write_message(log_level::INFO, "Backing up selected databases"); - res= info->add_dbs(lex->db_list); // backup databases specified by user + /* Backup databases specified by user. */ + res= info->add_dbs(thd, lex->db_list); } info->close(); // close catalogue after filling it with objects to backup @@ -1117,7 +1118,7 @@ int Backup_restore_ctx::restore_triggers case BSTREAM_IT_TRIGGER: DBUG_ASSERT(obj->m_obj_ptr); - if (obj->m_obj_ptr->execute(m_thd)) + if (obj->m_obj_ptr->create(m_thd)) { delete it; delete dbit; @@ -1140,7 +1141,7 @@ int Backup_restore_ctx::restore_triggers Image_info::Obj *ev; while ((ev= it++)) - if (ev->m_obj_ptr->execute(m_thd)) + if (ev->m_obj_ptr->create(m_thd)) { fatal_error(ER_BACKUP_CANT_RESTORE_EVENT,ev->describe(buf)); DBUG_RETURN(m_error); @@ -1905,24 +1906,30 @@ int bcat_create_item(st_bstream_image_he if (item->type == BSTREAM_IT_TABLESPACE) { - // if the tablespace exists, there is nothing more to do - if (obs::tablespace_exists(thd, sobj)) + Obj *ts= obs::find_tablespace(thd, sobj->get_name()); + + if (ts) { - DBUG_PRINT("restore",(" skipping tablespace which exists")); - return BSTREAM_OK; - } + /* + A tablespace with the same name exists. We have to check if other + attributes are the same as they were. + */ - /* - If there is a different tablespace with the same name then we can't - re-create the original tablespace used by tables being restored. We report - this and cancel restore process. - */ + if (obs::compare_tablespace_attributes(ts, sobj)) + { + /* The tablespace is the same. There is nothing more to do. */ + DBUG_PRINT("restore",(" skipping tablespace which exists")); + return BSTREAM_OK; + } - Obj *ts= obs::is_tablespace(thd, sobj); + /* + A tablespace with the same name exists, but it has been changed + since backup. We can't re-create the original tablespace used by + tables being restored. We report this and cancel restore process. + */ - if (ts) - { - DBUG_PRINT("restore",(" tablespace has changed on the server - aborting")); + DBUG_PRINT("restore", + (" tablespace has changed on the server - aborting")); info->m_ctx.fatal_error(ER_BACKUP_TS_CHANGE, desc); return BSTREAM_ERROR; } @@ -1943,12 +1950,13 @@ int bcat_create_item(st_bstream_image_he error handling work in WL#4384 with possible implementation via a related bug report. */ - if (!obs::check_user_existence(thd, sobj->get_name())) + if (!obs::check_user_existence(thd, sobj)) { - info->m_ctx.report_error(log_level::WARNING, + info->m_ctx.report_error(log_level::WARNING, ER_BACKUP_GRANT_SKIPPED, - create_stmt); - return BSTREAM_OK; + obs::grant_get_grant_info(sobj)->ptr(), + obs::grant_get_user_name(sobj)->ptr()); + return BSTREAM_OK; } /* We need to check the grant against the database list to ensure the @@ -1972,7 +1980,7 @@ int bcat_create_item(st_bstream_image_he } } - if (sobj->execute(thd)) + if (sobj->create(thd)) { info->m_ctx.fatal_error(create_err, desc); return BSTREAM_ERROR; === modified file 'sql/backup/logger.cc' --- a/sql/backup/logger.cc 2008-10-27 13:06:21 +0000 +++ b/sql/backup/logger.cc 2008-11-19 16:32:01 +0000 @@ -52,10 +52,10 @@ int Logger::write_message(log_level::val error.msg= sql_strdup(msg); } - sql_print_error(out); + sql_print_error("%s", out); if (m_push_errors) push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, - error_code, msg); + error_code, "%s", msg); DBUG_PRINT("backup_log",("[ERROR] %s", out)); if (m_state == READY || m_state == RUNNING) @@ -69,15 +69,15 @@ int Logger::write_message(log_level::val return 0; case log_level::WARNING: - sql_print_warning(out); + sql_print_warning("%s", out); if (m_push_errors) push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, - error_code, msg); + error_code, "%s", msg); DBUG_PRINT("backup_log",("[Warning] %s", out)); return 0; case log_level::INFO: - sql_print_information(out); + sql_print_information("%s", out); DBUG_PRINT("backup_log",("[Info] %s", out)); return 0; === modified file 'sql/debug_sync.cc' --- a/sql/debug_sync.cc 2008-09-08 09:25:46 +0000 +++ b/sql/debug_sync.cc 2008-11-20 11:01:12 +0000 @@ -832,7 +832,7 @@ static st_debug_sync_action *debug_sync_ /* Reuse an already active sync point action. */ DBUG_ASSERT((uint)(action - ds_control->ds_action) < ds_control->ds_active); DBUG_PRINT("debug_sync", ("reuse action idx: %ld", - action - ds_control->ds_action)); + (long) (action - ds_control->ds_action))); } else { === modified file 'sql/mysql_priv.h' --- a/sql/mysql_priv.h 2008-11-06 18:39:27 +0000 +++ b/sql/mysql_priv.h 2008-11-28 21:35:11 +0000 @@ -922,7 +922,7 @@ struct Query_cache_query_flags { unsigned int client_long_flag:1; unsigned int client_protocol_41:1; - unsigned int result_in_binary_protocol:1; + unsigned int protocol_type:2; unsigned int more_results_exists:1; unsigned int pkt_nr; uint character_set_client_num; @@ -1136,6 +1136,26 @@ void init_update_queries(void); void free_max_user_conn(void); pthread_handler_t handle_bootstrap(void *arg); int mysql_execute_command(THD *thd); + +class Ed_result; +/** + Execute a fragment of server code in an isolated context, so that + it doesn't leave any effect on THD. THD must have no open tables. + The code must not leave any open tables around. + The result of execution (if any) is stored in Ed_result. +*/ + +class Server_runnable +{ +public: + virtual bool execute_server_code(THD *thd)= 0; + virtual ~Server_runnable(); +}; + +bool mysql_execute_direct(THD *thd, LEX_STRING query, Ed_result *result); +bool mysql_execute_direct(THD *thd, Server_runnable *ed_runnable, + Ed_result *result); + bool do_command(THD *thd); bool dispatch_command(enum enum_server_command command, THD *thd, char* packet, uint packet_length); === modified file 'sql/mysql_priv.h.pp' --- a/sql/mysql_priv.h.pp 2008-07-11 13:08:06 +0000 +++ b/sql/mysql_priv.h.pp 2008-11-19 16:32:01 +0000 @@ -7672,7 +7672,6 @@ public: }; void send_warning(THD *thd, uint sql_errno, const char *err=0); void net_send_error(THD *thd, uint sql_errno=0, const char *err=0); -void net_end_statement(THD *thd); In_C_you_should_use_my_bool_instead() send_old_password_request(THD *thd); uchar *net_store_data(uchar *to,const uchar *from, size_t length); uchar *net_store_data(uchar *to,int32 from); === modified file 'sql/protocol.cc' --- a/sql/protocol.cc 2008-11-18 20:25:51 +0000 +++ b/sql/protocol.cc 2008-11-20 11:01:12 +0000 @@ -450,26 +450,26 @@ void Protocol::end_statement() switch (thd->main_da.status()) { case Diagnostics_area::DA_ERROR: /* The query failed, send error to log and abort bootstrap. */ - this->send_error(thd->main_da.sql_errno(), - thd->main_da.message()); + send_error(thd->main_da.sql_errno(), + thd->main_da.message()); break; case Diagnostics_area::DA_EOF: - this->send_eof(thd->main_da.server_status(), - thd->main_da.statement_warn_count()); + send_eof(thd->main_da.server_status(), + thd->main_da.statement_warn_count()); break; case Diagnostics_area::DA_OK: - this->send_ok(thd->main_da.server_status(), - thd->main_da.statement_warn_count(), - thd->main_da.affected_rows(), - thd->main_da.last_insert_id(), - thd->main_da.message()); + send_ok(thd->main_da.server_status(), + thd->main_da.statement_warn_count(), + thd->main_da.affected_rows(), + thd->main_da.last_insert_id(), + thd->main_da.message()); break; case Diagnostics_area::DA_DISABLED: break; case Diagnostics_area::DA_EMPTY: default: DBUG_ASSERT(0); - this->send_ok(thd->server_status, 0, 0, 0, NULL); + send_ok(thd->server_status, 0, 0, 0, NULL); break; } thd->main_da.is_sent= TRUE; @@ -858,7 +858,6 @@ bool Protocol::store(I_List* s return store((char*) tmp.ptr(), len, tmp.charset()); } - /**************************************************************************** Functions to handle the simple (default) protocol where everything is This protocol is the one that is used by default between the MySQL server @@ -1475,3 +1474,477 @@ bool Protocol_binary::send_out_parameter return FALSE; } + +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// + +Ed_result::Ed_result() : + m_current_result_set(NULL), + m_status(Diagnostics_area::DA_EMPTY), + m_server_status(0), + m_affected_rows(0), + m_last_insert_id(0), + m_sql_errno(0), + m_warning_info(0), + m_warning_info_saved(NULL) +{ + init_sql_alloc(&m_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0); + + m_message[0]= 0; +} + +/////////////////////////////////////////////////////////////////////////// + +Ed_result::~Ed_result() +{ + free_root(&m_mem_root, MYF(0)); +} + +/////////////////////////////////////////////////////////////////////////// + +bool Ed_result::add_result_set(List *col_metadata) +{ + Ed_result_set *rs= Ed_result_set::create(&m_mem_root, col_metadata); + + if (!rs) + return TRUE; + + m_current_result_set= rs; + + return push_back(rs, &m_mem_root) ? TRUE : FALSE; +} + +/////////////////////////////////////////////////////////////////////////// + +void Ed_result::send_ok(THD *thd, + uint server_status, uint statement_warn_count, + ha_rows affected_rows, ulonglong last_insert_id, + const char *message) +{ + DBUG_ENTER("Ed_result::send_ok()"); + DBUG_ASSERT(m_status == Diagnostics_area::DA_EMPTY); + + m_status= thd->main_da.status(); + DBUG_ASSERT(m_status == Diagnostics_area::DA_OK); + + DBUG_ASSERT(m_warning_info.statement_warn_count() == statement_warn_count); + + m_server_status= server_status; + m_affected_rows= affected_rows; + m_last_insert_id= last_insert_id; + + strmake(m_message, message, sizeof (m_message) - 1); + + DBUG_VOID_RETURN; +} + +/////////////////////////////////////////////////////////////////////////// + +void Ed_result::send_eof(THD *thd, uint server_status, + uint statement_warn_count) +{ + DBUG_ENTER("Ed_result::send_eof"); + DBUG_ASSERT(m_status == Diagnostics_area::DA_EMPTY); + + m_status= thd->main_da.status(); + DBUG_ASSERT(m_status == Diagnostics_area::DA_EOF); + + DBUG_ASSERT(m_warning_info.statement_warn_count() == statement_warn_count); + + m_server_status= server_status; + + DBUG_VOID_RETURN; +} + +/////////////////////////////////////////////////////////////////////////// + +void Ed_result::send_error(THD *thd, uint sql_errno, const char *err_msg) +{ + DBUG_ENTER("Ed_result::send_error()"); + DBUG_ASSERT(m_status == Diagnostics_area::DA_EMPTY); + + m_status= thd->main_da.status(); + DBUG_ASSERT(m_status == Diagnostics_area::DA_ERROR); + + m_sql_errno= sql_errno; + strmake(m_message, err_msg, sizeof (m_message) - 1); + + DBUG_VOID_RETURN; +} + +/////////////////////////////////////////////////////////////////////////// + +void Ed_result::begin_statement(THD *thd) +{ + DBUG_ASSERT(!m_warning_info_saved); + + m_warning_info_saved= thd->warning_info; + thd->warning_info= &m_warning_info; +} + +/////////////////////////////////////////////////////////////////////////// + +void Ed_result::end_statement(THD *thd) +{ + DBUG_ASSERT(m_warning_info_saved); + thd->warning_info= m_warning_info_saved; +} + +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// + +Ed_result_set * +Ed_result_set::create(MEM_ROOT *mem_root, List *col_metadata) +{ + Ed_result_set *rs= new (mem_root) Ed_result_set(mem_root); + + if (!rs || rs->init(col_metadata)) + return NULL; + + return rs; +} + +/////////////////////////////////////////////////////////////////////////// + +bool Ed_result_set::init(List *col_metadata) +{ + m_metadata= Ed_result_set_metadata::create(m_mem_root, col_metadata); + + return m_metadata == NULL; +} + +/////////////////////////////////////////////////////////////////////////// + +Ed_row *Ed_result_set::add_row() +{ + Ed_row *row= Ed_row::create(m_mem_root, m_metadata); + + if (!row) + return NULL; + + m_current_row= row; + + return m_data.push_back(row, m_mem_root) ? NULL : row; +} + +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// + +Ed_result_set_metadata * +Ed_result_set_metadata::create(MEM_ROOT *mem_root, + List *col_metadata) +{ + Ed_result_set_metadata *md= new (mem_root) Ed_result_set_metadata(); + + if (!md || md->init(mem_root, col_metadata)) + return NULL; + + return md; +} + +/////////////////////////////////////////////////////////////////////////// + +bool Ed_result_set_metadata::init(MEM_ROOT *mem_root, List *col_metadata) +{ + if (!col_metadata) + return FALSE; + + m_metadata= new (mem_root) Send_field[col_metadata->elements]; + + if (!m_metadata) + return TRUE; + + m_num_columns= col_metadata->elements; + + List_iterator_fast it(*col_metadata); + + int i= 0; + for (Item *column= it++; column; column= it++) + column->make_field(&m_metadata[i]); + + return FALSE; +} + +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// + +Ed_row *Ed_row::create(MEM_ROOT *mem_root, + const Ed_result_set_metadata *metadata) +{ + DBUG_ASSERT(metadata); + + Ed_row *row= new (mem_root) Ed_row(mem_root, metadata); + + if (!row || row->init()) + return NULL; + + return row; +} + +/////////////////////////////////////////////////////////////////////////// + +bool Ed_row::init() +{ + m_columns= new (m_mem_root) Ed_column[m_metadata->get_num_columns()]; + + return m_columns == NULL; +} + +/////////////////////////////////////////////////////////////////////////// + +bool Ed_row::add_null() +{ + if (m_current_column_index >= m_metadata->get_num_columns()) + return TRUE; + + ++m_current_column_index; + + return FALSE; +} + +/////////////////////////////////////////////////////////////////////////// + +bool Ed_row::add_column(const void *data_ptr, int data_length) +{ + if (m_current_column_index >= m_metadata->get_num_columns()) + return TRUE; + + m_columns[m_current_column_index++].set_data(m_mem_root, + data_ptr, data_length); + + return FALSE; +} + +/////////////////////////////////////////////////////////////////////////// +// +// Protocol_local: a protocol for retrieving result sets from the server +// locally. +// +/////////////////////////////////////////////////////////////////////////// + +void Protocol_local::prepare_for_resend() +{ + DBUG_ASSERT(m_result); + + Ed_result_set *rs= m_result->get_cur_result_set(); + + DBUG_ASSERT(rs); + + rs->add_row(); +} + +bool Protocol_local::write() +{ + return FALSE; +} + +bool Protocol_local::store_null() +{ + DBUG_ASSERT(m_result); + + Ed_result_set *rs= m_result->get_cur_result_set(); + Ed_row *row= rs->get_cur_row(); + DBUG_ASSERT(row); + + return row->add_null(); +} + +bool Protocol_local::store_string(const char *str, + int length, + CHARSET_INFO *src_cs, + CHARSET_INFO *dst_cs) +{ + DBUG_ASSERT(m_result); + + Ed_result_set *rs= m_result->get_cur_result_set(); + Ed_row *row= rs->get_cur_row(); + DBUG_ASSERT(row); + + /* 'dst_cs' is set 0 when client issued SET character_set_results = NULL */ + + if (!dst_cs || + my_charset_same(src_cs, dst_cs) || + src_cs == &my_charset_bin || + dst_cs == &my_charset_bin) + { + return row->add_column(str, length); + } + + /* Store with conversion */ + uint dummy_errors; + + if (convert->copy(str, length, src_cs, dst_cs, &dummy_errors)) + return TRUE; + + return row->add_column(convert->ptr(), convert->length()); +} + +bool Protocol_local::store_tiny(longlong value) +{ + Ed_result_set *rs= m_result->get_cur_result_set(); + Ed_row *row= rs->get_cur_row(); + + /* TODO: check medata type. */ + + char v= (char) value; + + return row->add_column(&v, 1); +} + +bool Protocol_local::store_short(longlong value) +{ + Ed_result_set *rs= m_result->get_cur_result_set(); + Ed_row *row= rs->get_cur_row(); + + /* TODO: check medata type. */ + + int16 v= (int16) value; + + return row->add_column(&v, 2); +} + +bool Protocol_local::store_long(longlong value) +{ + Ed_result_set *rs= m_result->get_cur_result_set(); + Ed_row *row= rs->get_cur_row(); + + /* TODO: check medata type. */ + + int32 v= (int32) value; + + return row->add_column(&v, 4); +} + +bool Protocol_local::store_longlong(longlong value, bool unsigned_flag) +{ + Ed_result_set *rs= m_result->get_cur_result_set(); + Ed_row *row= rs->get_cur_row(); + + /* TODO: check medata type. */ + + int64 v= (int64) value; + + return row->add_column(&v, 8); +} + +bool Protocol_local::store_decimal(const my_decimal *value) +{ + Ed_result_set *rs= m_result->get_cur_result_set(); + Ed_row *row= rs->get_cur_row(); + + /* TODO: check medata type. */ + + char buf[DECIMAL_MAX_STR_LENGTH]; + String str(buf, sizeof (buf), &my_charset_bin); + my_decimal2string(E_DEC_FATAL_ERROR, value, 0, 0, 0, &str); + + return row->add_column(str.ptr(), str.length()); +} + +bool Protocol_local::store(const char *str, + size_t length, + CHARSET_INFO *src_cs) +{ + CHARSET_INFO *dst_cs= this->thd->variables.character_set_results; + return store_string(str, length, src_cs, dst_cs); +} + +bool Protocol_local::store(const char *str, + size_t length, + CHARSET_INFO *src_cs, + CHARSET_INFO *dst_cs) +{ + return store_string(str, length, src_cs, dst_cs); +} + +bool Protocol_local::store(MYSQL_TIME *time) +{ + Ed_result_set *rs= m_result->get_cur_result_set(); + Ed_row *row= rs->get_cur_row(); + + /* TODO: check medata type. */ + + return row->add_column(time, sizeof (MYSQL_TIME)); +} + +bool Protocol_local::store_date(MYSQL_TIME *time) +{ + Ed_result_set *rs= m_result->get_cur_result_set(); + Ed_row *row= rs->get_cur_row(); + + /* TODO: check medata type. */ + + return row->add_column(time, sizeof (MYSQL_TIME)); +} + +bool Protocol_local::store_time(MYSQL_TIME *time) +{ + Ed_result_set *rs= m_result->get_cur_result_set(); + Ed_row *row= rs->get_cur_row(); + + /* TODO: check medata type. */ + + return row->add_column(time, sizeof (MYSQL_TIME)); +} + +bool Protocol_local::store(float value, uint32 decimals, String *buffer) +{ + Ed_result_set *rs= m_result->get_cur_result_set(); + Ed_row *row= rs->get_cur_row(); + + /* TODO: check medata type. */ + + return row->add_column(&value, sizeof (float)); +} + +bool Protocol_local::store(double value, uint32 decimals, String *buffer) +{ + Ed_result_set *rs= m_result->get_cur_result_set(); + Ed_row *row= rs->get_cur_row(); + + /* TODO: check medata type. */ + + return row->add_column(&value, sizeof (double)); +} + +bool Protocol_local::store(Field *field) +{ + if (field->is_null()) + return store_null(); + return field->send_binary(this); +} + +bool Protocol_local::send_result_set_metadata(List *columns, uint) +{ + DBUG_ASSERT(m_result); + + return m_result->add_result_set(columns); +} + +bool Protocol_local::send_out_parameters(List *sp_params) +{ + return FALSE; +} + +void Protocol_local::send_ok(uint server_status, uint statement_warn_count, + ha_rows affected_rows, ulonglong last_insert_id, + const char *message) +{ + m_result->send_ok(thd, server_status, statement_warn_count, + affected_rows, last_insert_id, message); +} + +void Protocol_local::send_eof(uint server_status, uint statement_warn_count) +{ + m_result->send_eof(thd, server_status, statement_warn_count); +} + +void Protocol_local::send_error(uint sql_errno, const char *err_msg) +{ + m_result->send_error(thd, sql_errno, err_msg); +} + +#ifdef EMBEDDED_LIBRARY +void Protocol_local::remove_last_row() +{ } +#endif === modified file 'sql/protocol.h' --- a/sql/protocol.h 2008-11-18 20:25:51 +0000 +++ b/sql/protocol.h 2008-11-27 18:31:59 +0000 @@ -17,6 +17,8 @@ #pragma interface /* gcc class implementation */ #endif +#include "sql_error.h" + class i_string; class THD; class Item_param; @@ -46,6 +48,15 @@ protected: CHARSET_INFO *fromcs, CHARSET_INFO *tocs); bool store_string_aux(const char *from, size_t length, CHARSET_INFO *fromcs, CHARSET_INFO *tocs); + + virtual void send_ok(uint server_status, uint statement_warn_count, + ha_rows affected_rows, ulonglong last_insert_id, + const char *message); + + virtual void send_eof(uint server_status, uint statement_warn_count); + + virtual void send_error(uint sql_errno, const char *err_msg); + public: Protocol() {} Protocol(THD *thd_arg) { init(thd_arg); } @@ -106,23 +117,15 @@ public: #endif enum enum_protocol_type { - PROTOCOL_TEXT= 0, PROTOCOL_BINARY= 1 /* - before adding here or change the values, consider that it is cast to a - bit in sql_cache.cc. + Before adding a new type, please make sure + there is enough storage for it in Query_cache_query_flags. */ + PROTOCOL_TEXT= 0, PROTOCOL_BINARY= 1, PROTOCOL_LOCAL= 2 }; virtual enum enum_protocol_type type()= 0; void end_statement(); - - virtual void send_ok(uint server_status, uint statement_warn_count, - ha_rows affected_rows, ulonglong last_insert_id, - const char *message); - - virtual void send_eof(uint server_status, uint statement_warn_count); - - virtual void send_error(uint sql_errno, const char *err_msg); }; @@ -198,4 +201,267 @@ bool send_old_password_request(THD *thd) uchar *net_store_data(uchar *to,const uchar *from, size_t length); uchar *net_store_data(uchar *to,int32 from); uchar *net_store_data(uchar *to,longlong from); + +/////////////////////////////////////////////////////////////////////////// + +/** + Protocol_local: a protocol to retrieve and store + a result set. +*/ + +class Ed_result; + +class Protocol_local :public Protocol +{ +public: + inline Protocol_local(THD *thd, Ed_result *result) + :Protocol(thd), m_result(result) + {} + +public: + virtual void prepare_for_resend(); + virtual bool write(); + virtual bool store_null(); + virtual bool store_tiny(longlong from); + virtual bool store_short(longlong from); + virtual bool store_long(longlong from); + virtual bool store_longlong(longlong from, bool unsigned_flag); + virtual bool store_decimal(const my_decimal *); + virtual bool store(const char *from, size_t length, CHARSET_INFO *cs); + virtual bool store(const char *from, size_t length, + CHARSET_INFO *fromcs, CHARSET_INFO *tocs); + virtual bool store(MYSQL_TIME *time); + virtual bool store_date(MYSQL_TIME *time); + virtual bool store_time(MYSQL_TIME *time); + virtual bool store(float value, uint32 decimals, String *buffer); + virtual bool store(double value, uint32 decimals, String *buffer); + virtual bool store(Field *field); + + virtual bool send_result_set_metadata(List *list, uint flags); + virtual bool send_out_parameters(List *sp_params); +#ifdef EMBEDDED_LIBRARY + void remove_last_row(); +#endif + virtual enum enum_protocol_type type() { return PROTOCOL_LOCAL; }; + +protected: + virtual void send_ok(uint server_status, uint statement_warn_count, + ha_rows affected_rows, ulonglong last_insert_id, + const char *message); + + virtual void send_eof(uint server_status, uint statement_warn_count); + + virtual void send_error(uint sql_errno, const char *err_msg); + +private: + bool store_string(const char *str, int length, + CHARSET_INFO *src_cs, CHARSET_INFO *dst_cs); + +private: + Ed_result *m_result; +}; + + +/** + Ed_column -- a class representing a column data in a row. Used with + Ed_row and Protocol_local. +*/ + +class Ed_column : public LEX_STRING, public Sql_alloc +{ +public: + inline Ed_column() + { + str= NULL; + length= 0; + } + + inline void set_data(MEM_ROOT *mem_root, const void *p_str, int p_length) + { + str= (char *) memdup_root(mem_root, p_str, p_length); + length= p_length; + } +}; + +/////////////////////////////////////////////////////////////////////////// + +/** + Ed_result_set_metadata -- a class representing result set metadata. Used + with Ed_result_set and Protocol_local. +*/ + +class Ed_result_set_metadata : public Sql_alloc +{ +public: + static Ed_result_set_metadata *create(MEM_ROOT *mem_root, + List *col_metadata); + +public: + inline int get_num_columns() const { return m_num_columns; } + + inline const Send_field *get_column(int idx) const + { return &m_metadata[idx]; } + +private: + inline Ed_result_set_metadata() : + m_num_columns(0), + m_metadata(NULL) + { } + +private: + bool init(MEM_ROOT *mem_root, List *col_metadata); + +private: + int m_num_columns; + Send_field *m_metadata; +}; + +/////////////////////////////////////////////////////////////////////////// + +/** + Ed_row -- a class representing a row in a result set. Used with + Ed_result_set and Protocol_local. +*/ +class Ed_row : public Sql_alloc +{ +public: + static Ed_row *create(MEM_ROOT *mem_root, + const Ed_result_set_metadata *metadata); + +public: + bool add_null(); + bool add_column(const void *data_ptr, int data_length); + +public: + inline const Ed_result_set_metadata *get_metadata() const + { return m_metadata; } + + inline const Ed_column *get_column(int idx) const + { return &m_columns[idx]; } + + inline const Ed_column &operator [](int idx) const + { return *get_column(idx); } + + inline int get_current_column_index() const + { return m_current_column_index; } + +private: + inline Ed_row(MEM_ROOT *mem_root, + const Ed_result_set_metadata *metadata) : + m_mem_root(mem_root), + m_metadata(metadata), + m_current_column_index(0) + { } + + bool init(); + +private: + MEM_ROOT *m_mem_root; + const Ed_result_set_metadata *m_metadata; + Ed_column *m_columns; + int m_current_column_index; +}; + +/////////////////////////////////////////////////////////////////////////// + +/** + Ed_result_set -- a class representing one result set. Used with Ed_result + and Protocol_local. +*/ +class Ed_result_set : public Sql_alloc +{ +public: + static Ed_result_set *create(MEM_ROOT *mem_root, + List *col_metadata); + +private: + inline Ed_result_set(MEM_ROOT *mem_root) : + m_mem_root(mem_root), + m_metadata(NULL), + m_current_row(NULL) + { } + +private: + bool init(List *col_metadata); + +public: + inline const Ed_result_set_metadata *get_metadata() const + { return m_metadata; } + + inline List *data() + { return &m_data; } + + inline Ed_row *get_cur_row() + { return m_current_row; } + + Ed_row *add_row(); + +private: + MEM_ROOT *m_mem_root; + + Ed_result_set_metadata *m_metadata; + List m_data; + + Ed_row *m_current_row; +}; + +/////////////////////////////////////////////////////////////////////////// + +/* + Ed_result -- a class representing results for an SQL statement execution. + Used with Protocol_local. +*/ +class Ed_result : public List +{ +public: + Ed_result(); + ~Ed_result(); + +public: + inline Ed_result_set *get_cur_result_set() + { return m_current_result_set; } + + bool add_result_set(List *col_metadata); + +public: + void send_ok(THD *thd, uint server_status, uint statement_warn_count, + ha_rows affected_rows, ulonglong last_insert_id, + const char *message); + + void send_eof(THD *thd, uint server_status, uint statement_warn_count); + + void send_error(THD *thd, uint sql_errno, const char *err_msg); + + void begin_statement(THD *thd); + void end_statement(THD *thd); + +public: + inline uint get_status() const { return m_status; } + inline uint get_server_status() const { return m_server_status; } + inline ha_rows get_affected_rows() const { return m_affected_rows; } + inline ulonglong get_last_insert_id() const { return m_last_insert_id; } + inline uint get_sql_errno() const { return m_sql_errno; } + inline const char *get_message() const { return m_message; } + + inline uint get_statement_warn_count() const + { return m_warning_info.statement_warn_count(); } + + inline List &get_warnings() + { return m_warning_info.warn_list(); } + +private: + MEM_ROOT m_mem_root; + Ed_result_set *m_current_result_set; + +private: + uint m_status; + uint m_server_status; + ha_rows m_affected_rows; + ulonglong m_last_insert_id; + uint m_sql_errno; + char m_message[MYSQL_ERRMSG_SIZE]; + + Warning_info m_warning_info; + Warning_info *m_warning_info_saved; +}; === modified file 'sql/share/errmsg.txt' --- a/sql/share/errmsg.txt 2008-11-07 17:07:58 +0000 +++ b/sql/share/errmsg.txt 2008-11-21 19:05:10 +0000 @@ -6397,7 +6397,7 @@ ER_BACKUP_GET_META_PRIV 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." + eng "The grant '%-.64s' for the user %-.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." ER_BACKUP_LOGPATHS === modified file 'sql/si_objects.cc' --- a/sql/si_objects.cc 2008-10-27 13:06:21 +0000 +++ b/sql/si_objects.cc 2008-12-02 11:27:23 +0000 @@ -1,2081 +1,1741 @@ -/** - @file +/* Copyright (C) 2008 MySQL AB - This file defines the API for the following object services: - - serialize database objects into a string; - - materialize (deserialize) object from a string; - - enumerating objects; - - finding dependencies for objects; - - executor for SQL statements; - - wrappers for controlling the DDL Blocker; + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - The methods defined below are used to provide server functionality to - and permitting an isolation layer for the client (caller). -*/ +/** @file Server Service Interface for Backup: the implementation. */ #include "mysql_priv.h" + #include "si_objects.h" #include "ddl_blocker.h" #include "sql_show.h" +#include "sql_trigger.h" +#include "sp.h" +#include "sp_head.h" // for sp_add_to_query_tables(). + #ifdef HAVE_EVENT_SCHEDULER #include "events.h" #include "event_data_objects.h" #include "event_db_repository.h" #endif -#include "sql_trigger.h" -#include "sp.h" -#include "sp_head.h" // for sp_add_to_query_tables(). - -TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list); // defined in sql_show.cc DDL_blocker_class *DDL_blocker= NULL; /////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// + +#define STR(x) (int) (x).length(), (x).ptr() + +#define LXS_INIT(x) {((char *) (x)), ((size_t) (sizeof (x) - 1))} + +/////////////////////////////////////////////////////////////////////////// namespace { -// Helper methods +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// /** - Execute the SQL string passed. - - This is a private helper function to the implementation. + Si_session_context defines a way to save/reset/restore session context + for SI-operations. */ -int silent_exec(THD *thd, String *query) -{ - Vio *save_vio= thd->net.vio; - DBUG_PRINT("si_objects",("executing %s",query->c_ptr())); +class Si_session_context +{ +public: + inline Si_session_context() + { } - /* - Note: the change net.vio idea taken from execute_init_command in - sql_parse.cc - */ - thd->net.vio= 0; - - thd->query= query->c_ptr(); - thd->query_length= query->length(); - - thd->set_time(); - pthread_mutex_lock(&::LOCK_thread_count); - thd->query_id= ::next_query_id(); - pthread_mutex_unlock(&::LOCK_thread_count); +public: + void save_si_ctx(THD *thd); + void reset_si_ctx(THD *thd); + void restore_si_ctx(THD *thd); - /* - @todo The following is a work around for online backup and the DDL blocker. - It should be removed when the generalized solution is in place. - This is needed to ensure the restore (which uses DDL) is not blocked - when the DDL blocker is engaged. - */ - thd->DDL_exception= TRUE; +private: + ulong m_sql_mode_saved; + CHARSET_INFO *m_client_cs_saved; + CHARSET_INFO *m_results_cs_saved; + CHARSET_INFO *m_connection_cl_saved; + Time_zone *m_tz_saved; + TABLE *m_tmp_tables_saved; - /* - Note: This is a copy and paste from the code in sql_parse.cc. - See "case COM_QUERY:". - */ - const char *found_semicolon= thd->query; - char *packet_end= thd->query + thd->query_length; - mysql_parse(thd, thd->query, thd->query_length, &found_semicolon); - while (!thd->killed && found_semicolon && !thd->is_error()) - { - char *next_packet= (char*) found_semicolon; - /* - Multiple queries exits, execute them individually - */ - close_thread_tables(thd); - ulong length= (ulong)(packet_end - next_packet); +private: + Si_session_context(const Si_session_context &); + Si_session_context &operator =(const Si_session_context &); +}; - /* Remove garbage at start of query */ - while (my_isspace(thd->charset(), *next_packet) && length > 0) - { - next_packet++; - length--; - } - pthread_mutex_lock(&LOCK_thread_count); - thd->query_length= length; - thd->query= next_packet; - thd->query_id= next_query_id(); - thd->set_time(); /* Reset the query start time. */ - /* TODO: set thd->lex->sql_command to SQLCOM_END here */ - pthread_mutex_unlock(&LOCK_thread_count); - mysql_parse(thd, next_packet, length, & found_semicolon); - } +/////////////////////////////////////////////////////////////////////////// - close_thread_tables(thd); +/** + Preserve the following session attributes: + - sql_mode; + - character_set_client; + - character_set_results; + - collation_connection; + - time_zone; - thd->net.vio= save_vio; + Remember also session temporary tables. +*/ - if (thd->is_error()) - { - DBUG_PRINT("restore", - ("error executing query %s!", thd->query)); - DBUG_PRINT("restore",("last error (%d): %s",thd->net.last_errno - ,thd->net.last_error)); - return thd->net.last_errno ? (int)thd->net.last_errno : -1; - } +void Si_session_context::save_si_ctx(THD *thd) +{ + DBUG_ENTER("Si_session_context::save_si_ctx"); + m_sql_mode_saved= thd->variables.sql_mode; + m_client_cs_saved= thd->variables.character_set_client; + m_results_cs_saved= thd->variables.character_set_results; + m_connection_cl_saved= thd->variables.collation_connection; + m_tz_saved= thd->variables.time_zone; + m_tmp_tables_saved= thd->temporary_tables; - return 0; + DBUG_VOID_RETURN; } -/* - This method gets the create statement for a procedure or function. +/////////////////////////////////////////////////////////////////////////// + +/** + Reset session state to the following: + - sql_mode: 0 + - character_set_client: utf8 + - character_set_results: binary (to fetch results w/o conversion) + - collation_connection: utf8 + + Temporary tables should be ignored while looking for table structures. + We want to deal with real tables, not temporary ones. */ -bool serialize_routine(THD *thd, - int type, - String db_name, - String r_name, - String *string) + +void Si_session_context::reset_si_ctx(THD *thd) { - int ret= 0; - sp_head *sp; - sp_name *routine_name; - LEX_STRING sql_mode; - DBUG_ENTER("serialize_routine"); - DBUG_PRINT("serialize_routine", ("name: %s@%s", db_name.c_ptr(), - r_name.c_ptr())); - - DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE || type == TYPE_ENUM_FUNCTION); - sp_cache **cache = type == TYPE_ENUM_PROCEDURE ? - &thd->sp_proc_cache : &thd->sp_func_cache; - LEX_STRING db; - db.str= db_name.c_ptr(); - db.length= db_name.length(); - LEX_STRING name; - name.str= r_name.c_ptr(); - name.length= r_name.length(); - routine_name= new sp_name(db, name, true); - routine_name->init_qname(thd); - if (type == TYPE_ENUM_PROCEDURE) - thd->variables.max_sp_recursion_depth++; - if ((sp= sp_find_routine(thd, type, routine_name, cache, FALSE))) - { - sys_var_thd_sql_mode::symbolic_mode_representation(thd, - sp->m_sql_mode, &sql_mode); - Stored_program_creation_ctx *sp_ctx= sp->get_creation_ctx(); + DBUG_ENTER("Si_session_context::reset_si_ctx"); - /* - Prepend sql_mode command. - */ - string->append("SET SQL_MODE = '"); - string->append(sql_mode.str); - string->append("'; "); + thd->variables.sql_mode= 0; - /* - append character set client charset information - */ - string->append("SET CHARACTER_SET_CLIENT = '"); - string->append(sp_ctx->get_client_cs()->csname); - string->append("'; "); + thd->variables.character_set_client= system_charset_info; + thd->variables.character_set_results= &my_charset_bin; + thd->variables.collation_connection= system_charset_info; + thd->update_charset(); - /* - append collation_connection information - */ - string->append("SET COLLATION_CONNECTION = '"); - string->append(sp_ctx->get_connection_cl()->name); - string->append("'; "); - - /* - append collation_connection information - */ - string->append("SET COLLATION_DATABASE = '"); - string->append(sp_ctx->get_db_cl()->name); - string->append("'; "); + thd->temporary_tables= NULL; - string->append(sp->m_defstr.str); - } - else - { - string->length(0); - ret= TRUE; - } - if (type == TYPE_ENUM_PROCEDURE) - thd->variables.max_sp_recursion_depth--; - DBUG_RETURN(ret); + DBUG_VOID_RETURN; } -/* - This method calls silent_exec() while saving the context - information before the call and restoring after the call. +/////////////////////////////////////////////////////////////////////////// - If save_timezone, it also saves and restores the timezone. +/** + Restore session state. */ -bool execute_with_ctx(THD *thd, String *query, bool save_timezone) -{ - bool ret= false; - ulong orig_sql_mode; - CHARSET_INFO *orig_char_set_client; - CHARSET_INFO *orig_coll_conn; - CHARSET_INFO *orig_coll_db; - Time_zone *tm_zone; - DBUG_ENTER("Obj::execute_with_ctx()"); - - /* - Preserve SQL_MODE, CHARACTER_SET_CLIENT, COLLATION_CONNECTION, - and COLLATION_DATABASE. - */ - orig_sql_mode= thd->variables.sql_mode; - orig_char_set_client= thd->variables.character_set_client; - orig_coll_conn= thd->variables.collation_connection; - orig_coll_db= thd->variables.collation_database; - /* - Preserve timezone. - */ - if (save_timezone) - tm_zone= thd->variables.time_zone; +void Si_session_context::restore_si_ctx(THD *thd) +{ + DBUG_ENTER("Si_session_context::restore_si_ctx"); - ret= silent_exec(thd, query); + thd->variables.sql_mode= m_sql_mode_saved; + thd->variables.time_zone= m_tz_saved; - /* - Restore SQL_MODE, CHARACTER_SET_CLIENT, COLLATION_CONNECTION, - and COLLATION_DATABASE. - */ - thd->variables.sql_mode= orig_sql_mode; - thd->variables.character_set_client= orig_char_set_client; - thd->variables.collation_connection= orig_coll_conn; - thd->variables.collation_database= orig_coll_db; + thd->variables.collation_connection= m_connection_cl_saved; + thd->variables.character_set_results= m_results_cs_saved; + thd->variables.character_set_client= m_client_cs_saved; + thd->update_charset(); - /* - Restore timezone. - */ - if (save_timezone) - thd->variables.time_zone= tm_zone; + thd->temporary_tables= m_tmp_tables_saved; - DBUG_RETURN(ret); + DBUG_VOID_RETURN; } -/* - Drops an object. - - obj_name is the name of the object e.g., DATABASE, PROCEDURE, etc. - name1 is the db name (blank for database objects) - name2 is the name of the object -*/ -bool drop_object(THD *thd, const char *obj_name, String *name1, String *name2) -{ - DBUG_ENTER("Obj::drop_object()"); - String cmd; - cmd.length(0); - cmd.append("DROP "); - cmd.append(obj_name); - cmd.append(" IF EXISTS "); - if (name1 && (name1->length() > 0)) - { - append_identifier(thd, &cmd, name1->c_ptr(), name1->length()); - cmd.append("."); - } - append_identifier(thd, &cmd, name2->c_ptr(), name2->length()); - DBUG_RETURN(silent_exec(thd, &cmd)); -} +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// /** - Open given table in @c INFORMATION_SCHEMA database. - - This is a private helper function to the implementation. + Execute one DML statement in a backup-specific context. Result set and + warning information are stored in the output parameter. Some session + attributes are preserved and reset to predefined values before query + execution (@see Si_session_context). - @param[in] thd Thread context - @param[in] st Schema table enum - @param[in] db_list List of databases for select condition + @param[in] thd Thread context. + @param[in] query SQL query to be executed. + @param[out] ed_result A place to store result and warnings. - @note: The select condition is designed to form a WHERE clause based on - the database/schema column of the information_schema views. Most views have - a database/schema column but for those that do not, you must ignore the - selection condition by passing db_list = NULL. - - @retval TABLE* The schema table + @return Error status. + @retval TRUE on error. + @retval FALSE on success. */ -TABLE* open_schema_table(THD *thd, ST_SCHEMA_TABLE *st, List *db_list) -{ - TABLE *t; - TABLE_LIST arg; - my_bitmap_map *old_map; - - bzero( &arg, sizeof(TABLE_LIST) ); - // set context for create_schema_table call - arg.schema_table= st; - arg.alias= NULL; - arg.select_lex= NULL; +bool +run_service_interface_sql(THD *thd, const LEX_STRING *query, + Ed_result *ed_result) +{ + Si_session_context session_context; - t= create_schema_table(thd,&arg); // Note: callers must free t. + DBUG_ENTER("run_service_interface_sql"); + DBUG_PRINT("run_service_interface_sql", + ("query: %.*s", + (int) query->length, (const char *) query->str)); - if( !t ) return NULL; // error! + session_context.save_si_ctx(thd); + session_context.reset_si_ctx(thd); - /* - Temporarily set thd->lex->wild to NULL to keep st->fill_table - happy. - */ - ::String *wild= thd->lex->wild; - ::enum_sql_command command= thd->lex->sql_command; + bool rc= mysql_execute_direct(thd, *query, ed_result); - thd->lex->wild = NULL; - thd->lex->sql_command = enum_sql_command(0); + session_context.restore_si_ctx(thd); - // context for fill_table - arg.table= t; + DBUG_RETURN(rc); +} - old_map= tmp_use_all_columns(t, t->read_set); +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// - /* - Create a selection condition only if db_list is defined. - */ - if (db_list) - st->fill_table(thd, &arg, obs::create_db_select_condition(thd, t, db_list)); - else - st->fill_table(thd, &arg, NULL); +/** + Update THD with the warnings from the given list. - tmp_restore_column_map(t->read_set, old_map); + @param[in] thd Thread context. + @parampin] src Warning list. +*/ - // undo changes to thd->lex - thd->lex->wild= wild; - thd->lex->sql_command= command; +void copy_warnings(THD *thd, List *src) +{ + List_iterator_fast err_it(*src); + MYSQL_ERROR *err; - return t; + while ((err= err_it++)) + push_warning(thd, err->level, err->code, err->msg); } -/* - Prepend the USE DB command. +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// + +/** + Table_name_key defines a hash key, which includes database and tables + names. */ -void prepend_db(THD *thd, String *serialization, String *db_name) + +struct Table_name_key { - DBUG_ENTER("Obj::prepend_db()"); - /* - prepend "USE db" statement - */ - serialization->length(0); - serialization->append("USE "); - append_identifier(thd, serialization, db_name->c_ptr(), db_name->length()); - serialization->append("; "); - DBUG_VOID_RETURN; -} +public: + LEX_STRING db_name; + LEX_STRING table_name; + LEX_STRING key; + +public: + void init_from_mdl_key(const char *key_arg, size_t key_length_arg, + char *key_buff_arg); +}; /////////////////////////////////////////////////////////////////////////// -struct Table_name_key +void +Table_name_key::init_from_mdl_key(const char *key_arg, size_t key_length_arg, + char *key_buff_arg) { - Table_name_key(const char *db_name_str, - uint db_name_length, - const char *table_name_str, - uint table_name_length) - { - db_name.copy(db_name_str, db_name_length, system_charset_info); - table_name.copy(table_name_str, table_name_length, system_charset_info); + key.str= key_buff_arg; + key.length= key_length_arg - 4; /* Skip MDL object type */ + memcpy(key.str, key_arg + 4, key.length); - key.length(0); - key.append(db_name); - key.append("."); - key.append(table_name); - } + db_name.str= key.str; + db_name.length= strlen(db_name.str); + table_name.str= db_name.str + db_name.length + 1; /* Skip \0 */ + table_name.length= strlen(table_name.str); +} - String db_name; - String table_name; +/////////////////////////////////////////////////////////////////////////// - String key; -}; +extern "C" { -uchar * +static uchar * get_table_name_key(const uchar *record, size_t *key_length, my_bool not_used __attribute__((unused))) { - Table_name_key *tnk= (Table_name_key *) record; - *key_length= tnk->key.length(); - return (uchar *) tnk->key.c_ptr_safe(); + Table_name_key *table_name_key= (Table_name_key *) record; + *key_length= table_name_key->key.length; + return (uchar *) table_name_key->key.str; } -void delete_table_name_key(void *data) +/////////////////////////////////////////////////////////////////////////// + +static void +free_table_name_key(void *data) { - Table_name_key *tnk= (Table_name_key *) data; - delete tnk; + Table_name_key *table_name_key= (Table_name_key *) data; + my_free(table_name_key, MYF(0)); } -} +} // end of extern "C" /////////////////////////////////////////////////////////////////////////// - -namespace obs { +/////////////////////////////////////////////////////////////////////////// /** - Build a where clause for list of databases. - - This method is used to help improve the efficiency of queries against - information schema tables. It builds a condition tree of the form - db_col IN ('a','b','c') where a,b,c are database names. - - @param[in] thd Thread context. - @param[in] t The table to operate on. - @param[in] db_list The list of databases in form List - - @returns NULL if no databases in list or pointer to COND tree. -*/ -COND *create_db_select_condition(THD *thd, - TABLE *t, - List *db_list) -{ - List in_db_list; - List_iterator< ::LEX_STRING> it(*db_list); - ::LEX_STRING *db; - DBUG_ENTER("Obj::create_select_condition()"); - - /* - If no list of databases, just return NULL - */ - if (!db_list->elements) - DBUG_RETURN(NULL); + Int_value is a wrapper for unsigned long type to be used with + the String_stream class. +*/ - /* - Build an inclusion list in the form of 'a', 'b', etc. - */ - while ((db= it++)) - { - Item *db_name= new Item_string(db->str, db->length, system_charset_info); - db_name->fix_fields(thd, &db_name); - db_name->next= NULL; - in_db_list.push_front(db_name); - } +struct Int_value +{ + unsigned long m_value; - /* - Build the compared field "table_schema" and link to temp table field. - */ - Item *db_field= new Item_field(thd, thd->lex->current_context(), t->field[1]); - in_db_list.push_front(db_field); + Int_value(unsigned long value_arg) + :m_value(value_arg) + { } +}; - /* - Build the in function item comparison and add list of databases. - */ - Item_func_in *in_cond = new Item_func_in(in_db_list); - in_cond->fix_fields(thd, (Item **)&in_cond); - in_cond->fix_length_and_dec(); +/////////////////////////////////////////////////////////////////////////// - DBUG_RETURN(in_cond); -} +/* + C_str is a wrapper for C-string (const char *) to be used with the + String_stream class. +*/ -/////////////////////////////////////////////////////////////////////////// +struct C_str +{ + LEX_STRING lex_string; -// -// Implementation: object impl classes. -// + inline C_str(const char *str, size_t length) + { + lex_string.str= (char *) str; + lex_string.length= length; + } +}; /////////////////////////////////////////////////////////////////////////// /** - @class DatabaseObj + @class String_stream - This class provides an abstraction to a database object for creation and - capture of the creation data. + This class provides a convenient way to create a dynamic string from + C-strings in different forms (LEX_STRING, const char *) and integer + constants. */ -class DatabaseObj : public Obj + +class String_stream { public: - DatabaseObj(const String *db_name); + inline String_stream() + : m_buffer(&m_container) + { } -public: - virtual bool materialize(uint serialization_version, - const String *serialization); + inline String_stream(String *dst) + : m_buffer(dst) + { } - const String* get_name() - { return &m_db_name; } +public: + inline String *str() { return m_buffer; } - const String *get_db_name() + inline const LEX_STRING *lex_string() { - return &m_db_name; + m_lex_string= m_buffer->lex_string(); + return &m_lex_string; } -private: - // These attributes are to be used only for serialization. - String m_db_name; - - bool drop(THD *thd); - virtual bool do_serialize(THD *thd, String *serialization); - virtual bool do_execute(THD *thd); + inline void reset() { m_buffer->length(0); } -private: - // These attributes are to be used only for materialization. - String m_create_stmt; -}; - -/////////////////////////////////////////////////////////////////////////// - -/** - @class TableObj - - This class provides an abstraction to a table object for creation and - capture of the creation data. -*/ -class TableObj : public Obj -{ public: - TableObj(const String *db_name, - const String *table_name, - bool table_is_view); + String_stream &operator <<(const Int_value &v); -public: - virtual bool materialize(uint serialization_version, - const String *serialization); + inline String_stream &operator <<(const C_str &v) + { + m_buffer->append(v.lex_string.str, v.lex_string.length); + return *this; + } + + inline String_stream &operator <<(const LEX_STRING *v) + { + m_buffer->append(v->str, v->length); + return *this; + } - const String* get_name() - { return &m_table_name; } + inline String_stream &operator <<(const String *v) + { + m_buffer->append(v->ptr(), v->length()); + return *this; + } - const String *get_db_name() + String_stream &operator <<(const char *v) { - return &m_db_name; + m_buffer->append(v); + return *this; } private: - // These attributes are to be used only for serialization. - String m_db_name; - String m_table_name; - bool m_table_is_view; + String m_container; + String *m_buffer; + LEX_STRING m_lex_string; +}; - bool drop(THD *thd); - virtual bool do_serialize(THD *thd, String *serialization); - virtual bool do_execute(THD *thd); +/////////////////////////////////////////////////////////////////////////// -private: - // These attributes are to be used only for materialization. - String m_create_stmt; +String_stream &String_stream::operator <<(const Int_value &int_value) +{ + char buffer[13]; + my_snprintf(buffer, sizeof (buffer), "%lu", int_value.m_value); -private: - bool serialize_table(THD *thd, String *serialization); - bool serialize_view(THD *thd, String *serialization); -}; + m_buffer->append(buffer); + return *this; +} /////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// /** - @class TriggerObj + @class Out_stream - This class provides an abstraction to a trigger object for creation and - capture of the creation data. + This class encapsulates the semantic of creating the serialization image. + The image is actually a list of strings. Strings may contain any data + (including binary and new-line characters). String is length-coded, which + means there is string length before the string data. + + The format is as follows: + \n + + Example: + 12 Hello, + world + 5 qwerty */ -class TriggerObj : public Obj + +class Out_stream { public: - TriggerObj(const String *db_name, - const String *trigger_name); + inline Out_stream(String *image) : + m_image(image) + { } public: - virtual bool materialize(uint serialization_version, - const String *serialization); + Out_stream &operator <<(const LEX_STRING *query); - const String* get_name() - { return &m_trigger_name; } - - const String *get_db_name() + inline Out_stream &operator <<(const char *query) { - return &m_db_name; + LEX_STRING str= { (char *) query, strlen(query) }; + return Out_stream::operator <<(&str); } -private: - // These attributes are to be used only for serialization. - String m_db_name; - String m_trigger_name; + inline Out_stream &operator <<(const String *query) + { + LEX_STRING str= { (char *) query->ptr(), query->length() }; + return Out_stream::operator <<(&str); + } - bool drop(THD *thd); - virtual bool do_serialize(THD *thd, String *serialization); - virtual bool do_execute(THD *thd); + inline Out_stream &operator <<(String_stream &s_stream) + { + return Out_stream::operator <<(s_stream.str()); + } private: - // These attributes are to be used only for materialization. - String m_create_stmt; + String *m_image; }; /////////////////////////////////////////////////////////////////////////// +Out_stream &Out_stream::operator <<(const LEX_STRING *query) +{ + String_stream s_stream(m_image); + + s_stream << + Int_value(query->length) << " " << query << "\n"; + + return *this; +} + +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// + /** - @class StoredProcObj + @class In_stream - This class provides an abstraction to a stored procedure object for creation - and capture of the creation data. + This class encapsulates the semantic of reading from the serialization image. + For the format definition of the serialization image, @see Out_stream. */ -class StoredProcObj : public Obj + +class In_stream { public: - StoredProcObj(const String *db_name, - const String *stored_proc_name); + inline In_stream(uint image_version, const String *image) + : m_image_version(image_version), + m_image(image), + m_read_ptr(m_image->ptr()), + m_end_ptr(m_image->ptr() + m_image->length()) + { } public: - virtual bool materialize(uint serialization_version, - const String *serialization); - - const String* get_name() - { return &m_stored_proc_name; } - - const String *get_db_name() - { - return &m_db_name; - } + bool next(LEX_STRING *chunk); private: - // These attributes are to be used only for serialization. - String m_db_name; - String m_stored_proc_name; - - bool drop(THD *thd); - virtual bool do_serialize(THD *thd, String *serialization); - virtual bool do_execute(THD *thd); - -private: - // These attributes are to be used only for materialization. - String m_create_stmt; + uint m_image_version; + const String *m_image; + const char *m_read_ptr; + const char *m_end_ptr; }; /////////////////////////////////////////////////////////////////////////// -/** - @class StoredFuncObj - - This class provides an abstraction to a stored function object for creation - and capture of the creation data. -*/ -class StoredFuncObj : public Obj +bool In_stream::next(LEX_STRING *chunk) { -public: - StoredFuncObj(const String *db_name, - const String *stored_func_name); - -public: - virtual bool materialize(uint serialization_version, - const String *serialization); + if (m_read_ptr >= m_end_ptr) + return TRUE; - const String* get_name() - { return &m_stored_func_name; } + const char *delimiter_ptr= + my_strchr(system_charset_info, m_read_ptr, m_end_ptr, ' '); - const String *get_db_name() + if (!delimiter_ptr) { - return &m_db_name; + m_read_ptr= m_end_ptr; + return TRUE; } -private: - // These attributes are to be used only for serialization. - String m_db_name; - String m_stored_func_name; + char buffer[STRING_BUFFER_USUAL_SIZE]; + int n= delimiter_ptr - m_read_ptr; - bool drop(THD *thd); - virtual bool do_serialize(THD *thd, String *serialization); - virtual bool do_execute(THD *thd); + memcpy(buffer, m_read_ptr, n); + buffer[n]= 0; -private: - // These attributes are to be used only for materialization. - String m_create_stmt; -}; + chunk->str= (char *) delimiter_ptr + 1; + chunk->length= atoi(buffer); -/////////////////////////////////////////////////////////////////////////// -#ifdef HAVE_EVENT_SCHEDULER -/** - @class EventObj + m_read_ptr+= n /* chunk length */ + + 1 /* delimiter (a space) */ + + chunk->length /* chunk */ + + 1; /* chunk delimiter (\n) */ - This class provides an abstraction to a event object for creation and capture - of the creation data. -*/ -class EventObj : public Obj -{ -public: - EventObj(const String *db_name, - const String *event_name); + return FALSE; +} -public: - virtual bool materialize(uint serialization_version, - const String *serialization); +/////////////////////////////////////////////////////////////////////////// - const String* get_name() - { return &m_event_name; } +} // end of anonymous namespace - const String *get_db_name() - { - return &m_db_name; - } - -private: - // These attributes are to be used only for serialization. - String m_db_name; - String m_event_name; +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// - bool drop(THD *thd); - virtual bool do_serialize(THD *thd, String *serialization); - virtual bool do_execute(THD *thd); +namespace obs { -private: - // These attributes are to be used only for materialization. - String m_create_stmt; -}; -#endif // HAVE_EVENT_SCHEDULER +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// /** - @class TablespaceObj + @class Abstract_obj - This class provides an abstraction to a user object for creation and - capture of the creation data. + This class is a base class for all other Obj implementations. */ -class TablespaceObj : public Obj + +class Abstract_obj : public Obj { public: - TablespaceObj(const String *ts_name); + virtual inline const String *get_name() const { return &m_id; } + virtual inline const String *get_db_name() const { return NULL; } public: - virtual bool do_serialize(THD *thd, String *serialization); + /** + Serialize an object to an image. The serialization image is opaque + object for the client. - virtual bool materialize(uint serialization_version, - const String *serialization); + @param[in] thd Thread context. + @param[out] image Serialization image. - virtual bool do_execute(THD *thd); + @return Error status. + */ + virtual bool serialize(THD *thd, String *image); - const String *describe(); + /** + Create an object persistently in the database. - const String *build_serialization(); + @param[in] thd Thread context. - /* - The get_db_name primitive is not used for tablespaces. + @return Error status. + */ + virtual bool create(THD *thd); + + /** + Drop an object in the database. + + @param[in] thd Thread context. + + @return Error status. */ - const String *get_db_name() { return 0; } + virtual bool drop(THD *thd); - const String* get_name() - { return &m_ts_name; } +public: + /** + Read the object state from a given serialization image and restores + object state to the point, where it can be created persistently in the + database. - const String* get_datafile() - { return &m_datafile; } + @param[in] image_version The version of the serialization format. + @param[in] image Buffer contained serialized object. - const String* get_comments() - { return &m_comments; } + @return Error status. + @retval FALSE on success. + @retval TRUE on error. + */ + virtual bool init_from_image(uint image_version, const String *image); - const String* get_engine() - { return &m_engine; } +protected: + /** + A primitive implementing @c serialize() method. + */ + virtual bool do_serialize(THD *thd, Out_stream &out_stream) = 0; - void set_datafile(const String *df) - { m_datafile.copy(*df); } + /** + A primitive implementing @c init_from_image() method. + */ + virtual bool do_init_from_image(In_stream *is); - void set_comments(const String *c) - { m_comments.copy(*c); } + virtual void build_drop_statement(String_stream &s_stream) const = 0; - void set_engine(const String *engine) - { m_engine.copy(*engine); } +protected: + MEM_ROOT m_mem_root; /* This mem-root is for keeping stmt list. */ + List m_stmt_list; -private: - // These attributes are to be used only for serialization. - String m_ts_name; - String m_datafile; - String m_comments; - String m_engine; +protected: + /* These attributes are to be used only for serialization. */ + String m_id; //< identify object - // Drop is not supported by this object. - bool drop(THD *thd) - { return 0; } +protected: + inline Abstract_obj(LEX_STRING id); + + virtual inline ~Abstract_obj(); private: - // These attributes are to be used only for materialization. - String m_create_stmt; + Abstract_obj(const Abstract_obj &); + Abstract_obj &operator =(const Abstract_obj &); }; -/** - @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 +inline Abstract_obj::Abstract_obj(LEX_STRING id) { -public: - DbGrantObj(const String *grantee, - const String *db_name, - const String *priv_type); + init_sql_alloc(&m_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0); -public: - virtual bool materialize(uint serialization_version, - const String *serialization); + if (id.str && id.length) + m_id.copy(id.str, id.length, system_charset_info); + else + m_id.length(0); +} - const String* get_name() - { - return &m_name; - } +/////////////////////////////////////////////////////////////////////////// - const String *get_db_name() - { - return &m_db_name; - } +inline Abstract_obj::~Abstract_obj() +{ + free_root(&m_mem_root, MYF(0)); +} - 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. +/** + Serialize object state into a buffer. The buffer actually should be a + binary buffer. String class is used here just because we don't have + convenient primitive for binary buffers. - bool drop(THD *thd) { return 0; }; // Drop not supported. - virtual bool do_execute(THD *thd); + Serialization format is opaque to the client, i.e. the client should + not make any assumptions about the format or the content of the + returned buffer. -private: - virtual bool do_serialize(THD *thd, String *serialization); - // These attributes are to be used only for materialization. - String m_grant_stmt; -}; + Serialization format can be changed in the future versions. However, + the server must be able to materialize objects coded in any previous + formats. -/** - @class TblGrantObj + @param[in] thd Server thread context. + @param[in] image Buffer to serialize the object - This class provides an abstraction to table-level and routine-level grants. - This class will permit the recording and replaying of these - grants. + @return Error status. + @retval FALSE on success. + @retval TRUE on error. + + @note The real work is done inside @c do_serialize() primitive which should be + defied in derived classes. This method prepares appropriate context and calls + the primitive. */ -class TblGrantObj : public DbGrantObj + +bool Abstract_obj::serialize(THD *thd, String *image) { -public: - TblGrantObj(const String *grantee, - const String *db_name, - const String *table_name, - const String *priv_type); + ulong sql_mode_saved= thd->variables.sql_mode; + thd->variables.sql_mode= 0; -public: + Out_stream out_stream(image); - 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. + bool ret= do_serialize(thd, out_stream); + thd->variables.sql_mode= sql_mode_saved; -private: - virtual bool do_serialize(THD *thd, String *serialization); + return ret; +} - // These attributes are to be used only for materialization. - String m_grant_stmt; -}; +/////////////////////////////////////////////////////////////////////////// /** - @class ColGrantObj + Create the object in the database. + + @param[in] thd Server thread context. - This class provides an abstraction to column-level grants. - This class will permit the recording and replaying of these - grants. + @return Error status. + @retval FALSE on success. + @retval TRUE on error. */ -class ColGrantObj : public TblGrantObj + +bool Abstract_obj::create(THD *thd) { -public: - ColGrantObj(const String *grantee, - const String *db_name, - const String *table_name, - const String *col_name, - const String *priv_type); + bool rc= FALSE; + List_iterator_fast it(m_stmt_list); + LEX_STRING *sql_text; + Si_session_context session_context; -public: + DBUG_ENTER("Abstract_obj::create"); + + /* + Drop the object if it exists first of all. + + @note this semantics will be changed in the future. + That's why drop() is a public separate operation of Obj. + */ + drop(thd); - const String *get_col_name() + /* + Now, proceed with creating the object. + */ + session_context.save_si_ctx(thd); + session_context.reset_si_ctx(thd); + + /* Allow to execute DDL operations. */ + ::obs::ddl_blocker_exception_on(thd); + + /* Run queries from the serialization image. */ + while ((sql_text= it++)) { - return &m_col_name; + Ed_result ed_result; + + rc= mysql_execute_direct(thd, *sql_text, &ed_result); + + /* Push warnings on the THD error stack. */ + copy_warnings(thd, &ed_result.get_warnings()); + + if (rc) + break; } -protected: - // These attributes are to be used only for serialization. - String m_col_name; ///< corresponds with COLUMN_NAME in IS tables. + /* Disable further DDL execution. */ + ::obs::ddl_blocker_exception_off(thd); -private: - virtual bool do_serialize(THD *thd, String *serialization); + session_context.restore_si_ctx(thd); - // These attributes are to be used only for materialization. - String m_grant_stmt; -}; + DBUG_RETURN(rc); +} /////////////////////////////////////////////////////////////////////////// -// -// Implementation: iterator impl classes. -// +/** + Drop the object in the database. -/////////////////////////////////////////////////////////////////////////// + @param[in] thd Server thread context. + + @return Error status. + @retval FALSE on success. + @retval TRUE on error. +*/ -class InformationSchemaIterator : public Obj_iterator +bool Abstract_obj::drop(THD *thd) { -public: - static bool prepare_is_table( - THD *thd, - TABLE **is_table, - handler **ha, - my_bitmap_map **orig_columns, - enum_schema_tables is_table_idx, - List db_list); - -public: - InformationSchemaIterator(THD *thd, - TABLE *is_table, - handler *ha, - my_bitmap_map *orig_columns) - : - m_thd(thd), - m_is_table(is_table), - m_ha(ha), - m_orig_columns(orig_columns) - { } + String_stream s_stream; + const LEX_STRING *sql_text; - virtual ~InformationSchemaIterator(); + DBUG_ENTER("Abstract_obj::drop"); -public: - virtual Obj *next(); + build_drop_statement(s_stream); + sql_text= s_stream.lex_string(); -protected: - virtual Obj *create_obj(TABLE *t) = 0; - THD *m_thd; + if (!sql_text->str || !sql_text->length) + DBUG_RETURN(FALSE); -private: - TABLE *m_is_table; - handler *m_ha; - my_bitmap_map *m_orig_columns; + Si_session_context session_context; -}; + session_context.save_si_ctx(thd); + session_context.reset_si_ctx(thd); -/////////////////////////////////////////////////////////////////////////// + /* Allow to execute DDL operations. */ + ::obs::ddl_blocker_exception_on(thd); -class ObjIteratorDummyImpl : Obj_iterator -{ -public: - ObjIteratorDummyImpl() { return; } - virtual ~ObjIteratorDummyImpl() { return; } - virtual Obj *next() { return NULL; } + Ed_result ed_result; -protected: - virtual Obj *create_obj(TABLE *t) { return NULL; } + /* Execute DDL operation. */ + bool rc= mysql_execute_direct(thd, *sql_text, &ed_result); -}; + /* Disable further DDL execution. */ + ::obs::ddl_blocker_exception_off(thd); + + session_context.restore_si_ctx(thd); + + DBUG_RETURN(rc); +} /////////////////////////////////////////////////////////////////////////// -class DatabaseIterator : public InformationSchemaIterator + +bool Abstract_obj::init_from_image(uint image_version, const String *image) { -public: - DatabaseIterator(THD *thd, - TABLE *is_table, - handler *ha, - my_bitmap_map *orig_columns) : - InformationSchemaIterator(thd, is_table, ha, orig_columns) - { } + In_stream is(image_version, image); -protected: - virtual DatabaseObj *create_obj(TABLE *t); -}; + return do_init_from_image(&is); +} /////////////////////////////////////////////////////////////////////////// -class DbTablesIterator : public InformationSchemaIterator +bool Abstract_obj::do_init_from_image(In_stream *is) { -public: - DbTablesIterator(THD *thd, - const String *db_name, - TABLE *is_table, - handler *ha, - my_bitmap_map *orig_columns) : - InformationSchemaIterator(thd, is_table, ha, orig_columns) + LEX_STRING sql_text; + while (! is->next(&sql_text)) { - m_db_name.copy(*db_name); - } + LEX_STRING *sql_text_root= (LEX_STRING *) alloc_root(&m_mem_root, + sizeof (LEX_STRING)); -protected: - virtual TableObj *create_obj(TABLE *t); - - virtual bool is_type_accepted(const String *type) const; + if (!sql_text_root) + return TRUE; - virtual bool is_engine_accepted(const String *engine) const; + sql_text_root->str= strmake_root(&m_mem_root, + sql_text.str, sql_text.length); + sql_text_root->length= sql_text.length; - virtual TableObj *create_table_obj(const String *db_name, - const String *table_name) const; + if (!sql_text_root->str || m_stmt_list.push_back(sql_text_root)) + return TRUE; + } -private: - String m_db_name; -}; + return FALSE; +} /////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// -class DbViewsIterator : public DbTablesIterator +/** + @class Database_obj + + This class provides an abstraction to a database object for creation and + capture of the creation data. +*/ + +class Database_obj : public Abstract_obj { public: - DbViewsIterator(THD *thd, - const String *db_name, - TABLE *is_tables, - handler *ha, - my_bitmap_map *orig_columns) - : DbTablesIterator(thd, db_name, is_tables, ha, orig_columns) + inline Database_obj(const Ed_row &ed_row) + : Abstract_obj(ed_row[0] /* database name */) { } -protected: - virtual bool is_type_accepted(const String *type) const; + inline Database_obj(LEX_STRING db_name) + : Abstract_obj(db_name) + { } - virtual bool is_engine_accepted(const String *engine) const - { - return true; - } +public: + virtual inline const String *get_db_name() const { return get_name(); } - virtual TableObj *create_table_obj(const String *db_name, - const String *table_name) const; +private: + virtual bool do_serialize(THD *thd, Out_stream &out_stream); + virtual void build_drop_statement(String_stream &s_stream) const; }; /////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// + +/** + @class Database_item_obj -class DbTriggerIterator : public InformationSchemaIterator + This class is a base class for all classes representing objects, which + belong to a Database. +*/ + +class Database_item_obj : public Abstract_obj { public: - DbTriggerIterator(THD *thd, - const String *db_name, - TABLE *is_table, - handler *ha, - my_bitmap_map *orig_columns) : - InformationSchemaIterator(thd, is_table, ha, orig_columns) + inline Database_item_obj(LEX_STRING db_name, LEX_STRING object_name) + : Abstract_obj(object_name) { - m_db_name.copy(*db_name); + if (db_name.str && db_name.length) + m_db_name.copy(db_name.str, db_name.length, system_charset_info); + else + m_db_name.length(0); } +public: + virtual inline const String *get_db_name() const { return &m_db_name; } + protected: - virtual TriggerObj *create_obj(TABLE *t); + virtual const LEX_STRING *get_type_name() const = 0; + virtual void build_drop_statement(String_stream &s_stream) const; -private: +protected: String m_db_name; }; /////////////////////////////////////////////////////////////////////////// -class DbStoredProcIterator : public InformationSchemaIterator +void Database_item_obj::build_drop_statement(String_stream &s_stream) const { -public: - DbStoredProcIterator(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); - } + s_stream << + "DROP " << get_type_name() << " IF EXISTS `" << get_name() << "`"; +} -protected: - virtual Obj *create_obj(TABLE *t); +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// - virtual bool check_type(const String *sr_type) const; +/** + @class Table_obj - virtual Obj *create_sr_object(const String *db_name, - const String *sr_name); + This class provides an abstraction to a table object for creation and + capture of the creation data. +*/ +class Table_obj : public Database_item_obj +{ private: - String m_db_name; -}; + static const LEX_STRING TYPE_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); - } + inline Table_obj(const Ed_row &ed_row) + : Database_item_obj(ed_row[0], /* database name */ + ed_row[1]) /* table name */ + { } -protected: - virtual DbGrantObj *create_obj(TABLE *t); + inline Table_obj(LEX_STRING db_name, LEX_STRING table_name) + : Database_item_obj(db_name, table_name) + { } private: - String m_db_name; + virtual bool do_serialize(THD *thd, Out_stream &out_stream); + + virtual inline const LEX_STRING *get_type_name() const + { return &Table_obj::TYPE_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); +const LEX_STRING Table_obj::TYPE_NAME= LXS_INIT("TABLE"); -private: - String m_db_name; -}; +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// -class ColGrantIterator : public InformationSchemaIterator +/** + @class View_obj + + This class provides an abstraction to a view object for creation and + capture of the creation data. +*/ + +class View_obj : public Database_item_obj { +private: + static const LEX_STRING TYPE_NAME; + 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); - } + inline View_obj(const Ed_row &ed_row) + : Database_item_obj(ed_row[0], /* schema name */ + ed_row[1]) /* view name */ + { } -protected: - virtual ColGrantObj *create_obj(TABLE *t); + inline View_obj(LEX_STRING db_name, LEX_STRING view_name) + : Database_item_obj(db_name, view_name) + { } private: - String m_db_name; + virtual bool do_serialize(THD *thd, Out_stream &out_stream); + + virtual inline const LEX_STRING *get_type_name() const + { return &View_obj::TYPE_NAME; } }; +/////////////////////////////////////////////////////////////////////////// + +const LEX_STRING View_obj::TYPE_NAME= LXS_INIT("VIEW"); /////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// -class DbStoredFuncIterator : public DbStoredProcIterator +/** + @class Stored_program_obj + + This is a base class for stored program objects: stored procedures, + stored functions, triggers, events. +*/ + +class Stored_program_obj : public Database_item_obj { public: - DbStoredFuncIterator(THD *thd, - const String *db_name, - TABLE *is_table, - handler *ha, - my_bitmap_map *orig_columns) : - DbStoredProcIterator(thd, db_name, is_table, ha, orig_columns) + inline Stored_program_obj(LEX_STRING db_name, LEX_STRING sp_name) + : Database_item_obj(db_name, sp_name) { } protected: - virtual bool check_type(const String *sr_type) const; + virtual const LEX_STRING *get_create_stmt(Ed_row *row) = 0; + virtual void dump_header(Ed_row *row, Out_stream &out_stream) = 0; - virtual Obj *create_sr_object(const String *db_name, - const String *sr_name); +private: + virtual bool do_serialize(THD *thd, Out_stream &out_stream); }; /////////////////////////////////////////////////////////////////////////// -#ifdef HAVE_EVENT_SCHEDULER -class DbEventIterator : public InformationSchemaIterator +/////////////////////////////////////////////////////////////////////////// + +/** + @class Stored_routine_obj + + This is a base class for stored routine objects: stored procedures, + stored functions, triggers. +*/ + +class Stored_routine_obj : public Stored_program_obj { public: - DbEventIterator(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); - } + inline Stored_routine_obj(LEX_STRING db_name, LEX_STRING sr_name) + : Stored_program_obj(db_name, sr_name) + { } protected: - virtual EventObj *create_obj(TABLE *t); - -private: - String m_db_name; + virtual const LEX_STRING *get_create_stmt(Ed_row *row); + virtual void dump_header(Ed_row *row, Out_stream &out_stream); }; -#endif /////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// -class ViewBaseObjectsIterator : public Obj_iterator -{ -public: - enum IteratorType - { - GET_BASE_TABLES, - GET_BASE_VIEWS - }; - -public: - virtual ~ViewBaseObjectsIterator(); +/** + @class Trigger_obj -public: - virtual TableObj *next(); + This class provides an abstraction to a trigger object for creation and + capture of the creation data. +*/ +class Trigger_obj : public Stored_routine_obj +{ private: - static ViewBaseObjectsIterator *create(THD *thd, - const String *db_name, - const String *view_name, - IteratorType iterator_type ); + static const LEX_STRING TYPE_NAME; -private: - ViewBaseObjectsIterator(HASH *table_names); +public: + inline Trigger_obj(const Ed_row &ed_row) + : Stored_routine_obj(ed_row[0], ed_row[1]) + { } -private: - HASH *m_table_names; - uint m_cur_idx; + inline Trigger_obj(LEX_STRING db_name, LEX_STRING trigger_name) + : Stored_routine_obj(db_name, trigger_name) + { } private: - friend Obj_iterator *get_view_base_tables(THD *, - const String *, - const String *); - - friend Obj_iterator *get_view_base_views(THD *, - const String *, - const String *); + virtual inline const LEX_STRING *get_type_name() const + { return &Trigger_obj::TYPE_NAME; } }; /////////////////////////////////////////////////////////////////////////// -// -// Implementation: InformationSchemaIterator class. -// +const LEX_STRING Trigger_obj::TYPE_NAME= LXS_INIT("TRIGGER"); /////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// + +/** + @class Stored_proc_obj -bool InformationSchemaIterator::prepare_is_table( - THD *thd, - TABLE **is_table, - handler **ha, - my_bitmap_map **orig_columns, - enum_schema_tables is_table_idx, - List db_list) + This class provides an abstraction to a stored procedure object for creation + and capture of the creation data. +*/ + +class Stored_proc_obj : public Stored_routine_obj { - ST_SCHEMA_TABLE *st= get_schema_table(is_table_idx); - if (!(*is_table= open_schema_table(thd, st, &db_list))) - return TRUE; +private: + static const LEX_STRING TYPE_NAME; - *ha= (*is_table)->file; +public: + inline Stored_proc_obj(const Ed_row &ed_row) + : Stored_routine_obj(ed_row[0], ed_row[1]) + { } - if (!*ha) - { - free_tmp_table(thd, *is_table); - return TRUE; - } + inline Stored_proc_obj(LEX_STRING db_name, LEX_STRING sp_name) + : Stored_routine_obj(db_name, sp_name) + { } - *orig_columns= - dbug_tmp_use_all_columns(*is_table, (*is_table)->read_set); +private: + virtual inline const LEX_STRING *get_type_name() const + { return &Stored_proc_obj::TYPE_NAME; } +}; - if ((*ha)->ha_rnd_init(TRUE)) - { - dbug_tmp_restore_column_map((*is_table)->read_set, *orig_columns); - free_tmp_table(thd, *is_table); - return TRUE; - } +/////////////////////////////////////////////////////////////////////////// - return FALSE; -} +const LEX_STRING Stored_proc_obj::TYPE_NAME= LXS_INIT("PROCEDURE"); -InformationSchemaIterator::~InformationSchemaIterator() -{ - m_ha->ha_rnd_end(); +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// - dbug_tmp_restore_column_map(m_is_table->read_set, m_orig_columns); - free_tmp_table(m_thd, m_is_table); -} +/** + @class Stored_func_obj -Obj *InformationSchemaIterator::next() + This class provides an abstraction to a stored function object for creation + and capture of the creation data. +*/ + +class Stored_func_obj : public Stored_routine_obj { - while (true) - { - if (m_ha->rnd_next(m_is_table->record[0])) - return NULL; +private: + static const LEX_STRING TYPE_NAME; - Obj *obj= create_obj(m_is_table); +public: + inline Stored_func_obj(const Ed_row &ed_row) + : Stored_routine_obj(ed_row[0], ed_row[1]) + { } - if (obj) - return obj; - } -} + inline Stored_func_obj(LEX_STRING db_name, LEX_STRING sf_name) + : Stored_routine_obj(db_name, sf_name) + { } + +private: + virtual inline const LEX_STRING *get_type_name() const + { return &Stored_func_obj::TYPE_NAME; } +}; /////////////////////////////////////////////////////////////////////////// -// -// Implementation: DatabaseIterator class. -// +const LEX_STRING Stored_func_obj::TYPE_NAME= LXS_INIT("FUNCTION"); /////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// -DatabaseObj* DatabaseIterator::create_obj(TABLE *t) +#ifdef HAVE_EVENT_SCHEDULER + +/** + @class Event_obj + + This class provides an abstraction to a event object for creation and capture + of the creation data. +*/ + +class Event_obj : public Stored_program_obj { - String name; +private: + static const LEX_STRING TYPE_NAME; + +public: + inline Event_obj(const Ed_row &ed_row) + : Stored_program_obj(ed_row[0], ed_row[1]) + { } + + inline Event_obj(LEX_STRING db_name, LEX_STRING event_name) + : Stored_program_obj(db_name, event_name) + { } - t->field[1]->val_str(&name); +private: + virtual inline const LEX_STRING *get_type_name() const + { return &Event_obj::TYPE_NAME; } - DBUG_PRINT("DatabaseIterator::next", (" Found database %s", name.ptr())); + virtual inline const LEX_STRING *get_create_stmt(Ed_row *row) + { return row->get_column(3); } - return new DatabaseObj(&name); -} + virtual void dump_header(Ed_row *row, Out_stream &out_stream); +}; /////////////////////////////////////////////////////////////////////////// -// -// Implementation: DbTablesIterator class. -// +const LEX_STRING Event_obj::TYPE_NAME= LXS_INIT("EVENT"); + +#endif // HAVE_EVENT_SCHEDULER /////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// -TableObj* DbTablesIterator::create_obj(TABLE *t) -{ - String table_name; - String db_name; - String type; - String engine; +/** + @class Tablespace_obj - t->field[1]->val_str(&db_name); - t->field[2]->val_str(&table_name); - t->field[3]->val_str(&type); - t->field[4]->val_str(&engine); + This class provides an abstraction to a user object for creation and + capture of the creation data. +*/ - // Skip tables not from the given database. +class Tablespace_obj : public Abstract_obj +{ +public: + Tablespace_obj(LEX_STRING ts_name, + LEX_STRING comment, + LEX_STRING data_file_name, + LEX_STRING engine_name); - if (db_name != m_db_name) - return NULL; + Tablespace_obj(LEX_STRING ts_name); - // Skip tables/views depending on enumerate_views flag. +public: + const String *get_description(); - if (!is_type_accepted(&type)) - return NULL; +public: + virtual bool init_from_image(uint image_version, const String *image); - // TODO: actually, Backup Kernel needs to know also tables with - // invalid/empty engines. It is required so that Backup Kernel can throw - // a warning to the user. +private: + virtual bool do_serialize(THD *thd, Out_stream &out_stream); + virtual void build_drop_statement(String_stream &s_stream) const; - if (!is_engine_accepted(&engine)) - return NULL; +private: + /* These attributes are to be used only for serialization. */ + String m_comment; + String m_data_file_name; + String m_engine; - DBUG_PRINT("DbTablesIterator::next", (" Found table %s.%s", - db_name.ptr(), table_name.ptr())); +private: + String m_description; +}; - return create_table_obj(&db_name, &table_name); -} +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// -bool DbTablesIterator::is_type_accepted(const String *type) const -{ - return my_strcasecmp(system_charset_info, - ((String *) type)->c_ptr_safe(), "BASE TABLE") == 0; -} +/** + @class Grant_obj -bool DbTablesIterator::is_engine_accepted(const String *engine) const -{ - return engine->length() > 0; -} + This class provides an abstraction to grants. This class will permit the + recording and replaying of these grants. +*/ -TableObj *DbTablesIterator::create_table_obj(const String *db_name, - const String *table_name) const +class Grant_obj : public Abstract_obj { - return new TableObj(db_name, table_name, false); -} +public: + static void generate_unique_grant_id(const String *user_name, String *id); -/////////////////////////////////////////////////////////////////////////// +public: + Grant_obj(LEX_STRING grant_id); + Grant_obj(const Ed_row &ed_row); -// -// Implementation: DbViewsIterator class. -// +public: + inline const String *get_user_name() const { return &m_user_name; } + inline const String *get_grant_info() const { return &m_grant_info; } -/////////////////////////////////////////////////////////////////////////// +private: + virtual bool do_init_from_image(In_stream *is); + inline virtual void build_drop_statement(String_stream &s_stream) const + { } -bool DbViewsIterator::is_type_accepted(const String *type) const -{ - return my_strcasecmp(system_charset_info, - ((String *) type)->c_ptr_safe(), "VIEW") == 0; -} +private: + /* These attributes are to be used only for serialization. */ + String m_user_name; + String m_grant_info; //< contains privilege definition -TableObj *DbViewsIterator::create_table_obj(const String *db_name, - const String *table_name) const -{ - return new TableObj(db_name, table_name, true); -} +private: + virtual bool do_serialize(THD *thd, Out_stream &out_stream); +}; /////////////////////////////////////////////////////////////////////////// - -// -// Implementation: DbTriggerIterator class. -// - /////////////////////////////////////////////////////////////////////////// -TriggerObj *DbTriggerIterator::create_obj(TABLE *t) +template +Iterator *create_row_set_iterator(THD *thd, const LEX_STRING *query) { - String db_name; - String trigger_name; + Ed_result *ed_result= new Ed_result(); - t->field[1]->val_str(&db_name); - t->field[2]->val_str(&trigger_name); - - // Skip triggers not from the given database. - - if (db_name != m_db_name) + if (run_service_interface_sql(thd, query, ed_result) || + ed_result->get_warnings().elements > 0) + { + /* There should be no warnings. */ + delete ed_result; return NULL; + } + + /* The result must contain only one result-set. */ + DBUG_ASSERT(ed_result->elements == 1); - return new TriggerObj(&db_name, &trigger_name); + return new Iterator(ed_result); } /////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// -// -// Implementation: DbStoredProcIterator class. -// +/** + @class Ed_result_set_iterator -/////////////////////////////////////////////////////////////////////////// + This is an implementation of Obj_iterator, which creates objects from a + result set (represented by an instance of Ed_result). +*/ -Obj *DbStoredProcIterator::create_obj(TABLE *t) +template +class Ed_result_set_iterator : public Obj_iterator { - String db_name; - String sr_name; - String sr_type; +public: + inline Ed_result_set_iterator(Ed_result *ed_result); + inline ~Ed_result_set_iterator(); - t->field[2]->val_str(&db_name); - t->field[3]->val_str(&sr_name); - t->field[4]->val_str(&sr_type); +public: + virtual Obj *next(); - // Skip stored procedure not from the given database. +private: + Ed_result *m_ed_result; + List_iterator_fast m_row_it; +}; - if (db_name != m_db_name) - return NULL; +/////////////////////////////////////////////////////////////////////////// - if (!check_type(&sr_type)) - return NULL; +template +inline +Ed_result_set_iterator:: +Ed_result_set_iterator(Ed_result *ed_result) + : m_ed_result(ed_result), + m_row_it(*ed_result->get_cur_result_set()->data()) +{ } - return create_sr_object(&db_name, &sr_name); -} +/////////////////////////////////////////////////////////////////////////// -bool DbStoredProcIterator::check_type(const String *sr_type) const +template +inline +Ed_result_set_iterator::~Ed_result_set_iterator() { - return - my_strcasecmp(system_charset_info, - ((String *) sr_type)->c_ptr_safe(), - "PROCEDURE") == 0; + delete m_ed_result; } -Obj *DbStoredProcIterator::create_sr_object(const String *db_name, - const String *sr_name) + +template +Obj * +Ed_result_set_iterator::next() { - return new StoredProcObj(db_name, sr_name); -} + Ed_row *ed_row= m_row_it++; -/////////////////////////////////////////////////////////////////////////// + if (!ed_row) + return NULL; -// -// Implementation: DbStoredFuncIterator class. -// + return new Obj_type(*ed_row); +} /////////////////////////////////////////////////////////////////////////// -bool DbStoredFuncIterator::check_type(const String *sr_type) const -{ - return - my_strcasecmp(system_charset_info, - ((String *) sr_type)->c_ptr_safe(), - "FUNCTION") == 0; -} +typedef Ed_result_set_iterator Database_iterator; +typedef Ed_result_set_iterator Db_tables_iterator; +typedef Ed_result_set_iterator Db_views_iterator; +typedef Ed_result_set_iterator Db_trigger_iterator; +typedef Ed_result_set_iterator Db_stored_proc_iterator; +typedef Ed_result_set_iterator Db_stored_func_iterator; +#ifdef HAVE_EVENT_SCHEDULER +typedef Ed_result_set_iterator Db_event_iterator; +#endif +typedef Ed_result_set_iterator Grant_iterator; -Obj *DbStoredFuncIterator::create_sr_object(const String *db_name, - const String *sr_name) -{ - return new StoredFuncObj(db_name, sr_name); -} +/////////////////////////////////////////////////////////////////////////// +#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION +template class Ed_result_set_iterator; +template class Ed_result_set_iterator; +template class Ed_result_set_iterator; +template class Ed_result_set_iterator; +template class Ed_result_set_iterator; +template class Ed_result_set_iterator; #ifdef HAVE_EVENT_SCHEDULER -/////////////////////////////////////////////////////////////////////////// +template class Ed_result_set_iterator; +#endif +template class Ed_result_set_iterator; -// -// Implementation: DbEventIterator class. -// +template +Database_iterator * +create_row_set_iterator(THD *thd, const LEX_STRING *query); -/////////////////////////////////////////////////////////////////////////// -EventObj *DbEventIterator::create_obj(TABLE *t) -{ - String db_name; - String event_name; +template +Db_tables_iterator * +create_row_set_iterator(THD *thd, const LEX_STRING *query); - t->field[1]->val_str(&db_name); - t->field[2]->val_str(&event_name); +template +Db_views_iterator * +create_row_set_iterator(THD *thd, const LEX_STRING *query); - // Skip event not from the given database. +template +Db_trigger_iterator * +create_row_set_iterator(THD *thd, const LEX_STRING *query); - if (db_name != m_db_name) - return NULL; +template +Db_stored_proc_iterator * +create_row_set_iterator(THD *thd, + const LEX_STRING *query); - return new EventObj(&db_name, &event_name); -} +template +Db_stored_func_iterator * +create_row_set_iterator(THD *thd, + const LEX_STRING *query); + +#ifdef HAVE_EVENT_SCHEDULER +template +Db_event_iterator * +create_row_set_iterator(THD *thd, const LEX_STRING *query); #endif -/////////////////////////////////////////////////////////////////////////// +template +Grant_iterator * +create_row_set_iterator(THD *thd, const LEX_STRING *query); -// -// Implementation: DbGrantIterator class. -// +#endif // HAVE_EXPLICIT_TEMPLATE_INSTANTIATION /////////////////////////////////////////////////////////////////////////// -DbGrantObj* DbGrantIterator::create_obj(TABLE *t) +/** + @class View_base_iterator + + This is a base implementation of Obj_iterator for the + view-dependency-object iterators. +*/ + +class View_base_obj_iterator : public Obj_iterator { - 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); +public: + inline View_base_obj_iterator(); + virtual inline ~View_base_obj_iterator(); - /* - 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. +public: + virtual Obj *next(); - 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())); + enum enum_base_obj_kind { BASE_TABLE= 0, VIEW }; - /* - Include grants for only users that exist at time of backup. - */ - if (check_user_existence(m_thd, &grantee)) - return new DbGrantObj(&grantee, &db_name, &priv_type); - else - return NULL; - } - else - return NULL; -} + virtual enum_base_obj_kind get_base_obj_kind() const= 0; -/////////////////////////////////////////////////////////////////////////// +protected: + template + static Iterator *create(THD *thd, + const String *db_name, const String *view_name); -// -// Implementation: TblGrantIterator class. -// +protected: + bool init(THD *thd, const String *db_name, const String *view_name); + + virtual Obj *create_obj(const LEX_STRING *db_name, + const LEX_STRING *obj_name)= 0; + +private: + HASH m_table_names; + uint m_cur_idx; +}; /////////////////////////////////////////////////////////////////////////// -TblGrantObj* TblGrantIterator::create_obj(TABLE *t) +template +Iterator *View_base_obj_iterator::create(THD *thd, + const String *db_name, + const String *view_name) { - 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. + Iterator *it= new Iterator(); - Ensure the only rows sent back from iterator are the ones that match the - database specified. - */ - if (db_name == m_db_name) + if (it->init(thd, db_name, view_name)) { - DBUG_PRINT("TblGrantIterator::create", (" Found grant %s %s %s %s", - db_name.ptr(), grantee.ptr(), tbl_name.ptr(), priv_type.ptr())); - - /* - Include grants for only users that exist at time of backup. - */ - if (check_user_existence(m_thd, &grantee)) - return new TblGrantObj(&grantee, &db_name, &tbl_name, &priv_type); - else - return NULL; - } - else + delete it; return NULL; + } + + return it; } /////////////////////////////////////////////////////////////////////////// -// -// Implementation: ColGrantIterator class. -// +inline View_base_obj_iterator::View_base_obj_iterator() + :m_cur_idx(0) +{ + hash_init(&m_table_names, system_charset_info, 16, 0, 0, + get_table_name_key, free_table_name_key, + MYF(0)); +} /////////////////////////////////////////////////////////////////////////// -ColGrantObj* ColGrantIterator::create_obj(TABLE *t) +inline View_base_obj_iterator::~View_base_obj_iterator() { - 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); + hash_free(&m_table_names); +} - /* - 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())); +/** + Find all base tables or views of a view. +*/ - /* - Include grants for only users that exist at time of backup. - */ - if (check_user_existence(m_thd, &grantee)) - return new ColGrantObj(&grantee, &db_name, &tbl_name, - &col_name, &priv_type); - else - return NULL; - } - else - return NULL; -} +class Find_view_underlying_tables: public Server_runnable +{ +public: + Find_view_underlying_tables(const View_base_obj_iterator *base_obj_it, + HASH *table_names, + const String *db_name, + const String *view_name); -/////////////////////////////////////////////////////////////////////////// + bool execute_server_code(THD *thd); +private: + /* Store the resulting unique here */ + const View_base_obj_iterator *m_base_obj_it; + HASH *m_table_names; + const String *m_db_name; + const String *m_view_name; +}; -// -// Implementation: ViewBaseObjectsIterator class. -// -/////////////////////////////////////////////////////////////////////////// +Find_view_underlying_tables:: +Find_view_underlying_tables(const View_base_obj_iterator *base_obj_it, + HASH *table_names, + const String *db_name, + const String *view_name) + :m_base_obj_it(base_obj_it), + m_table_names(table_names), + m_db_name(db_name), + m_view_name(view_name) +{ +} -ViewBaseObjectsIterator * -ViewBaseObjectsIterator::create(THD *thd, - const String *db_name, - const String *view_name, - IteratorType iterator_type) + +bool +Find_view_underlying_tables::execute_server_code(THD *thd) { - uint table_count; // Passed to open_tables(). Not used. - THD *my_thd= new THD(); + bool res= TRUE; + uint counter_not_used; /* Passed to open_tables(). Not used. */ - my_thd->security_ctx= thd->security_ctx; + TABLE_LIST *table_list; - my_thd->thread_stack= (char*) &my_thd; - my_thd->store_globals(); - lex_start(my_thd); - - TABLE_LIST *tl = - sp_add_to_query_tables(my_thd, - my_thd->lex, - ((String *) db_name)->c_ptr_safe(), - ((String *) view_name)->c_ptr_safe(), - TL_READ); - - if (open_tables(my_thd, &tl, &table_count, 0)) - { - close_thread_tables(my_thd); - delete my_thd; - thd->store_globals(); + DBUG_ENTER("Find_view_underlying_tables::execute_server_code"); - return NULL; - } + lex_start(thd); + table_list= sp_add_to_query_tables(thd, thd->lex, + ((String *) m_db_name)->c_ptr_safe(), + ((String *) m_view_name)->c_ptr_safe(), + TL_READ); - HASH *table_names = new HASH(); + if (table_list == NULL) /* out of memory, reported */ + { + lex_end(thd->lex); + DBUG_RETURN(TRUE); + } - hash_init(table_names, system_charset_info, 16, 0, 0, - get_table_name_key, - delete_table_name_key, - MYF(0)); + if (open_tables(thd, &table_list, &counter_not_used, + MYSQL_OPEN_SKIP_TEMPORARY)) + goto end; - if (tl->view_tables) + if (table_list->view_tables) { - List_iterator_fast it(*tl->view_tables); - TABLE_LIST *tl2; + TABLE_LIST *table; + List_iterator_fast it(*table_list->view_tables); - while ((tl2 = it++)) + /* + Iterate over immediate underlying tables. + The list doesn't include views or tables referenced indirectly, + through other views, or stored functions or triggers. + */ + while ((table= it++)) { - Table_name_key *tnk= - new Table_name_key(tl2->db, tl2->db_length, - tl2->table_name, tl2->table_name_length); + Table_name_key *table_name_key; + char *key_buff; - if (iterator_type == GET_BASE_TABLES && tl2->view || - iterator_type == GET_BASE_VIEWS && !tl2->view) - { - delete tnk; + /* If we expect a view, and it's a table, or vice versa, continue */ + if ((int) m_base_obj_it->get_base_obj_kind() != test(table->view)) continue; - } - if (!hash_search(table_names, - (uchar *) tnk->key.c_ptr_safe(), - tnk->key.length())) - { - my_hash_insert(table_names, (uchar *) tnk); - } - else + if (! my_multi_malloc(MYF(MY_WME), + &table_name_key, sizeof(*table_name_key), + &key_buff, table->mdl_lock_data->key_length, + NullS)) + goto end; + + table_name_key->init_from_mdl_key(table->mdl_lock_data->key, + table->mdl_lock_data->key_length, + key_buff); + + if (my_hash_insert(m_table_names, (uchar*) table_name_key)) { - delete tnk; + my_free(table_name_key, MYF(0)); + goto end; } } } + res= FALSE; + my_ok(thd); - close_thread_tables(my_thd); - delete my_thd; - - thd->store_globals(); - - return new ViewBaseObjectsIterator(table_names); +end: + lex_end(thd->lex); + DBUG_RETURN(res); } -ViewBaseObjectsIterator::ViewBaseObjectsIterator(HASH *table_names) : - m_table_names(table_names), - m_cur_idx(0) -{ -} +/////////////////////////////////////////////////////////////////////////// -ViewBaseObjectsIterator::~ViewBaseObjectsIterator() +bool View_base_obj_iterator::init(THD *thd, + const String *db_name, + const String *view_name) { - hash_free(m_table_names); - delete m_table_names; -} + Find_view_underlying_tables find_tables(this, &m_table_names, + db_name, view_name); + Ed_result ed_result; /* Just to grab OK or ERROR */ -TableObj *ViewBaseObjectsIterator::next() -{ - if (m_cur_idx >= m_table_names->records) - return NULL; + if (mysql_execute_direct(thd, &find_tables, &ed_result)) + return TRUE; - Table_name_key *tnk= - (Table_name_key *) hash_element(m_table_names, m_cur_idx); + /* The table list is filled with unique underlying table names. */ - ++m_cur_idx; - - return new TableObj(&tnk->db_name, &tnk->table_name, false); + return FALSE; } /////////////////////////////////////////////////////////////////////////// -// -// Implementation: enumeration functions. -// - -/////////////////////////////////////////////////////////////////////////// - -Obj_iterator *get_databases(THD *thd) +Obj *View_base_obj_iterator::next() { - TABLE *is_table; - handler *ha; - my_bitmap_map *orig_columns; - - if (InformationSchemaIterator::prepare_is_table( - thd, &is_table, &ha, &orig_columns, SCH_SCHEMATA, - thd->lex->db_list)) + if (m_cur_idx >= m_table_names.records) return NULL; - return new DatabaseIterator(thd, is_table, ha, orig_columns); -} + Table_name_key *table_name_key= + (Table_name_key *) hash_element(&m_table_names, m_cur_idx); -template -Iterator *create_is_iterator(THD *thd, - enum_schema_tables is_table_idx, - const String *db_name) -{ - TABLE *is_table; - handler *ha; - my_bitmap_map *orig_columns; - - LEX_STRING dbname; - String db; - db.copy(*db_name); - thd->make_lex_string(&dbname, db.c_ptr(), db.length(), FALSE); - List db_list; - db_list.push_back(&dbname); - - if (InformationSchemaIterator::prepare_is_table( - thd, &is_table, &ha, &orig_columns, is_table_idx, - db_list)) - return NULL; + ++m_cur_idx; - return new Iterator(thd, db_name, is_table, ha, orig_columns); + return create_obj(&table_name_key->db_name, &table_name_key->table_name); } -template -DbTablesIterator * -create_is_iterator(THD *, enum_schema_tables, const String *); - -template -DbViewsIterator * -create_is_iterator(THD *, enum_schema_tables, const String *); - -template -DbTriggerIterator * -create_is_iterator(THD *, enum_schema_tables, const String *); - -template -DbStoredProcIterator * -create_is_iterator(THD *, enum_schema_tables, const String *); - -template -DbStoredFuncIterator * -create_is_iterator(THD *, enum_schema_tables, const String *); - -#ifdef HAVE_EVENT_SCHEDULER -template -DbEventIterator * -create_is_iterator(THD *, enum_schema_tables, const String *); -#endif - -template -DbGrantIterator * -create_is_iterator(THD *, enum_schema_tables, const String *); - -template -TblGrantIterator * -create_is_iterator(THD *, enum_schema_tables, const String *); - -template -ColGrantIterator * -create_is_iterator(THD *, enum_schema_tables, const String *); +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// -Obj_iterator *get_db_tables(THD *thd, const String *db_name) -{ - return create_is_iterator(thd, SCH_TABLES, db_name); -} +/** + @class View_base_table_iterator -Obj_iterator *get_db_views(THD *thd, const String *db_name) -{ - return create_is_iterator(thd, SCH_TABLES, db_name); -} + This is an iterator over base tables for a view. +*/ -Obj_iterator *get_db_triggers(THD *thd, const String *db_name) +class View_base_table_iterator : public View_base_obj_iterator { - return create_is_iterator(thd, SCH_TRIGGERS, db_name); -} +public: + static inline View_base_obj_iterator * + create(THD *thd, const String *db_name, const String *view_name) + { + return View_base_obj_iterator::create + (thd, db_name, view_name); + } -Obj_iterator *get_db_stored_procedures(THD *thd, const String *db_name) -{ - return create_is_iterator(thd, SCH_PROCEDURES, db_name); -} +protected: + virtual inline enum_base_obj_kind get_base_obj_kind() const + { return BASE_TABLE; } -Obj_iterator *get_db_stored_functions(THD *thd, const String *db_name) -{ - return create_is_iterator(thd, SCH_PROCEDURES, db_name); -} + virtual inline Obj *create_obj(const LEX_STRING *db_name, + const LEX_STRING *obj_name) + { return new Table_obj(*db_name, *obj_name); } +}; -Obj_iterator *get_db_events(THD *thd, const String *db_name) -{ -#ifdef HAVE_EVENT_SCHEDULER - return create_is_iterator(thd, SCH_EVENTS, db_name); -#else - return (Obj_iterator *)new ObjIteratorDummyImpl; -#endif -} +/////////////////////////////////////////////////////////////////////////// -/** - GrantObjIterator constructor +template +View_base_table_iterator * +View_base_obj_iterator:: +create(THD *thd, const String *db_name, + const String *view_name); - 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) -: Obj_iterator() -{ - db_grants= create_is_iterator(thd, - SCH_SCHEMA_PRIVILEGES, - db_name); - tbl_grants= create_is_iterator(thd, - SCH_TABLE_PRIVILEGES, - db_name); - col_grants= create_is_iterator(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 + @class View_base_view_iterator - @Note The client is responsible for destroying the returned iterator. - - @return a pointer to an iterator object. - @retval NULL in case of error. + This is an iterator over base views for a view. */ -Obj_iterator *get_all_db_grants(THD *thd, const String *db_name) + +class View_base_view_iterator : public View_base_obj_iterator { - return new GrantObjIterator(thd, db_name); -} +public: + static inline View_base_obj_iterator * + create(THD *thd, const String *db_name, const String *view_name) + { + return View_base_obj_iterator::create + (thd, db_name, view_name); + } -/////////////////////////////////////////////////////////////////////////// +protected: + virtual inline enum_base_obj_kind get_base_obj_kind() const { return VIEW; } -// -// Implementation: dependency functions. -// + virtual inline Obj *create_obj(const LEX_STRING *db_name, + const LEX_STRING *obj_name) + { return new View_obj(*db_name, *obj_name); } +}; /////////////////////////////////////////////////////////////////////////// -Obj_iterator* get_view_base_tables(THD *thd, - const String *db_name, - const String *view_name) -{ - return ViewBaseObjectsIterator::create( - thd, db_name, view_name, ViewBaseObjectsIterator::GET_BASE_TABLES); -} - -Obj_iterator* get_view_base_views(THD *thd, - const String *db_name, - const String *view_name) -{ - return ViewBaseObjectsIterator::create( - thd, db_name, view_name, ViewBaseObjectsIterator::GET_BASE_VIEWS); -} +template +View_base_view_iterator * +View_base_obj_iterator:: +create(THD *thd, const String *db_name, + const String *view_name); /////////////////////////////////////////////////////////////////////////// - -// -// Implementation: DatabaseObj class. -// - /////////////////////////////////////////////////////////////////////////// -DatabaseObj::DatabaseObj(const String *db_name) -{ - m_db_name.copy(*db_name); // copy name string to newly allocated memory -} - /** 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. + @param[in] thd Thread context. + @param[out] out_stream Output stream. @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. + 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 + @retval FALSE on success. + @retval TRUE on error. */ -bool DatabaseObj::do_serialize(THD *thd, String *serialization) + +bool Database_obj::do_serialize(THD *thd, Out_stream &out_stream) { - HA_CREATE_INFO create; - DBUG_ENTER("DatabaseObj::serialize()"); - DBUG_PRINT("DatabaseObj::serialize", ("name: %s", m_db_name.c_ptr())); + DBUG_ENTER("Database_obj::do_serialize"); + DBUG_PRINT("Database_obj::do_serialize", + ("name: %.*s", STR(*get_name()))); - if (is_internal_db_name(&m_db_name)) + if (is_internal_db_name(get_name())) { - DBUG_PRINT("backup",(" Skipping internal database %s", m_db_name.c_ptr())); - DBUG_RETURN(TRUE); - } - create.default_table_charset= system_charset_info; + DBUG_PRINT("backup", + (" Skipping internal database %.*s", STR(*get_name()))); - if (check_db_dir_existence(m_db_name.c_ptr())) - { - my_error(ER_BAD_DB_ERROR, MYF(0), m_db_name.c_ptr()); DBUG_RETURN(TRUE); } - load_db_opt_by_name(thd, m_db_name.c_ptr(), &create); + /* Run 'SHOW CREATE' query. */ - serialization->append(STRING_WITH_LEN("CREATE DATABASE ")); - append_identifier(thd, serialization, m_db_name.c_ptr(), m_db_name.length()); + Ed_result ed_result; - if (create.default_table_charset) { - serialization->append(STRING_WITH_LEN(" DEFAULT CHARACTER SET ")); - serialization->append(create.default_table_charset->csname); - if (!(create.default_table_charset->state & MY_CS_PRIMARY)) + String_stream s_stream; + s_stream << + "SHOW CREATE DATABASE `" << get_name() << "`"; + + if (run_service_interface_sql(thd, s_stream.lex_string(), &ed_result) || + ed_result.get_warnings().elements > 0) { - serialization->append(STRING_WITH_LEN(" COLLATE ")); - serialization->append(create.default_table_charset->name); + /* + There should be no warnings. A warning means that serialization has + failed. + */ + DBUG_RETURN(TRUE); } } - DBUG_RETURN(FALSE); -} - -/** - Materialize the serialization string. - This method saves serialization string into a member variable. + /* Check result. */ - @param[in] serialization_version version number of this interface - @param[in] serialization the string from serialize() + /* The result must contain only one result-set... */ + DBUG_ASSERT(ed_result.elements == 1); - @todo take serialization_version into account + Ed_result_set *ed_result_set= ed_result.get_cur_result_set(); - @returns Error status. - @retval FALSE on success - @retval TRUE on error - */ -bool DatabaseObj::materialize(uint serialization_version, - const String *serialization) -{ - DBUG_ENTER("DatabaseObj::materialize()"); - m_create_stmt.copy(*serialization); - DBUG_RETURN(FALSE); -} + /* ... which is not NULL. */ + DBUG_ASSERT(ed_result_set); -/** - Create the object. + if (ed_result_set->data()->elements == 0) + DBUG_RETURN(TRUE); - This method uses serialization string in a query and executes it. + /* There must be one row. */ + DBUG_ASSERT(ed_result_set->data()->elements == 1); - @param[in] thd Thread context. + List_iterator_fast row_it(*ed_result_set->data()); + Ed_row *row= row_it++; - @returns Error status. - @retval FALSE on success - @retval TRUE on error -*/ -bool DatabaseObj::do_execute(THD *thd) -{ - DBUG_ENTER("DatabaseObj::execute()"); - drop(thd); - DBUG_RETURN(silent_exec(thd, &m_create_stmt)); -} + /* There must be two columns: database name and create statement. */ + DBUG_ASSERT(row->get_metadata()->get_num_columns() == 2); -/** - Drop the object. - - This method calls the silent_exec method to execute the query. - - @note This uses "IF EXISTS" and does not return error if - object does not exist. + /* Generate image. */ - @param[in] thd Thread context. - @param[out] serialization the data needed to recreate this object + out_stream << row->get_column(1); - @returns Error status. - @retval FALSE on success - @retval TRUE on error -*/ -bool DatabaseObj::drop(THD *thd) -{ - DBUG_ENTER("DatabaseObj::drop()"); - DBUG_RETURN(drop_object(thd, - (char *) "DATABASE", - 0, - &m_db_name)); + DBUG_RETURN(FALSE); } /////////////////////////////////////////////////////////////////////////// -// -// Implementation: TableObj class. -// - -/////////////////////////////////////////////////////////////////////////// - -TableObj::TableObj(const String *db_name, - const String *table_name, - bool table_is_view) : - m_table_is_view(table_is_view) +void Database_obj::build_drop_statement(String_stream &s_stream) const { - m_db_name.copy(*db_name); - m_table_name.copy(*table_name); + s_stream << + "DROP DATABASE IF EXISTS `" << get_name() << "`"; } -bool TableObj::serialize_table(THD *thd, String *serialization) -{ - return 0; -} - -bool TableObj::serialize_view(THD *thd, String *serialization) -{ - return 0; -} +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// /** Serialize the object. @@ -2083,1225 +1743,883 @@ bool TableObj::serialize_view(THD *thd, 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. + @param[in] thd Thread context. + @param[out] out_stream Output stream. @returns Error status. - @retval FALSE on success - @retval TRUE on error + @retval FALSE on success. + @retval TRUE on error. */ -bool TableObj::do_serialize(THD *thd, String *serialization) -{ - bool ret= 0; - LEX_STRING tname, dbname; - DBUG_ENTER("TableObj::serialize()"); - DBUG_PRINT("TableObj::serialize", ("name: %s@%s", m_db_name.c_ptr(), - m_table_name.c_ptr())); - - prepend_db(thd, serialization, &m_db_name); - tname.str= m_table_name.c_ptr(); - tname.length= m_table_name.length(); - dbname.str= m_db_name.c_ptr(); - dbname.length= m_db_name.length(); - Table_ident *name_id= new Table_ident(tname); - name_id->db= dbname; - /* - Add the view to the table list and set the thd to look at views only. - Note: derived from sql_yacc.yy. - */ - thd->lex->select_lex.add_table_to_list(thd, name_id, NULL, 0); - TABLE_LIST *table_list= (TABLE_LIST*)thd->lex->select_lex.table_list.first; - thd->lex->sql_command = SQLCOM_SHOW_CREATE; +bool Table_obj::do_serialize(THD *thd, Out_stream &out_stream) +{ + DBUG_ENTER("Table_obj::do_serialize"); + DBUG_PRINT("Table_obj::do_serialize", + ("name: %.*s.%.*s", + STR(m_db_name), STR(m_id))); - /* - Setup view specific variables and settings - */ - if (m_table_is_view) - { - thd->lex->only_view= 1; - thd->lex->view_prepare_mode= TRUE; // use prepare mode - table_list->skip_temporary= 1; // skip temporary tables - } + Ed_result ed_result; + String_stream s_stream; - /* - Open the view and its base tables or views - */ - if (open_normal_and_derived_tables(thd, table_list, 0)) { - close_thread_tables(thd); - thd->lex->select_lex.table_list.empty(); - DBUG_RETURN(TRUE); - } + s_stream << + "SHOW CREATE TABLE `" << &m_db_name << "`.`" << &m_id << "`"; - /* - Setup view specific variables and settings - */ - if (m_table_is_view) + if (run_service_interface_sql(thd, s_stream.lex_string(), &ed_result) || + ed_result.get_warnings().elements > 0) { - View_creation_ctx *creation_ctx= table_list->view_creation_ctx; - - /* - append character set client charset information - */ - serialization->append("SET CHARACTER_SET_CLIENT = '"); - serialization->append(creation_ctx->get_client_cs()->csname); - serialization->append("'; "); - /* - append collation_connection information + There should be no warnings. A warning means that serialization has + failed. */ - serialization->append("SET COLLATION_CONNECTION = '"); - serialization->append(creation_ctx->get_connection_cl()->name); - serialization->append("'; "); - - table_list->view_db= dbname; - serialization->set_charset(creation_ctx->get_client_cs()); + DBUG_RETURN(TRUE); } - /* - Get the create statement and close up shop. - */ - ret= m_table_is_view ? - view_store_create_info(thd, table_list, serialization) : - store_create_info(thd, table_list, serialization, NULL, - /* show_database */ TRUE); - close_thread_tables(thd); - serialization->set_charset(system_charset_info); - thd->lex->select_lex.table_list.empty(); - DBUG_RETURN(FALSE); -} - -/** - Materialize the serialization string. + /* Check result. */ - This method saves serialization string into a member variable. + /* The result must contain only one result-set... */ + DBUG_ASSERT(ed_result.elements == 1); - @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 TableObj::materialize(uint serialization_version, - const String *serialization) -{ - DBUG_ENTER("TableObj::materialize()"); - m_create_stmt.copy(*serialization); - DBUG_RETURN(FALSE); -} + Ed_result_set *ed_result_set= ed_result.get_cur_result_set(); -/** - Create the object represented by TableObj in the database. + /* ... which is not NULL. */ + DBUG_ASSERT(ed_result_set); - This method uses serialization string in a query and executes it. + if (ed_result_set->data()->elements == 0) + DBUG_RETURN(TRUE); - @param[in] thd Thread context. + /* There must be one row. */ + DBUG_ASSERT(ed_result_set->data()->elements == 1); - @returns Error status. - @retval FALSE on success - @retval TRUE on error -*/ -bool TableObj::do_execute(THD *thd) -{ - DBUG_ENTER("TableObj::execute()"); - drop(thd); - DBUG_RETURN(silent_exec(thd, &m_create_stmt)); -} + List_iterator_fast row_it(*ed_result_set->data()); + Ed_row *row= row_it++; -/** - Drop the object. + /* There must be two columns: database name and create statement. */ + DBUG_ASSERT(row->get_metadata()->get_num_columns() == 2); - This method calls the silent_exec method to execute the query. + /* Generate serialization image. */ - @note This uses "IF EXISTS" and does not return error if - object does not exist. + { + s_stream.reset(); + s_stream << "USE `" << &m_db_name << "`"; + out_stream << s_stream; + } - @param[in] thd Thread context. - @param[out] serialization The data needed to recreate this object. + out_stream << row->get_column(1); - @returns Error status. - @retval FALSE on success - @retval TRUE on error -*/ -bool TableObj::drop(THD *thd) -{ - DBUG_ENTER("TableObj::drop()"); - DBUG_RETURN(drop_object(thd, - (char *) "TABLE", - &m_db_name, - &m_table_name)); + DBUG_RETURN(FALSE); } /////////////////////////////////////////////////////////////////////////// - -// -// Implementation: TriggerObj class. -// /////////////////////////////////////////////////////////////////////////// -TriggerObj::TriggerObj(const String *db_name, - const String *trigger_name) -{ - // copy strings to newly allocated memory - m_db_name.copy(*db_name); - m_trigger_name.copy(*trigger_name); -} +static bool +get_view_create_stmt(THD *thd, + View_obj *view, + LEX_STRING *create_stmt, + LEX_STRING *client_cs_name, + LEX_STRING *connection_cl_name) +{ + /* Get a create statement for a view. */ + Ed_result ed_result; + String_stream s_stream; + + s_stream << + "SHOW CREATE VIEW `" << view->get_db_name() << "`." + "`" << view->get_name() << "`"; -/** - Serialize the object. + if (run_service_interface_sql(thd, s_stream.lex_string(), &ed_result) || + ed_result.get_warnings().elements > 0) + { + /* + There should be no warnings. A warning means that serialization has + failed. + */ + return TRUE; + } - This method produces the data necessary for materializing the object - on restore (creates object). + /* The result must contain only one result-set... */ + DBUG_ASSERT(ed_result.elements == 1); - @param[in] thd Thread handler. - @param[out] serialization The data needed to recreate this object. + Ed_result_set *ed_result_set= ed_result.get_cur_result_set(); - @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. + /* ... which is not NULL. */ + DBUG_ASSERT(ed_result_set); - @returns Error status. - @retval FALSE on success - @retval TRUE on error -*/ -bool TriggerObj::do_serialize(THD *thd, String *serialization) -{ - bool ret= false; - uint num_tables; - sp_name *trig_name; - LEX_STRING trg_name; - ulonglong trg_sql_mode; - LEX_STRING trg_sql_mode_str; - LEX_STRING trg_sql_original_stmt; - LEX_STRING trg_client_cs_name; - LEX_STRING trg_connection_cl_name; - LEX_STRING trg_db_cl_name; - CHARSET_INFO *trg_client_cs; - DBUG_ENTER("TriggerObj::serialize()"); - - DBUG_PRINT("TriggerObj::serialize", ("name: %s in %s", - m_trigger_name.c_ptr(), m_db_name.c_ptr())); - - prepend_db(thd, serialization, &m_db_name); - LEX_STRING db; - db.str= m_db_name.c_ptr(); - db.length= m_db_name.length(); - LEX_STRING t_name; - t_name.str= m_trigger_name.c_ptr(); - t_name.length= m_trigger_name.length(); - trig_name= new sp_name(db, t_name, true); - trig_name->init_qname(thd); - TABLE_LIST *lst= get_trigger_table(thd, trig_name); - if (!lst) - DBUG_RETURN(FALSE); + if (ed_result_set->data()->elements == 0) + return TRUE; - alloc_mdl_locks(lst, thd->mem_root); + /* There must be one row. */ + DBUG_ASSERT(ed_result_set->data()->elements == 1); - DBUG_EXECUTE_IF("backup_fail_add_trigger", DBUG_RETURN(TRUE);); - if (open_tables(thd, &lst, &num_tables, 0)) - DBUG_RETURN(TRUE); + List_iterator_fast row_it(*ed_result_set->data()); + Ed_row *row= row_it++; - DBUG_ASSERT(num_tables == 1); - Table_triggers_list *triggers= lst->table->triggers; - if (!triggers) - DBUG_RETURN(FALSE); + /* There must be four columns. */ + DBUG_ASSERT(row->get_metadata()->get_num_columns() == 4); - int trigger_idx= triggers->find_trigger_by_name(&trig_name->m_name); - if (trigger_idx < 0) - DBUG_RETURN(FALSE); + const LEX_STRING *c1= row->get_column(1); + const LEX_STRING *c2= row->get_column(2); + const LEX_STRING *c3= row->get_column(3); - triggers->get_trigger_info(thd, - trigger_idx, - &trg_name, - &trg_sql_mode, - &trg_sql_original_stmt, - &trg_client_cs_name, - &trg_connection_cl_name, - &trg_db_cl_name); - sys_var_thd_sql_mode::symbolic_mode_representation(thd, - trg_sql_mode, - &trg_sql_mode_str); + create_stmt->str= thd->strmake(c1->str, c1->length); + create_stmt->length= c1->length; - /* - prepend SQL Mode - */ - serialization->append("SET SQL_MODE = '"); - serialization->append(trg_sql_mode_str.str); - serialization->append("'; "); + client_cs_name->str= thd->strmake(c2->str, c2->length); + client_cs_name->length= c2->length; - /* - append character set client charset information - */ - serialization->append("SET CHARACTER_SET_CLIENT = '"); - serialization->append(trg_client_cs_name.str); - serialization->append("'; "); + connection_cl_name->str= thd->strmake(c3->str, c3->length); + connection_cl_name->length= c3->length; - /* - append collation_connection information - */ - serialization->append("SET COLLATION_CONNECTION = '"); - serialization->append(trg_connection_cl_name.str); - serialization->append("'; "); - - /* - append collation_connection information - */ - serialization->append("SET COLLATION_DATABASE = '"); - serialization->append(trg_db_cl_name.str); - serialization->append("'; "); - - if (resolve_charset(trg_client_cs_name.str, NULL, &trg_client_cs)) - ret= false; - else - serialization->append(trg_sql_original_stmt.str); - close_thread_tables(thd); - thd->lex->select_lex.table_list.empty(); - serialization->set_charset(system_charset_info); - DBUG_RETURN(ret); + return FALSE; } -/** - Materialize the serialization string. +/////////////////////////////////////////////////////////////////////////// - This method saves serialization string into a member variable. +/** + Serialize the object. - @param[in] serialization_version version number of this interface - @param[in] serialization the string from serialize() + This method produces the data necessary for materializing the object + on restore (creates object). - @todo take serialization_version into account + @param[in] thd Thread context. + @param[out] out_stream Output stream. @returns Error status. - @retval FALSE on success - @retval TRUE on error + @retval FALSE on success. + @retval TRUE on error. */ -bool TriggerObj::materialize(uint serialization_version, - const String *serialization) +bool View_obj::do_serialize(THD *thd, Out_stream &out_stream) { - DBUG_ENTER("TriggerObj::materialize()"); - m_create_stmt.copy(*serialization); - DBUG_RETURN(0); -} - -/** - Create the object. + DBUG_ENTER("View_obj::do_serialize"); + DBUG_PRINT("View_obj::do_serialize", + ("name: %.*s.%.*s", + STR(m_db_name), STR(m_id))); - This method uses serialization string in a query and executes it. + String_stream s_stream; - @param[in] thd Thread context. - - @returns Error status. - @retval FALSE on success - @retval TRUE on error -*/ -bool TriggerObj::do_execute(THD *thd) -{ - DBUG_ENTER("TriggerObj::execute()"); - drop(thd); - DBUG_RETURN(execute_with_ctx(thd, &m_create_stmt, false)); -} + LEX_STRING create_stmt= null_lex_str; + LEX_STRING client_cs_name= null_lex_str; + LEX_STRING connection_cl_name= null_lex_str; -/** - Drop the object. + if (get_view_create_stmt(thd, this, &create_stmt, + &client_cs_name, &connection_cl_name)) + { + DBUG_RETURN(TRUE); + } - This method calls the silent_exec method to execute the query. + s_stream << "USE `" << &m_db_name << "`"; + out_stream << s_stream; - @note This uses "IF EXISTS" and does not return error if - object does not exist. + s_stream.reset(); + s_stream << "SET character_set_client = " << &client_cs_name; + out_stream << s_stream; + + s_stream.reset(); + s_stream << "SET collation_connection = " << &connection_cl_name; + out_stream << s_stream; - @param[in] thd Thread context. - @param[out] serialization The data needed to recreate this object. + out_stream << &create_stmt; - @returns Error status. - @retval FALSE on success - @retval TRUE on error -*/ -bool TriggerObj::drop(THD *thd) -{ - DBUG_ENTER("TriggerObj::drop()"); - DBUG_RETURN(drop_object(thd, - (char *) "TRIGGER", - &m_db_name, - &m_trigger_name)); + DBUG_RETURN(FALSE); } /////////////////////////////////////////////////////////////////////////// - -// -// Implementation: StoredProcObj class. -// - /////////////////////////////////////////////////////////////////////////// -StoredProcObj::StoredProcObj(const String *db_name, - const String *stored_proc_name) +bool Stored_program_obj::do_serialize(THD *thd, Out_stream &out_stream) { - // copy strings to newly allocated memory - m_db_name.copy(*db_name); - m_stored_proc_name.copy(*stored_proc_name); -} - -/** - Serialize the object. + DBUG_ENTER("Stored_program_obj::do_serialize"); + DBUG_PRINT("Stored_program_obj::do_serialize", + ("name: %.*s.%.*s", + STR(m_db_name), STR(m_id))); - This method produces the data necessary for materializing the object - on restore (creates object). + DBUG_EXECUTE_IF("backup_fail_add_trigger", DBUG_RETURN(TRUE);); - @param[in] thd Thread context. - @param[out] serialization The data needed to recreate this object. + String_stream s_stream; + Ed_result ed_result; - @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. + s_stream << + "SHOW CREATE " << get_type_name() << + " `" << &m_db_name << "`.`" << &m_id << "`"; - @returns Error status. -*/ -bool StoredProcObj::do_serialize(THD *thd, String *serialization) -{ - bool ret= false; - DBUG_ENTER("StoredProcObj::serialize()"); - DBUG_PRINT("StoredProcObj::serialize", ("name: %s in %s", - m_stored_proc_name.c_ptr(), m_db_name.c_ptr())); - prepend_db(thd, serialization, &m_db_name); - ret= serialize_routine(thd, TYPE_ENUM_PROCEDURE, m_db_name, - m_stored_proc_name, serialization); - serialization->set_charset(system_charset_info); - DBUG_RETURN(ret); -} + if (run_service_interface_sql(thd, s_stream.lex_string(), &ed_result) || + ed_result.get_warnings().elements > 0) + { + /* + There should be no warnings. A warning means that serialization has + failed. + */ + DBUG_RETURN(TRUE); + } -/** - Materialize the serialization string. + /* The result must contain only one result-set... */ + DBUG_ASSERT(ed_result.elements == 1); - This method saves serialization string into a member variable. + Ed_result_set *ed_result_set= ed_result.get_cur_result_set(); - @param[in] serialization_version version number of this interface - @param[in] serialization the string from serialize() + /* ... which is not NULL. */ + DBUG_ASSERT(ed_result_set); - @todo take serialization_version into account + if (ed_result_set->data()->elements == 0) + DBUG_RETURN(TRUE); - @returns Error status. - @retval FALSE on success - @retval TRUE on error -*/ -bool StoredProcObj::materialize(uint serialization_version, - const String *serialization) -{ - DBUG_ENTER("StoredProcObj::materialize()"); - m_create_stmt.copy(*serialization); - DBUG_RETURN(0); -} + /* There must be one row. */ + DBUG_ASSERT(ed_result_set->data()->elements == 1); -/** - Create the object. + List_iterator_fast row_it(*ed_result_set->data()); + Ed_row *row= row_it++; - This method uses serialization string in a query and executes it. + s_stream.reset(); + s_stream << "USE `" << &m_db_name << "`"; + out_stream << s_stream; - @param[in] thd current thread + dump_header(row, out_stream); + out_stream << get_create_stmt(row); - @returns Error status. - @retval FALSE on success - @retval TRUE on error -*/ -bool StoredProcObj::do_execute(THD *thd) -{ - DBUG_ENTER("StoredProcObj::execute()"); - drop(thd); - DBUG_RETURN(execute_with_ctx(thd, &m_create_stmt, false)); + DBUG_RETURN(FALSE); } -/** - Drop the object. - - This method calls the silent_exec method to execute the query. - - @note This uses "IF EXISTS" and does not return error if - object does not exist. - - @param[in] thd current thread - @param[out] serialization the data needed to recreate this object +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// - @returns Error status. - @retval FALSE on success - @retval TRUE on error -*/ -bool StoredProcObj::drop(THD *thd) +const LEX_STRING *Stored_routine_obj::get_create_stmt(Ed_row *row) { - DBUG_ENTER("StoredProcObj::drop()"); - DBUG_RETURN(drop_object(thd, - (char *) "PROCEDURE", - &m_db_name, - &m_stored_proc_name)); + return row->get_column(2); } /////////////////////////////////////////////////////////////////////////// -// -// Implementation: StoredFuncObj class. -// - -/////////////////////////////////////////////////////////////////////////// - -StoredFuncObj::StoredFuncObj(const String *db_name, - const String *stored_func_name) +void Stored_routine_obj::dump_header(Ed_row *row, Out_stream &out_stream) { - // copy strings to newly allocated memory - m_db_name.copy(*db_name); - m_stored_func_name.copy(*stored_func_name); -} + String_stream s_stream; -/** - Serialize the object. - - This method produces the data necessary for materializing the object - on restore (creates object). + s_stream << + "SET character_set_client = " << row->get_column(3); + out_stream << s_stream; - @param[in] thd Thread context. - @param[out] serialization The data needed to recreate this object. + s_stream.reset(); + s_stream << + "SET collation_connection = " << row->get_column(4); + out_stream << s_stream; - @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. + s_stream.reset(); + s_stream << + "SET collation_database = " << row->get_column(5); + out_stream << s_stream; - @returns Error status. - @retval FALSE on success - @retval TRUE on error - */ -bool StoredFuncObj::do_serialize(THD *thd, String *serialization) -{ - bool ret= false; - DBUG_ENTER("StoredFuncObj::serialize()"); - DBUG_PRINT("StoredProcObj::serialize", ("name: %s in %s", - m_stored_func_name.c_ptr(), m_db_name.c_ptr())); - prepend_db(thd, serialization, &m_db_name); - ret= serialize_routine(thd, TYPE_ENUM_FUNCTION, m_db_name, - m_stored_func_name, serialization); - serialization->set_charset(system_charset_info); - DBUG_RETURN(ret); + s_stream.reset(); + s_stream << + "SET sql_mode = '" << row->get_column(1) << "'"; + out_stream << s_stream; } -/** - 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 +#ifdef HAVE_EVENT_SCHEDULER - @returns Error status. - @retval FALSE on success - @retval TRUE on error -*/ -bool StoredFuncObj::materialize(uint serialization_version, - const String *serialization) +void Event_obj::dump_header(Ed_row *row, Out_stream &out_stream) { - DBUG_ENTER("StoredFuncObj::materialize()"); - m_create_stmt.copy(*serialization); - DBUG_RETURN(0); -} + String_stream s_stream; -/** - Create the object. + s_stream << + "SET character_set_client = " << row->get_column(4); + out_stream << s_stream; + + s_stream.reset(); + s_stream << + "SET collation_connection = " << row->get_column(5); + out_stream << s_stream; + + s_stream.reset(); + s_stream << + "SET collation_database = " << row->get_column(6); + out_stream << s_stream; + + s_stream.reset(); + s_stream << + "SET sql_mode = '" << row->get_column(1) << "'"; + out_stream << s_stream; + + s_stream.reset(); + s_stream << + "SET time_zone = '" << row->get_column(2) << "'"; + out_stream << s_stream; +} - This method uses serialization string in a query and executes it. +#endif // HAVE_EVENT_SCHEDULER - @param[in] thd Thread context. +/////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// - @returns Error status. - @retval FALSE on success - @retval TRUE on error -*/ -bool StoredFuncObj::do_execute(THD *thd) +Tablespace_obj:: +Tablespace_obj(LEX_STRING ts_name, + LEX_STRING comment, + LEX_STRING data_file_name, + LEX_STRING engine) + : Abstract_obj(ts_name) { - DBUG_ENTER("StoredFuncObj::execute()"); - drop(thd); - DBUG_RETURN(execute_with_ctx(thd, &m_create_stmt, false)); -} + m_comment.copy(comment.str, comment.length, system_charset_info); + m_data_file_name.copy(data_file_name.str, data_file_name.length, + system_charset_info); + m_engine.copy(engine.str, engine.length, system_charset_info); -/** - Drop the object. - - This method calls the silent_exec method to execute the query. - - @note This uses "IF EXISTS" and does not return error if - object does not exist. + m_description.length(0); +} - @param[in] thd Thread context. - @param[out] serialization The data needed to recreate this object. - @returns Error status. - @retval FALSE on success - @retval TRUE on error -*/ -bool StoredFuncObj::drop(THD *thd) +Tablespace_obj::Tablespace_obj(LEX_STRING ts_name) + : Abstract_obj(ts_name) { - DBUG_ENTER("StoredFuncObj::drop()"); - DBUG_RETURN(drop_object(thd, - (char *) "FUNCTION", - &m_db_name, - &m_stored_func_name)); + m_comment.length(0); + m_data_file_name.length(0); + m_engine.length(0); + + m_description.length(0); } /////////////////////////////////////////////////////////////////////////// -// -// Implementation: EventObj class. -// - -///////////////////////////////////////////////////////////////////////////// -#ifdef HAVE_EVENT_SCHEDULER -EventObj::EventObj(const String *db_name, - const String *event_name) -{ - // copy strings to newly allocated memory - m_db_name.copy(*db_name); - m_event_name.copy(*event_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. + @param[in] thd Thread context. + @param[out] out_stream Output stream. @returns Error status. - @retval FALSE on success - @retval TRUE on error + @retval FALSE on success. + @retval TRUE on error. */ -bool EventObj::do_serialize(THD *thd, String *serialization) -{ - bool ret= false; - Open_tables_state open_tables_backup; - Event_timed et; - LEX_STRING sql_mode; - DBUG_ENTER("EventObj::serialize()"); - DBUG_PRINT("EventObj::serialize", ("name: %s.%s", m_db_name.c_ptr(), - m_event_name.c_ptr())); - - prepend_db(thd, serialization, &m_db_name); - Event_db_repository *db_repository= Events::get_db_repository(); - thd->reset_n_backup_open_tables_state(&open_tables_backup); - LEX_STRING db; - db.str= m_db_name.c_ptr(); - db.length= m_db_name.length(); - LEX_STRING ev; - ev.str= m_event_name.c_ptr(); - ev.length= m_event_name.length(); - ret= db_repository->load_named_event(thd, db, ev, &et); - thd->restore_backup_open_tables_state(&open_tables_backup); - if (sys_var_thd_sql_mode::symbolic_mode_representation(thd, - et.sql_mode, &sql_mode)) - DBUG_RETURN(TRUE); - if (!ret) - { - /* - Prepend sql_mode command. - */ - serialization->append("SET SQL_MODE = '"); - serialization->append(sql_mode.str); - serialization->append("'; "); - - /* - append time zone information - */ - serialization->append("SET TIME_ZONE = '"); - const String *tz= et.time_zone->get_name(); - serialization->append(tz->ptr()); - serialization->append("'; "); - - /* - append character set client charset information - */ - serialization->append("SET CHARACTER_SET_CLIENT = '"); - serialization->append(et.creation_ctx->get_client_cs()->csname); - serialization->append("'; "); - /* - append collation_connection information - */ - serialization->append("SET COLLATION_CONNECTION = '"); - serialization->append(et.creation_ctx->get_connection_cl()->name); - serialization->append("'; "); +bool Tablespace_obj::do_serialize(THD *thd, Out_stream &out_stream) +{ + DBUG_ENTER("Tablespace_obj::do_serialize"); - /* - append collation_connection information - */ - serialization->append("SET COLLATION_DATABASE = '"); - serialization->append(et.creation_ctx->get_db_cl()->name); - serialization->append("'; "); + out_stream << get_description(); - if (et.get_create_event(thd, serialization)) - DBUG_RETURN(0); - } - serialization->set_charset(system_charset_info); - DBUG_RETURN(0); + DBUG_RETURN(FALSE); } -/** - Materialize the serialization string. +/////////////////////////////////////////////////////////////////////////// - This method saves serialization string into a member variable. +bool Tablespace_obj::init_from_image(uint image_version, const String *image) +{ + if (Abstract_obj::init_from_image(image_version, image)) + return TRUE; - @param[in] serialization_version version number of this interface - @param[in] serialization the string from serialize() + List_iterator_fast it(m_stmt_list); + LEX_STRING *desc= it++; - @todo take serialization_version into account + /* Tablespace description must not be NULL. */ + DBUG_ASSERT(desc); - @returns Error status. - @retval FALSE on success - @retval TRUE on error -*/ -bool EventObj::materialize(uint serialization_version, - const String *serialization) -{ - DBUG_ENTER("EventObj::materialize()"); - m_create_stmt.copy(*serialization); - DBUG_RETURN(0); + m_description.copy(desc->str, desc->length, system_charset_info); + + return FALSE; } -/** - Create the object. +/////////////////////////////////////////////////////////////////////////// - This method uses serialization string in a query and executes it. +/** + Get a description of the tablespace object. - @param[in] thd Thread context. + This method returns the description of the object which is currently + the serialization image. - @returns Error status. - @retval FALSE on success - @retval TRUE on error + @returns Serialization string. */ -bool EventObj::do_execute(THD *thd) + +const String *Tablespace_obj::get_description() { - DBUG_ENTER("EventObj::execute()"); - drop(thd); - DBUG_RETURN(execute_with_ctx(thd, &m_create_stmt, true)); -} + DBUG_ENTER("Tablespace_obj::get_description"); -/** - Drop the object. + /* Either description or id and data file name must be not empty. */ + DBUG_ASSERT(m_description.length() || + m_id.length() && m_data_file_name.length()); - This method calls the silent_exec method to execute the query. + if (m_description.length()) + DBUG_RETURN(&m_description); - @note This uses "IF EXISTS" and does not return error if - object does not exist. + /* Construct the CREATE TABLESPACE command from the variables. */ - @param[in] thd Thread context. - @param[out] serialization the data needed to recreate this object + m_description.length(0); - @returns Error status. - @retval FALSE on success - @retval TRUE on error -*/ -bool EventObj::drop(THD *thd) -{ - DBUG_ENTER("EventObj::drop()"); - DBUG_RETURN(drop_object(thd, - (char *) "EVENT", - &m_db_name, - &m_event_name)); -} -#endif // HAVE_EVENT_SCHEDULER + String_stream s_stream(&m_description); -/////////////////////////////////////////////////////////////////////////// + s_stream << + "CREATE TABLESPACE `" << &m_id << "` " + "ADD DATAFILE '" << &m_data_file_name << "' "; -// -// Implementation: TablespaceObj class. -// + if (m_comment.length()) + s_stream << "COMMENT = '" << &m_comment << "' "; -///////////////////////////////////////////////////////////////////////////// + s_stream << "ENGINE = " << &m_engine; -TablespaceObj::TablespaceObj(const String *ts_name) -{ - // copy strings to newly allocated memory - m_ts_name.copy(*ts_name); - m_datafile.length(0); - m_comments.length(0); - m_engine.length(0); + DBUG_RETURN(&m_description); } -/** - Serialize the object. +/////////////////////////////////////////////////////////////////////////// - This method produces the data necessary for materializing the object - on restore (creates object). +void Tablespace_obj::build_drop_statement(String_stream &s_stream) const +{ + s_stream << + "DROP TABLESPACE `" << &m_id << "` ENGINE = " << &m_engine; +} - @param[in] thd Thread context. - @param[out] serialization The data needed to recreate this object. +/////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// - @returns Error status. - @retval FALSE on success - @retval TRUE on error -*/ -bool TablespaceObj::do_serialize(THD *thd, String *serialization) +void +Grant_obj:: +generate_unique_grant_id(const String *user_name, String *id) { - DBUG_ENTER("TablespaceObj::serialize()"); - build_serialization(); - serialization->copy(m_create_stmt); - DBUG_RETURN(FALSE); -} + /* + @note This code is not MT-safe, but we don't need MT-safety here. + Backup has object cache (a hash) for one BACKUP/RESTORE statement. + Hash keys are formed from object names (Obj::get_db_name() and + Obj::get_name()). So, here unique keys for the object cache are + generated. These keys need to be unique only within one backup session + (serialization image). + */ -/** - Materialize the serialization string. + static unsigned long id_counter= 0; - This method saves serialization string into a member variable. - Also extracts tablespace engine name from serialization string. + id->length(0); - @param[in] serialization_version version number of this interface - @param[in] serialization the string from serialize() + String_stream s_stream(id); - @todo take serialization_version into account + if (user_name->length()) + s_stream << ""; + else + s_stream << user_name; - @returns Error status. - @retval FALSE on success - @retval TRUE on error -*/ -bool TablespaceObj::materialize(uint serialization_version, - const String *serialization) -{ - DBUG_ENTER("TablespaceObj::materialize()"); - m_create_stmt.copy(*serialization); - /* Extract engine from create statement */ - String tmp_str= String("=", 1, system_charset_info); - int pos= m_create_stmt.strrstr(tmp_str, m_create_stmt.length()); - m_engine.copy(m_create_stmt.ptr() + pos + 1, m_create_stmt.length() - pos - 1, - system_charset_info); - DBUG_RETURN(FALSE); + s_stream << " " << Int_value(++id_counter); } -/** - Get a description of the tablespace object. - - This method returns the description of the object which is currently - the serialization string. +///////////////////////////////////////////////////////////////////////////// - @returns Serialization string. -*/ -const String *TablespaceObj::describe() +Grant_obj::Grant_obj(const Ed_row &row) + : Abstract_obj(null_lex_str) { - DBUG_ENTER("TablespaceObj::describe()"); - DBUG_RETURN(build_serialization()); -} + const LEX_STRING *user_name= row.get_column(0); + const LEX_STRING *privilege_type= row.get_column(1); + const LEX_STRING *db_name= row.get_column(2); + const LEX_STRING *tbl_name= row.get_column(3); + const LEX_STRING *col_name= row.get_column(4); -/** - Build the serialization string. + LEX_STRING table_name= { C_STRING_WITH_LEN("") }; + LEX_STRING column_name= { C_STRING_WITH_LEN("") }; - This constructs the serialization string for identification - use in describing tablespace to the user and for creating the - tablespace. + if (tbl_name) + table_name= *tbl_name; - @todo take serialization_version into account + if (col_name) + column_name= *col_name; - @returns Serialization string. -*/ -const String *TablespaceObj::build_serialization() -{ - DBUG_ENTER("TablespaceObj::build_serialization()"); + m_user_name.copy(user_name->str, user_name->length, system_charset_info); - if (m_create_stmt.length()) - DBUG_RETURN(&m_create_stmt); + /* Grant info. */ - /* - Construct the CREATE TABLESPACE command from the variables. - */ - m_create_stmt.length(0); - m_create_stmt.append("CREATE TABLESPACE "); - if (m_ts_name.length() > 0) - { - THD *thd= current_thd; - append_identifier(thd, &m_create_stmt, - m_ts_name.c_ptr(), m_ts_name.length()); - } - m_create_stmt.append(" ADD DATAFILE '"); - m_create_stmt.append(m_datafile); - if (m_comments.length()) - { - m_create_stmt.append("' COMMENT = '"); - m_create_stmt.append(m_comments); - } - m_create_stmt.append("' ENGINE="); - m_create_stmt.append(m_engine); - DBUG_RETURN(&m_create_stmt); -} + String_stream s_stream(&m_grant_info); + s_stream << privilege_type; -/** - Create the object. + if (column_name.length) + s_stream << "(" << &column_name << ")"; - This method uses serialization string in a query and executes it. + s_stream << " ON " << db_name << "."; - @param[in] thd Thread context. + if (table_name.length) + s_stream << &table_name; + else + s_stream << "*"; - @returns Error status. - @retval FALSE on success - @retval TRUE on error -*/ -bool TablespaceObj::do_execute(THD *thd) -{ - DBUG_ENTER("TablespaceObj::execute()"); - build_serialization(); // Build the CREATE command. - DBUG_RETURN(silent_exec(thd, &m_create_stmt)); + /* Id. */ + + generate_unique_grant_id(&m_user_name, &m_id); } -/////////////////////////////////////////////////////////////////////////// -// -// 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); +Grant_obj::Grant_obj(LEX_STRING name) + : Abstract_obj(null_lex_str) +{ + m_user_name.length(0); + m_grant_info.length(0); + + m_id.copy(name.str, name.length, system_charset_info); } +///////////////////////////////////////////////////////////////////////////// + /** 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. + @param[in] thd Thread context. + @param[out] out_stream Output stream. @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. + 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 + @retval FALSE on success. + @retval TRUE on error. */ -bool DbGrantObj::do_serialize(THD *thd, String *serialization) + +bool Grant_obj::do_serialize(THD *thd, Out_stream &out_stream) { - 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); -} + DBUG_ENTER("Grant_obj::do_serialize"); -/** - Materialize the serialization string. + out_stream << + &m_user_name << + &m_grant_info << + "SET character_set_client= binary"; - This method saves serialization string into a member variable. + String_stream s_stream; + s_stream << "GRANT " << &m_grant_info << " TO " << &m_user_name; - @param[in] serialization_version version number of this interface - @param[in] serialization the string from serialize() + out_stream << s_stream; - @todo take serialization_version into account + DBUG_RETURN(FALSE); +} - @returns Error status. - @retval FALSE on success - @retval TRUE on error -*/ -bool DbGrantObj::materialize(uint serialization_version, - const String *serialization) +///////////////////////////////////////////////////////////////////////////// + +bool Grant_obj::do_init_from_image(In_stream *is) { - DBUG_ENTER("DbGrantObj::materialize()"); - m_grant_stmt.copy(*serialization); - DBUG_RETURN(0); -} + LEX_STRING user_name; + LEX_STRING grant_info; -/** - Create the object. + if (is->next(&user_name)) + return TRUE; /* Can not decode user name. */ - This method uses serialization string in a query and executes it. + if (is->next(&grant_info)) + return TRUE; /* Can not decode grant info. */ - @param[in] thd Thread context. + m_user_name.copy(user_name.str, user_name.length, system_charset_info); + m_grant_info.copy(grant_info.str, grant_info.length, system_charset_info); - @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)); + return Abstract_obj::do_init_from_image(is); } /////////////////////////////////////////////////////////////////////////// -// -// 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) +Obj *get_database_stub(const String *db_name) { - // copy strings to newly allocated memory - m_table_name.copy(*table_name); + return new Database_obj(db_name->lex_string()); } -/** - Serialize the object. +/////////////////////////////////////////////////////////////////////////// - This method produces the data necessary for materializing the object - on restore (creates object). +Obj_iterator *get_databases(THD *thd) +{ + LEX_STRING query= + { C_STRING_WITH_LEN( + "SELECT schema_name " + "FROM INFORMATION_SCHEMA.SCHEMATA " + "WHERE LCASE(schema_name) != 'mysql' AND " + "LCASE(schema_name) != 'information_schema'") }; - @param[in] thd Thread context. - @param[out] serialization The data needed to recreate this object. + return create_row_set_iterator(thd, &query); +} - @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) +Obj_iterator *get_db_tables(THD *thd, const String *db_name) { - 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); + String_stream s_stream; + + s_stream << + "SELECT '" << db_name << "', table_name " + "FROM INFORMATION_SCHEMA.TABLES " + "WHERE table_schema = '" << db_name << "' AND " + "table_type = 'BASE TABLE'"; + + return create_row_set_iterator(thd, s_stream.lex_string()); } /////////////////////////////////////////////////////////////////////////// -// -// 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) +Obj_iterator *get_db_views(THD *thd, const String *db_name) { - // copy strings to newly allocated memory - m_col_name.copy(*col_name); + String_stream s_stream; + s_stream << + "SELECT '" << db_name << "', table_name " + "FROM INFORMATION_SCHEMA.TABLES " + "WHERE table_schema = '" << db_name << "' AND table_type = 'VIEW'"; + + return create_row_set_iterator(thd, s_stream.lex_string()); } -/** - Serialize the object. +/////////////////////////////////////////////////////////////////////////// - This method produces the data necessary for materializing the object - on restore (creates object). +Obj_iterator *get_db_triggers(THD *thd, const String *db_name) +{ + String_stream s_stream; + s_stream << + "SELECT '" << db_name << "', trigger_name " + "FROM INFORMATION_SCHEMA.TRIGGERS " + "WHERE trigger_schema = '" << db_name << "'"; - @param[in] thd Thread context. - @param[out] serialization The data needed to recreate this object. + return create_row_set_iterator(thd, s_stream.lex_string()); +} - @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) +Obj_iterator *get_db_stored_procedures(THD *thd, const String *db_name) { - 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); + String_stream s_stream; + s_stream << + "SELECT '" << db_name << "', routine_name " + "FROM INFORMATION_SCHEMA.ROUTINES " + "WHERE routine_schema = '" << db_name << "' AND " + "routine_type = 'PROCEDURE'"; + + return create_row_set_iterator(thd, s_stream.lex_string()); } /////////////////////////////////////////////////////////////////////////// -Obj *get_database(const String *db_name) +Obj_iterator *get_db_stored_functions(THD *thd, const String *db_name) { - return new DatabaseObj(db_name); -} + String_stream s_stream; + s_stream << + "SELECT '" << db_name << "', routine_name " + "FROM INFORMATION_SCHEMA.ROUTINES " + "WHERE routine_schema = '" << db_name <<"' AND " + "routine_type = 'FUNCTION'"; -Obj *get_table(const String *db_name, - const String *table_name) -{ - return new TableObj(db_name, table_name, false); + return create_row_set_iterator(thd, s_stream.lex_string()); } -Obj *get_view(const String *db_name, - const String *view_name) -{ - return new TableObj(db_name, view_name, true); -} +/////////////////////////////////////////////////////////////////////////// -Obj *get_trigger(const String *db_name, - const String *trigger_name) +Obj_iterator *get_db_events(THD *thd, const String *db_name) { - return new TriggerObj(db_name, trigger_name); +#ifdef HAVE_EVENT_SCHEDULER + String_stream s_stream; + s_stream << + "SELECT '" << db_name << "', event_name " + "FROM INFORMATION_SCHEMA.EVENTS " + "WHERE event_schema = '" << db_name <<"'"; + + return create_row_set_iterator(thd, s_stream.lex_string()); +#else + return NULL; +#endif } -Obj *get_stored_procedure(const String *db_name, - const String *sp_name) +/////////////////////////////////////////////////////////////////////////// + +Obj_iterator *get_all_db_grants(THD *thd, const String *db_name) { - return new StoredProcObj(db_name, sp_name); + String_stream s_stream; + s_stream << + "(SELECT grantee AS c1, " + "privilege_type AS c2, " + "table_schema AS c3, " + "NULL AS c4, " + "NULL AS c5 " + "FROM INFORMATION_SCHEMA.SCHEMA_PRIVILEGES " + "WHERE table_schema = '" << db_name << "') " + "UNION " + "(SELECT grantee, " + "privilege_type, " + "table_schema, " + "table_name, " + "NULL " + "FROM INFORMATION_SCHEMA.TABLE_PRIVILEGES " + "WHERE table_schema = '" << db_name << "') " + "UNION " + "(SELECT grantee, " + "privilege_type, " + "table_schema, " + "table_name, " + "column_name " + "FROM INFORMATION_SCHEMA.COLUMN_PRIVILEGES " + "WHERE table_schema = '" << db_name << "') " + "ORDER BY c1 ASC, c2 ASC, c3 ASC, c4 ASC, c5 ASC"; + + return create_row_set_iterator(thd, s_stream.lex_string()); } -Obj *get_stored_function(const String *db_name, - const String *sf_name) +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// + +Obj_iterator* get_view_base_tables(THD *thd, + const String *db_name, + const String *view_name) { - return new StoredFuncObj(db_name, sf_name); + return View_base_table_iterator::create(thd, db_name, view_name); } -Obj *get_event(const String *db_name, - const String *event_name) +/////////////////////////////////////////////////////////////////////////// + +Obj_iterator* get_view_base_views(THD *thd, + const String *db_name, + const String *view_name) { -#ifdef HAVE_EVENT_SCHEDULER - return new EventObj(db_name, event_name); -#else - return NULL; -#endif + return View_base_view_iterator::create(thd, db_name, view_name); } - +/////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// -Obj *materialize_database(const String *db_name, - uint serialization_version, - const String *serialization) +Obj *get_database(const String *db_name, + uint image_version, + const String *image) { - Obj *obj= new DatabaseObj(db_name); - obj->materialize(serialization_version, serialization); + Database_obj *obj= new Database_obj(db_name->lex_string()); + obj->init_from_image(image_version, image); return obj; } -Obj *materialize_table(const String *db_name, - const String *table_name, - uint serialization_version, - const String *serialization) -{ - Obj *obj= new TableObj(db_name, table_name, false); - obj->materialize(serialization_version, serialization); +/////////////////////////////////////////////////////////////////////////// + +Obj *get_table(const String *db_name, + const String *table_name, + uint image_version, + const String *image) +{ + Table_obj *obj= new Table_obj(db_name->lex_string(), + table_name->lex_string()); + obj->init_from_image(image_version, image); return obj; } -Obj *materialize_view(const String *db_name, - const String *view_name, - uint serialization_version, - const String *serialization) +/////////////////////////////////////////////////////////////////////////// + +Obj *get_view(const String *db_name, + const String *view_name, + uint image_version, + const String *image) { - Obj *obj= new TableObj(db_name, view_name, true); - obj->materialize(serialization_version, serialization); + View_obj *obj= new View_obj(db_name->lex_string(), view_name->lex_string()); + obj->init_from_image(image_version, image); return obj; } -Obj *materialize_trigger(const String *db_name, - const String *trigger_name, - uint serialization_version, - const String *serialization) -{ - Obj *obj= new TriggerObj(db_name, trigger_name); - obj->materialize(serialization_version, serialization); +/////////////////////////////////////////////////////////////////////////// + +Obj *get_trigger(const String *db_name, + const String *trigger_name, + uint image_version, + const String *image) +{ + Trigger_obj *obj= new Trigger_obj(db_name->lex_string(), + trigger_name->lex_string()); + if (obj->init_from_image(image_version, image)) + { + delete obj; + obj= 0; + } return obj; } -Obj *materialize_stored_procedure(const String *db_name, - const String *stored_proc_name, - uint serialization_version, - const String *serialization) -{ - Obj *obj= new StoredProcObj(db_name, stored_proc_name); - obj->materialize(serialization_version, serialization); +/////////////////////////////////////////////////////////////////////////// + +Obj *get_stored_procedure(const String *db_name, + const String *sp_name, + uint image_version, + const String *image) +{ + Stored_proc_obj *obj= new Stored_proc_obj(db_name->lex_string(), + sp_name->lex_string()); + if (obj->init_from_image(image_version, image)) + { + delete obj; + obj= 0; + } return obj; } -Obj *materialize_stored_function(const String *db_name, - const String *stored_func_name, - uint serialization_version, - const String *serialization) -{ - Obj *obj= new StoredFuncObj(db_name, stored_func_name); - obj->materialize(serialization_version, serialization); +/////////////////////////////////////////////////////////////////////////// + +Obj *get_stored_function(const String *db_name, + const String *sf_name, + uint image_version, + const String *image) +{ + Stored_func_obj *obj= new Stored_func_obj(db_name->lex_string(), + sf_name->lex_string()); + if (obj->init_from_image(image_version, image)) + { + delete obj; + obj= 0; + } return obj; } +/////////////////////////////////////////////////////////////////////////// + #ifdef HAVE_EVENT_SCHEDULER -Obj *materialize_event(const String *db_name, - const String *event_name, - uint serialization_version, - const String *serialization) -{ - Obj *obj= new EventObj(db_name, event_name); - obj->materialize(serialization_version, serialization); + +Obj *get_event(const String *db_name, + const String *event_name, + uint image_version, + const String *image) +{ + Event_obj *obj= new Event_obj(db_name->lex_string(), + event_name->lex_string()); + if (obj->init_from_image(image_version, image)) + { + delete obj; + obj= 0; + } return obj; } + #endif -Obj *materialize_tablespace(const String *ts_name, - uint serialization_version, - const String *serialization) +/////////////////////////////////////////////////////////////////////////// + +Obj *get_tablespace(const String *ts_name, + uint image_version, + const String *image) { - Obj *obj= new TablespaceObj(ts_name); - obj->materialize(serialization_version, serialization); + Tablespace_obj *obj= new Tablespace_obj(ts_name->lex_string()); + if (obj->init_from_image(image_version, image)) + { + delete obj; + obj= 0; + } 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) +Obj *get_db_grant(const String *db_name, + const String *name, + uint image_version, + const String *image) { - /* - 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); + Grant_obj *obj= new Grant_obj(name->lex_string()); + if (obj->init_from_image(image_version, image)) + { + delete obj; + obj= 0; + } return obj; } /////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// bool is_internal_db_name(const String *db_name) { @@ -3319,370 +2637,190 @@ bool is_internal_db_name(const String *d /////////////////////////////////////////////////////////////////////////// -bool check_db_existence(const String *db_name) +bool check_db_existence(THD *thd, const String *db_name) { - return check_db_dir_existence(((String *) db_name)->c_ptr_safe()); + String_stream s_stream; + int rc; + + s_stream << "SHOW CREATE DATABASE `" << db_name << "`"; + + Ed_result ed_result; + rc= run_service_interface_sql(thd, s_stream.lex_string(), &ed_result); + + /* We're not interested in warnings/errors here. */ + + return test(rc); } -/* - 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) +/////////////////////////////////////////////////////////////////////////// + +bool check_user_existence(THD *thd, const Obj *obj) { - int len= 0; - int tics= 0; - char *ptr= 0; +#ifdef EMBEDDED_LIBRARY + return TRUE; +#else + Grant_obj *grant_obj= (Grant_obj *) obj; + Ed_result ed_result; + String_stream s_stream; - /* - Since passwords are single byte characters and usernames can be multibyte - characters and the 0x40 = 64 = @ can occur in the username, we must search - for the first @ from the right. - */ - len= grantee->length(); - len--; - ptr= grantee->c_ptr() + len; - while ((len > 0) && (*ptr != '@')) - { - len--; - ptr= grantee->c_ptr() + len; - } + s_stream << + "SELECT 1 " + "FROM INFORMATION_SCHEMA.USER_PRIVILEGES " + "WHERE grantee = \"" << grant_obj->get_user_name() << "\""; - 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) + if (run_service_interface_sql(thd, s_stream.lex_string(), &ed_result) || + ed_result.get_warnings().elements > 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; -} - -bool check_user_existence(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 + /* Should be no warnings. */ + return FALSE; } - return user_exists; -} - -/** - Locate the row in the information_schema view for this tablespace. - This method returns a row from a tablespace information_schema view - that matches the tablespace name passed. + Ed_result_set *ed_result_set= ed_result.get_cur_result_set(); - @param[in] thd Thread context - @param[in] is_table_idx The information schema to search - @param[in] ts_name The name of the tablespace to find - @param[in] ts_engine Engine of the tablespace to find - @param[out] datafile The datafile for the tablespace - @param[out] comments The comments for the tablespace - - @retval FALSE if tablespace exists and no errors - @retval TRUE if tablespace does not exist or errors -*/ -static bool find_tablespace_schema_row(THD *thd, - enum_schema_tables is_table_idx, - const String *ts_name, - const String *ts_engine, - String *datafile, - String *comments) -{ - TABLE *is_table; - handler *ha; - my_bitmap_map *orig_col; - LEX_STRING lex_ts_name; - String found_ts_name, found_ts_engine; - bool retval= TRUE; - String data; - List ts_list; - DBUG_ENTER("obs::find_tablespace_schema_row()"); + if (!ed_result_set) + return FALSE; - /* - First, open the IS table. - */ - lex_ts_name.str= (char *)ts_name->ptr(); - lex_ts_name.length= ts_name->length(); - ts_list.push_back(&lex_ts_name); + return ed_result_set->data()->elements > 0; +#endif +} - if (InformationSchemaIterator::prepare_is_table( - thd, &is_table, &ha, &orig_col, is_table_idx, ts_list)) - DBUG_RETURN(TRUE); +/////////////////////////////////////////////////////////////////////////// - /* Locate the row in the schema table and retrive the data. */ - switch (is_table_idx) { - case SCH_TABLESPACES: - while (!ha->rnd_next(is_table->record[0])) - { - is_table->field[IS_TABLESPACES_TABLESPACE_NAME]->val_str(&found_ts_name); - is_table->field[IS_TABLESPACES_ENGINE]->val_str(&found_ts_engine); - if (found_ts_name.length() && found_ts_engine.length() && - !my_strnncoll(system_charset_info, (const uchar*) found_ts_name.ptr(), - found_ts_name.length(), (const uchar*) ts_name->ptr(), - ts_name->length()) && - !my_strnncoll(system_charset_info, - (const uchar*) found_ts_engine.ptr(), - found_ts_engine.length(), - (const uchar*) ts_engine->ptr(), ts_engine->length())) - { - retval= FALSE; - is_table->field[IS_TABLESPACES_TABLESPACE_COMMENT]->val_str(&data); - comments->copy(data); - DBUG_PRINT("find_tablespace_schema_row", (" Found tablespace %s", - found_ts_name.ptr())); - break; - } - found_ts_name.length(0); - found_ts_engine.length(0); - } - break; - case SCH_FILES: - while (!ha->rnd_next(is_table->record[0])) - { - is_table->field[IS_FILES_TABLESPACE_NAME]->val_str(&found_ts_name); - is_table->field[IS_FILES_ENGINE]->val_str(&found_ts_engine); - if (found_ts_name.length() && found_ts_engine.length() && - !my_strnncoll(system_charset_info, (const uchar*) found_ts_name.ptr(), - found_ts_name.length(), (const uchar*) ts_name->ptr(), - ts_name->length()) && - !my_strnncoll(system_charset_info, - (const uchar*) found_ts_engine.ptr(), - found_ts_engine.length(), - (const uchar*) ts_engine->ptr(), ts_engine->length())) - { - retval= FALSE; - is_table->field[IS_FILES_FILE_NAME]->val_str(&data); - datafile->copy(data); - DBUG_PRINT("find_tablespace_schema_row", (" Found tablespace %s", - found_ts_name.ptr())); - break; - } - found_ts_name.length(0); - found_ts_engine.length(0); - } - break; - default: - DBUG_ASSERT(0); - break; - } +const String *grant_get_user_name(const Obj *obj) +{ + return ((Grant_obj *) obj)->get_user_name(); +} - /* - Cleanup - */ - ha->ha_rnd_end(); +/////////////////////////////////////////////////////////////////////////// - dbug_tmp_restore_column_map(is_table->read_set, orig_col); - free_tmp_table(thd, is_table); - DBUG_RETURN(retval); +const String *grant_get_grant_info(const Obj *obj) +{ + return ((Grant_obj *) obj)->get_grant_info(); } -/** - Build a valid tablespace from the information_schema views. +/////////////////////////////////////////////////////////////////////////// - This method builds a @c TablespaceObj object if the tablespace - exists on the server. +Obj *find_tablespace(THD *thd, const String *ts_name) +{ + Ed_result ed_result; + String_stream s_stream; - @param[in] thd Thread context. - @param[out] TablespaceObj A pointer to a new tablespace object - @param[in] ts_name The name of the tablespace to find - @param[in] ts_engine Engine of the tablespace to find + s_stream << + "SELECT t1.tablespace_comment, t2.file_name, t1.engine " + "FROM INFORMATION_SCHEMA.TABLESPACES AS t1, " + "INFORMATION_SCHEMA.FILES AS t2 " + "WHERE t1.tablespace_name = t2.tablespace_name AND " + "t1.tablespace_name = '" << ts_name << "'"; - @note Caller is responsible for destroying the tablespace object. - @retval FALSE if tablespace exists and no errors - @retval TRUE if tablespace does not exist or errors -*/ -static bool get_tablespace_from_schema(THD *thd, - TablespaceObj **ts, - const String *ts_name, - const String *ts_engine) -{ - String datafile; - String comments; - DBUG_ENTER("obs::get_tablespace_from_schema()"); + if (run_service_interface_sql(thd, s_stream.lex_string(), &ed_result) || + ed_result.get_warnings().elements > 0) + { + /* Should be no warnings. */ + return NULL; + } - /* - Locate the row in TABLESPACES and get the comments. - */ - if (find_tablespace_schema_row(thd, SCH_TABLESPACES, - ts_name, ts_engine, &datafile, &comments)) - DBUG_RETURN(TRUE); + if (!ed_result.elements) + return NULL; - /* - Locate the row in FILES and get the datafile. - */ - if (find_tablespace_schema_row(thd, SCH_FILES, - ts_name, ts_engine, &datafile, &comments)) - DBUG_RETURN(TRUE); + Ed_result_set *ed_result_set= ed_result.get_cur_result_set(); - /* - The datafile parameter is required. - */ - if (datafile.length() == 0) - DBUG_RETURN(TRUE); + /* The result must contain only one result-set. */ + DBUG_ASSERT(ed_result_set->data()->elements == 1); - DBUG_PRINT("get_tablespace_from_schema", (" Found tablespace %s %s", - ts_name->ptr(), datafile.ptr())); + Ed_row *row= ed_result_set->get_cur_row(); - TablespaceObj *ts_local= new TablespaceObj(ts_name); - *ts= ts_local; - ts_local->set_datafile(&datafile); - ts_local->set_comments(&comments); - ts_local->set_engine(ts_engine); + /* There must be 3 columns. */ + DBUG_ASSERT(row->get_metadata()->get_num_columns() == 3); - DBUG_RETURN(FALSE); + const LEX_STRING *comment= row->get_column(0); + const LEX_STRING *data_file_name= row->get_column(1); + const LEX_STRING *engine= row->get_column(2); + + return new Tablespace_obj(ts_name->lex_string(), + *comment, *data_file_name, *engine); } +/////////////////////////////////////////////////////////////////////////// + /** Retrieve the tablespace for a table if it exists - This method returns a @c TablespaceObj object if the table has a tablespace. + This method returns a @c Tablespace_obj object if the table has a tablespace. - @param[in] thd Thread context. - @param[in] db_name The database name for the table. - @param[in] tbl_name The table name. + @param[in] thd Thread context. + @param[in] db_name The database name for the table. + @param[in] table_name The table name. @note Caller is responsible for destroying the object. - @retval Tablespace object if table uses a tablespace - @retval NULL if table does not use a tablespace + @return Tablespace object. + @retval Tablespace object if table uses a tablespace. + @retval NULL if table does not use a tablespace. */ -Obj *get_tablespace_for_table(THD *thd, - const String *db_name, - const String *tbl_name) + +Obj *find_tablespace_for_table(THD *thd, + const String *db_name, + const String *table_name) { - TablespaceObj *ts= NULL; - char path[FN_REFLEN]; - String ts_name, ts_engine; - const char *ts_name_str= NULL; - DBUG_ENTER("obs::get_tablespace_for_table()"); - DBUG_PRINT("obs::get_tablespace_for_table", ("name: %s.%s", - db_name->ptr(), tbl_name->ptr())); - - const char *db= db_name->ptr(); - const char *name= tbl_name->ptr(); - - build_table_filename(path, sizeof(path), db, name, "", 0); - ts_name.length(0); - ts_engine.length(0); - - TABLE *table= open_temporary_table(thd, path, db, name, - FALSE /* don't link to thd->temporary_tables */, - OTM_OPEN); + Ed_result ed_result; + String_stream s_stream; + + s_stream << + "SELECT t1.tablespace_name, t1.engine, t1.tablespace_comment, t2.file_name " + "FROM INFORMATION_SCHEMA.TABLESPACES AS t1, " + "INFORMATION_SCHEMA.FILES AS t2, " + "INFORMATION_SCHEMA.TABLES AS t3 " + "WHERE t1.tablespace_name = t2.tablespace_name AND " + "t2.tablespace_name = t3.tablespace_name AND " + "t3.table_schema = '" << db_name << "' AND " + "t3.table_name = '" << table_name << "'"; - if (table) + + if (run_service_interface_sql(thd, s_stream.lex_string(), &ed_result) || + ed_result.get_warnings().elements > 0) { - if ((ts_name_str= table->file->get_tablespace_name())) - { - ts_name.append(ts_name_str); - ts_name.set_charset(system_charset_info); - ts_engine.append(table->file->engine_name()->str); - ts_engine.set_charset(system_charset_info); - } - intern_close_table(table); - my_free(table, MYF(0)); + /* Should be no warnings. */ + return NULL; } - else - goto end; - /* - Now open the information_schema table and get the tablespace information. - */ - if (ts_name_str) - get_tablespace_from_schema(thd, &ts, &ts_name, &ts_engine); -end: - DBUG_RETURN(ts); -} + if (!ed_result.elements) + return NULL; -/** - Determine if tablespace exists. + Ed_result_set *ed_result_set= ed_result.get_cur_result_set(); - This method determines if a materialized tablespace exists on the - system. This compares the name and all saved attributes of the - tablespace. A FALSE return would mean either the tablespace does - not exist or the tablespace attributes are different. + if (!ed_result_set->data()->elements) + return NULL; - @param[in] Obj The TablspaceObj pointer to compare. + /* The result must contain only one result-set. */ + DBUG_ASSERT(ed_result_set->data()->elements == 1); - @retval TRUE if it exists - @retval FALSE if it does not exist -*/ -bool tablespace_exists(THD *thd, - Obj *ts) -{ - TablespaceObj *other_ts= NULL, *this_ts= static_cast(ts); - bool retval= FALSE; - DBUG_ENTER("obs::tablespace_exists()"); - get_tablespace_from_schema(thd, &other_ts, this_ts->get_name(), - this_ts->get_engine()); - if (!other_ts) - DBUG_RETURN(retval); - retval= (my_strcasecmp(system_charset_info, - other_ts->build_serialization()->ptr(), - ((TablespaceObj *)ts)->build_serialization()->ptr()) == 0); - delete other_ts; - DBUG_RETURN(retval); -} + Ed_row *row= ed_result_set->get_cur_row(); -/** - Is there a tablespace with the given name? + /* There must be 4 columns. */ + DBUG_ASSERT(row->get_metadata()->get_num_columns() == 4); - This method determines if the tablespace referenced by name exists on the - system. Returns a TablespaceObj if it exists or NULL if it doesn't. + const LEX_STRING *ts_name= row->get_column(0); + const LEX_STRING *engine= row->get_column(1); + const LEX_STRING *comment= row->get_column(2); + const LEX_STRING *data_file_name= row->get_column(3); - @param[in] Obj The TablspaceObj pointer to compare. + return new Tablespace_obj(*ts_name, *comment, *data_file_name, *engine); +} - @note Caller is responsible for destroying the tablespace object. +/////////////////////////////////////////////////////////////////////////// - @returns the tablespace if found or NULL if not found -*/ -Obj *is_tablespace(THD *thd, Obj *ts) +bool compare_tablespace_attributes(Obj *ts1, Obj *ts2) { - TablespaceObj *other_ts= NULL, *this_ts= static_cast(ts); - DBUG_ENTER("obs::is_tablespace()"); - get_tablespace_from_schema(thd, &other_ts, this_ts->get_name(), - this_ts->get_engine()); - DBUG_RETURN(other_ts); + DBUG_ENTER("obs::compare_tablespace_attributes"); + + Tablespace_obj *o1= (Tablespace_obj *) ts1; + Tablespace_obj *o2= (Tablespace_obj *) ts2; + + DBUG_RETURN(my_strcasecmp(system_charset_info, + o1->get_description()->ptr(), + o2->get_description()->ptr()) == 0); } /////////////////////////////////////////////////////////////////////////// @@ -3698,65 +2836,70 @@ Obj *is_tablespace(THD *thd, Obj *ts) */ /** - Turn on the ddl blocker + Turn on the ddl blocker - This method is used to start the ddl blocker blocking DDL commands. + This method is used to start the ddl blocker blocking DDL commands. - @param[in] thd current thread + @param[in] thd current thread - @retval FALSE on success. - @retval TRUE on error. - */ + @return Error status. + @retval FALSE on success. + @retval TRUE on error. +*/ bool ddl_blocker_enable(THD *thd) { - DBUG_ENTER("ddl_blocker_enable()"); + DBUG_ENTER("obs::ddl_blocker_enable"); if (!DDL_blocker->block_DDL(thd)) DBUG_RETURN(TRUE); DBUG_RETURN(FALSE); } + /** - Turn off the ddl blocker + Turn off the ddl blocker - This method is used to stop the ddl blocker from blocking DDL commands. - */ + This method is used to stop the ddl blocker from blocking DDL commands. +*/ void ddl_blocker_disable() { - DBUG_ENTER("ddl_blocker_disable()"); + DBUG_ENTER("obs::ddl_blocker_disable"); DDL_blocker->unblock_DDL(); DBUG_VOID_RETURN; } + /** - Turn on the ddl blocker exception + Turn on the ddl blocker exception - This method is used to allow the exception allowing a restore operation to - perform DDL operations while the ddl blocker blocking DDL commands. + This method is used to allow the exception allowing a restore operation to + perform DDL operations while the ddl blocker blocking DDL commands. - @param[in] thd current thread - */ + @param[in] thd current thread +*/ void ddl_blocker_exception_on(THD *thd) { - DBUG_ENTER("ddl_blocker_exception_on()"); + DBUG_ENTER("obs::ddl_blocker_exception_on"); thd->DDL_exception= TRUE; DBUG_VOID_RETURN; } + /** - Turn off the ddl blocker exception + Turn off the ddl blocker exception - This method is used to suspend the exception allowing a restore operation to - perform DDL operations while the ddl blocker blocking DDL commands. + This method is used to suspend the exception allowing a restore operation to + perform DDL operations while the ddl blocker blocking DDL commands. - @param[in] thd current thread - */ + @param[in] thd current thread +*/ void ddl_blocker_exception_off(THD *thd) { - DBUG_ENTER("ddl_blocker_exception_off()"); + DBUG_ENTER("obs::ddl_blocker_exception_off"); thd->DDL_exception= FALSE; DBUG_VOID_RETURN; } + /** Build a table list from a list of tables as class Obj. @@ -3774,7 +2917,7 @@ TABLE_LIST *Name_locker::build_table_lis { TABLE_LIST *tl= NULL; Obj *tbl= NULL; - DBUG_ENTER("Name_locker::build_table_list()"); + DBUG_ENTER("Name_locker::build_table_list"); List_iterator it(*tables); while ((tbl= it++)) @@ -3798,15 +2941,16 @@ TABLE_LIST *Name_locker::build_table_lis DBUG_RETURN(tl); } -void Name_locker::free_table_list(TABLE_LIST *tl) + +void Name_locker::free_table_list(TABLE_LIST *table_list) { - TABLE_LIST *ptr= tl; + TABLE_LIST *ptr= table_list; while (ptr) { - tl= tl->next_global; + table_list= table_list->next_global; my_free(ptr, MYF(0)); - ptr= tl; + ptr= table_list; } } @@ -3825,7 +2969,7 @@ int Name_locker::get_name_locks(List to TABLE_LIST * */ @@ -3852,7 +2996,7 @@ int Name_locker::get_name_locks(Listvariables.sql_mode; - thd->variables.sql_mode= 0; - - set_var_collation_client saved_charset_settings( - thd->variables.character_set_client, - thd->variables.character_set_results, - thd->variables.collation_connection); - - set_var_collation_client new_charset_settings(::system_charset_info, - ::system_charset_info, - ::system_charset_info); - new_charset_settings.update(thd); - - bool ret= do_execute(thd); - - saved_charset_settings.update(thd); - thd->variables.sql_mode= saved_sql_mode; - - return ret; -} - -/** - Serialize object state into a buffer. The buffer actually should be a - binary buffer. String class is used here just because we don't have - convenient primitive for binary buffers. - - Serialization format is opaque to the client, i.e. the client should - not make any assumptions about the format or the content of the - returned buffer. - - Serialization format can be changed in the future versions. However, - the server must be able to materialize objects coded in any previous - formats. - - @param[in] thd Server thread context. - @param[in] serialization Buffer to serialize the object - - @return error status. - @retval FALSE on success. - @retval TRUE on error. - - @note The real work is done inside @c do_serialize() primitive which should be - defied in derived classes. This method prepares appropriate context and calls - the primitive. -*/ -inline -bool Obj::serialize(THD *thd, String *serialization) -{ - ulong saved_sql_mode= thd->variables.sql_mode; - thd->variables.sql_mode= 0; - - bool ret= do_serialize(thd, serialization); - - thd->variables.sql_mode= saved_sql_mode; - - return ret; -} - /////////////////////////////////////////////////////////////////////////// /** - Obj_iterator is a basic interface to enumerate the objects. + @class Obj_iterator + + This is a basic interface to enumerate objects. */ class Obj_iterator { public: - Obj_iterator() { } /** This operation returns a pointer to the next object in an enumeration. It returns NULL if there is no more objects. + Results of an attempt to continue iteration when there is no + more objects are undefined. - The client is responsible to destroy the returned object. + The client is responsible for destruction of the returned object. @return a pointer to the object @retval NULL if there is no more objects in an enumeration. @@ -226,254 +128,115 @@ public: public: virtual ~Obj_iterator() { } - -}; - -/** - GrantObjIternator is an encapsulation of the three iterators for each level - of grant supported: database-, table- and routine-, and column-level. -*/ -class GrantObjIterator : public Obj_iterator -{ -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: - Obj_iterator *db_grants; ///< database-level grants - Obj_iterator *tbl_grants; ///< table- and routine-level grants - Obj_iterator *col_grants; ///< column-level grants }; /////////////////////////////////////////////////////////////////////////// -// The functions in this section are intended to construct an instance of -// Obj class for any particular database object. These functions do not -// interact with the server to validate requested names. So, it is possible -// to construct instances for non-existing objects. +// Functions in this section are intended to construct an instance of Obj +// class for any particular database object. These functions do not interact +// with the server to validate requested names. So, it is possible to +// construct instances for non-existing objects. // // The client is responsible for destroying the returned object. /** Construct an instance of Obj representing a database. - No actual actions are performed in the server. An object can be created - even for invalid database name or for non-existing database. + No actions are performed in the server. An object can be created + even for an invalid database name or for a non-existing database. - The client is responsible to destroy the created object. + The client is responsible for destruction of the created object. @param[in] db_name Database name. - @return a pointer to an instance of Obj representing given database. -*/ - -Obj *get_database(const String *db_name); - -/** - Construct an instance of Obj representing a table. - - No actual actions are performed in the server. An object can be created - even for invalid database/table name or for non-existing table. - - The client is responsible to destroy the created object. - - @param[in] db_name Database name. - @param[in] table_name Table name. - - @return a pointer to an instance of Obj representing given table. + @return a pointer to an instance of Obj representing the given database. */ - -Obj *get_table(const String *db_name, const String *table_name); - -/** - Construct an instance of Obj representing a view. - - No actual actions are performed in the server. An object can be created - even for invalid database/view name or for non-existing view. - - The client is responsible to destroy the created object. - - @param[in] db_name Database name. - @param[in] view_name View name. - - @return a pointer to an instance of Obj representing given view. -*/ - -Obj *get_view(const String *db_name, const String *view_name); - -/** - Construct an instance of Obj representing a trigger. - - No actual actions are performed in the server. An object can be created - even for invalid database/trigger name or for non-existing trigger. - - The client is responsible to destroy the created object. - - @param[in] db_name Database name. - @param[in] trigger_name Trigger name. - - @return a pointer to an instance of Obj representing given trigger. -*/ - -Obj *get_trigger(const String *db_name, const String *trigger_name); - -/** - Construct an instance of Obj representing a stored procedure. - - No actual actions are performed in the server. An object can be created - even for invalid database/procedure name or for non-existing stored - procedure. - - The client is responsible to destroy the created object. - - @param[in] db_name Database name. - @param[in] sp_name Stored procedure name. - - @return a pointer to an instance of Obj representing given stored - procedure. -*/ - -Obj *get_stored_procedure(const String *db_name, const String *sp_name); - -/** - Construct an instance of Obj representing a stored function. - - No actual actions are performed in the server. An object can be created - even for invalid database/function name or for non-existing stored - function. - - The client is responsible to destroy the created object. - - @param[in] db_name Database name. - @param[in] sf_name Stored function name. - - @return a pointer to an instance of Obj representing given stored - function. -*/ - -Obj *get_stored_function(const String *db_name, const String *sf_name); - -/** - Construct an instance of Obj representing an event. - - No actual actions are performed in the server. An object can be created - even for invalid database/event name or for non-existing event. - - The client is responsible to destroy the created object. - - @param[in] db_name Database name. - @param[in] event_name Event name. - - @return a pointer to an instance of Obj representing given event. -*/ - -Obj *get_event(const String *db_name, const String *event_name); +Obj *get_database_stub(const String *db_name); /////////////////////////////////////////////////////////////////////////// -// The functions in this section provides a way to iterator over all -// objects in the server or in the particular database. +// Functions in this section provide a way to iterate over all objects in +// the server or in a particular database. // -// The client is responsible for destroying the returned iterator. +// The client is responsible for destruction of the returned iterator. + +/////////////////////////////////////////////////////////////////////////// /** Create an iterator over all databases in the server. + Includes system databases, such as "mysql" and "information_schema". - The client is responsible to destroy the returned iterator. + The client is responsible for destruction of the returned iterator. @return a pointer to an iterator object. */ - Obj_iterator *get_databases(THD *thd); /** - Create an iterator over all tables in the particular database. + Create an iterator over all base tables in a particular database. + Temporary tables are not included. - The client is responsible to destroy the returned iterator. + The client is responsible for destruction of the returned iterator. @return a pointer to an iterator object. @retval NULL in case of error. */ - Obj_iterator *get_db_tables(THD *thd, const String *db_name); /** - Create an iterator over all views in the particular database. + Create an iterator over all views in a particular database. - The client is responsible to destroy the returned iterator. + The client is responsible for destruction of the returned iterator. @return a pointer to an iterator object. @retval NULL in case of error. */ - Obj_iterator *get_db_views(THD *thd, const String *db_name); /** - Create an iterator over all triggers in the particular database. + Create an iterator over all triggers in a particular database. - The client is responsible to destroy the returned iterator. + The client is responsible for destruction of the returned iterator. @return a pointer to an iterator object. @retval NULL in case of error. */ - Obj_iterator *get_db_triggers(THD *thd, const String *db_name); /** - Create an iterator over all stored procedures in the particular database. + Create an iterator over all stored procedures in a particular database. - The client is responsible to destroy the returned iterator. + The client is responsible for destruction of the returned iterator. @return a pointer to an iterator object. @retval NULL in case of error. */ - Obj_iterator *get_db_stored_procedures(THD *thd, const String *db_name); /** - Create an iterator over all stored functions in the particular database. + Create an iterator over all stored functions in a particular database. - The client is responsible to destroy the returned iterator. + The client is responsible for destruction of the returned iterator. @return a pointer to an iterator object. @retval NULL in case of error. */ - Obj_iterator *get_db_stored_functions(THD *thd, const String *db_name); /** - Create an iterator over all events in the particular database. + Create an iterator over all events in a particular database. - The client is responsible to destroy the returned iterator. + The client is responsible for destruction of the returned iterator. @return a pointer to an iterator object. @retval NULL in case of error. */ - Obj_iterator *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. + routine-, and column-level- privileges. This allows to retrieve all + privileges of a given database using a single iterator. */ Obj_iterator *get_all_db_grants(THD *thd, const String *db_name); @@ -481,83 +244,92 @@ Obj_iterator *get_all_db_grants(THD *thd // The functions are intended to enumerate dependent objects. // -// The client is responsible for destroying the returned iterator. +// The client is responsible for destruction of the returned iterator. + +/////////////////////////////////////////////////////////////////////////// /** - Create an iterator overl all base tables in the particular view. + Create an iterator over all base tables of a view. - The client is responsible to destroy the returned iterator. + The client is responsible for destruction of the returned iterator. @return a pointer to an iterator object. @retval NULL in case of error. */ - Obj_iterator* get_view_base_tables(THD *thd, const String *db_name, const String *view_name); /** - Create an iterator overl all base tables in the particular view. + Create an iterator over all base views of a particular view. - The client is responsible to destroy the returned iterator. + The client is responsible for destruction of the returned iterator. @return a pointer to an iterator object. @retval NULL in case of error. */ - Obj_iterator* get_view_base_views(THD *thd, const String *db_name, const String *view_name); /////////////////////////////////////////////////////////////////////////// -// The functions in this section provides a way to materialize objects from -// the serialized form. +// Functions in this section provide a way to materialize objects from their +// serialized form (serialization image). In order to do that, the client +// creates an object handle, by means of one of the functions below, and +// then calls "create()" method on it. // -// The client is responsible for destroying the returned iterator. +// The client is responsible for destruction of the returned object handle. +// +// The client is responsible for providing valid serialization image. The +// operations below do not modify serialization image in any way. In +// particular, the client is responsible to advance in the serialiazation +// stream after successful object restoration. + +/////////////////////////////////////////////////////////////////////////// -Obj *materialize_database(const String *db_name, - uint serialization_version, - const String *serialization); - -Obj *materialize_table(const String *db_name, - const String *table_name, - uint serialization_version, - const String *serialization); - -Obj *materialize_view(const String *db_name, - const String *view_name, - uint serialization_version, - const String *serialization); - -Obj *materialize_trigger(const String *db_name, - const String *trigger_name, - uint serialization_version, - const String *serialization); - -Obj *materialize_stored_procedure(const String *db_name, - const String *stored_proc_name, - uint serialization_version, - const String *serialization); - -Obj *materialize_stored_function(const String *db_name, - const String *stored_func_name, - uint serialization_version, - const String *serialization); - -Obj *materialize_event(const String *db_name, - const String *event_name, - uint serialization_version, - const String *serialization); - -Obj *materialize_tablespace(const String *ts_name, - uint serialization_version, - const String *serialization); - -Obj *materialize_db_grant(const String *grantee, - const String *db_name, - uint serialization_version, - const String *serialization); +Obj *get_database(const String *db_name, + uint image_version, + const String *image); + +Obj *get_table(const String *db_name, + const String *table_name, + uint image_version, + const String *image); + +Obj *get_view(const String *db_name, + const String *view_name, + uint image_version, + const String *image); + +Obj *get_trigger(const String *db_name, + const String *trigger_name, + uint image_version, + const String *image); + +Obj *get_stored_procedure(const String *db_name, + const String *stored_proc_name, + uint image_version, + const String *image); + +Obj *get_stored_function(const String *db_name, + const String *stored_func_name, + uint image_version, + const String *image); + +Obj *get_event(const String *db_name, + const String *event_name, + uint image_version, + const String *image); + +Obj *get_tablespace(const String *ts_name, + uint image_version, + const String *image); + +Obj *get_db_grant(const String *db_name, + const String *name, + uint image_version, + const String *image); /////////////////////////////////////////////////////////////////////////// @@ -565,14 +337,11 @@ Obj *materialize_db_grant(const String * Check if the given database name is reserved for internal use. @return - @retval TRUE if the given database name is reserved for internal use + @retval TRUE if the given database name is reserved for internal use. @retval FALSE otherwise. */ - bool is_internal_db_name(const String *db_name); -/////////////////////////////////////////////////////////////////////////// - /** Check if the given directory actually exists. @@ -580,42 +349,49 @@ bool is_internal_db_name(const String *d @retval FALSE on success (the database exists and accessible). @retval TRUE on error (the database either not exists, or not accessible). */ +bool check_db_existence(THD *thd, const String *db_name); -bool check_db_existence(const String *db_name); - -/* - Check if the given user is actually defined on the system. +/** + Check if the user is defined on the system. - @return Existence status. - @retval TRUE if user is defined on the system. - @retval FALSE if user does not exist. + @return + @retval TRUE if user is defined + @retval FALSE otherwise */ +bool check_user_existence(THD *thd, const Obj *obj); -bool check_user_existence(THD *thd, const String *grantee); +/** + Return user name of materialized grant object. +*/ +const String *grant_get_user_name(const Obj *obj); -/* - This method returns a @c TablespaceObj object if the table has a tablespace. +/** + Return grant info of materialized grant object. */ +const String *grant_get_grant_info(const Obj *obj); -Obj *get_tablespace_for_table(THD *thd, - const String *db_name, - const String *tbl_name); +/** + Determine if the tablespace referenced by name exists on the system. -/* - This method determines if a materialized tablespace exists on the - system. This compares the name and all saved attributes of the - tablespace. A FALSE return would mean either the tablespace does - not exist or the tablespace attributes are different. + @return a Tablespace_obj if it exists or NULL if it doesn't. */ +Obj *find_tablespace(THD *thd, const String *ts_name); -bool tablespace_exists(THD *thd, Obj *ts); - -/* - This method determines if the tablespace referenced by name exists on the - system. Returns a TablespaceObj if it exists or NULL if it doesn't. +/** + This method returns a @c Tablespace_obj object if the table has a + tablespace. */ +Obj *find_tablespace_for_table(THD *thd, + const String *db_name, + const String *table_name); -Obj *is_tablespace(THD *thd, Obj *ts); +/** + This method determines if a materialized tablespace exists on the system. + This compares the name and all saved attributes of the tablespace. A + FALSE return would mean either the tablespace does not exist or the + tablespace attributes are different. +*/ +bool compare_tablespace_attributes(Obj *ts1, Obj *ts2); /////////////////////////////////////////////////////////////////////////// @@ -623,6 +399,8 @@ Obj *is_tablespace(THD *thd, Obj *ts); // DDL blocker methods. // +/////////////////////////////////////////////////////////////////////////// + /** Turn on the ddl blocker. @@ -662,14 +440,6 @@ void ddl_blocker_exception_on(THD *thd); @param[in] thd Thread context. */ void ddl_blocker_exception_off(THD *thd); - -/* - Creates a WHERE clause for information schema table lookups of the - for FROM INFORMATION_SCHEMA.X WHERE IN ('a','b','c'). -*/ -COND *create_db_select_condition(THD *thd, - TABLE *t, - List *db_list); /* The following class is used to manage name locks on a list of tables. === modified file 'sql/sql_cache.cc' --- a/sql/sql_cache.cc 2008-11-11 16:47:57 +0000 +++ b/sql/sql_cache.cc 2008-11-24 23:00:01 +0000 @@ -1014,7 +1014,9 @@ void Query_cache::store_query(THD *thd, protocol (COM_EXECUTE) cannot be served to statements asking for results in the text protocol (COM_QUERY) and vice-versa. */ - flags.result_in_binary_protocol= (unsigned int) thd->protocol->type(); + flags.protocol_type= (unsigned int) thd->protocol->type(); + /* PROTOCOL_LOCAL results are not cached. */ + DBUG_ASSERT(flags.protocol_type != (unsigned int) Protocol::PROTOCOL_LOCAL); flags.more_results_exists= test(thd->server_status & SERVER_MORE_RESULTS_EXISTS); flags.pkt_nr= net->pkt_nr; @@ -1041,7 +1043,7 @@ sql mode: 0x%lx, sort len: %lu, conncat def_week_frmt: %lu", (int)flags.client_long_flag, (int)flags.client_protocol_41, - (int)flags.result_in_binary_protocol, + (int)flags.protocol_type, (int)flags.more_results_exists, flags.pkt_nr, flags.character_set_client_num, @@ -1279,7 +1281,7 @@ Query_cache::send_result_to_client(THD * flags.client_long_flag= test(thd->client_capabilities & CLIENT_LONG_FLAG); flags.client_protocol_41= test(thd->client_capabilities & CLIENT_PROTOCOL_41); - flags.result_in_binary_protocol= (unsigned int)thd->protocol->type(); + flags.protocol_type= (unsigned int) thd->protocol->type(); flags.more_results_exists= test(thd->server_status & SERVER_MORE_RESULTS_EXISTS); flags.pkt_nr= thd->net.pkt_nr; @@ -1304,7 +1306,7 @@ sql mode: 0x%lx, sort len: %lu, conncat def_week_frmt: %lu", (int)flags.client_long_flag, (int)flags.client_protocol_41, - (int)flags.result_in_binary_protocol, + (int)flags.protocol_type, (int)flags.more_results_exists, flags.pkt_nr, flags.character_set_client_num, === modified file 'sql/sql_error.h' --- a/sql/sql_error.h 2008-11-18 22:30:59 +0000 +++ b/sql/sql_error.h 2008-11-19 19:20:47 +0000 @@ -80,8 +80,6 @@ private: public: Warning_info(ulonglong warn_id_arg); - /* Do nothing - used to initialize a backup info */ - Warning_info() { clear_alloc_root(&m_warn_root); } ~Warning_info(); /** === modified file 'sql/sql_lex.cc' --- a/sql/sql_lex.cc 2008-10-16 02:13:16 +0000 +++ b/sql/sql_lex.cc 2008-11-24 23:00:01 +0000 @@ -37,6 +37,7 @@ sys_var *trg_new_row_fake_var= (sys_var* LEX_STRING constant for null-string to be used in parser and other places. */ const LEX_STRING null_lex_str= {NULL, 0}; +const LEX_STRING empty_lex_str= { (char*) "", 0 }; /* Longest standard keyword name */ @@ -144,6 +145,7 @@ Lex_input_stream::Lex_input_stream(THD * found_semicolon(NULL), ignore_space(test(thd->variables.sql_mode & MODE_IGNORE_SPACE)), stmt_prepare_mode(FALSE), + multi_statements(TRUE), in_comment(NO_COMMENT), m_underscore_cs(NULL) { === modified file 'sql/sql_lex.h' --- a/sql/sql_lex.h 2008-11-19 18:34:03 +0000 +++ b/sql/sql_lex.h 2008-11-24 23:00:01 +0000 @@ -942,6 +942,7 @@ enum xa_option_words {XA_NONE, XA_JOIN, XA_SUSPEND, XA_FOR_MIGRATE}; extern const LEX_STRING null_lex_str; +extern const LEX_STRING empty_lex_str; /* @@ -1484,7 +1485,6 @@ public: TRUE if we should allow multi-statements. */ bool multi_statements; - /** State of the lexical analyser for comments. */ enum_comment_state in_comment; === modified file 'sql/sql_prepare.cc' --- a/sql/sql_prepare.cc 2008-11-19 18:34:03 +0000 +++ b/sql/sql_prepare.cc 2008-11-28 21:35:11 +0000 @@ -162,7 +162,7 @@ public: bool execute_loop(String *expanded_query, bool open_cursor, uchar *packet_arg, uchar *packet_end_arg); - bool execute_immediate(const char *stmt, uint length); + bool execute_server_runnable(Server_runnable *server_runnable); /* Destroy this statement */ void deallocate(); private: @@ -184,6 +184,18 @@ private: }; +/** +*/ + +class Execute_sql_statement: public Server_runnable +{ +public: + Execute_sql_statement(LEX_STRING sql_text); + virtual bool execute_server_code(THD *thd); +private: + LEX_STRING m_sql_text; +}; + /****************************************************************************** Implementation ******************************************************************************/ @@ -2764,6 +2776,54 @@ void mysql_stmt_get_longdata(THD *thd, c } +bool +mysql_execute_direct(THD *thd, LEX_STRING query, Ed_result *ed_result) +{ + Execute_sql_statement execute_sql_statement(query); + + return mysql_execute_direct(thd, &execute_sql_statement, ed_result); +} + + +/** + Execute a fragment of server functionality without an effect on + thd, and store results in Ed_result. + + @param thd Thread handle. + @param server_runnable A code fragment to execute. + @param ed_result Result interceptor +*/ + +bool +mysql_execute_direct(THD *thd, Server_runnable *server_runnable, + Ed_result *ed_result) +{ + Protocol_local protocol_local(thd, ed_result); + Prepared_statement stmt(thd); + + DBUG_ENTER("mysql_execute_direct"); + + DBUG_ASSERT(ed_result); + + Protocol *protocol_saved= thd->protocol; + + thd->protocol= &protocol_local; + + ed_result->begin_statement(thd); + bool rc= stmt.execute_server_runnable(server_runnable); + ed_result->end_statement(thd); + + thd->protocol->end_statement(); + + thd->protocol= protocol_saved; + + thd->main_da.reset_diagnostics_area(); + + DBUG_RETURN(rc); +} + + + /*************************************************************************** Select_fetch_protocol_binary ****************************************************************************/ @@ -2809,6 +2869,63 @@ Select_fetch_protocol_binary::send_data( return rc; } +/******************************************************************* +* +*******************************************************************/ + +Server_runnable::~Server_runnable() +{ +} + +/////////////////////////////////////////////////////////////////////////// + +Execute_sql_statement:: +Execute_sql_statement(LEX_STRING sql_text) + :m_sql_text(sql_text) +{} + + +/** + Parse and execute a statement. Does not prepare the query. + + Allows to execute a statement from within another statement. + The main property of the implementation is that it does not + affect the environment -- i.e. you can run many + executions without having to cleanup/reset THD in between. +*/ + +bool +Execute_sql_statement::execute_server_code(THD *thd) +{ + bool error; + + if (alloc_query(thd, m_sql_text.str, m_sql_text.length)) + return TRUE; + + Parser_state parser_state(thd, thd->query, thd->query_length); + + parser_state.m_lip.multi_statements= FALSE; + lex_start(thd); + + error= parse_sql(thd, &parser_state, NULL) || thd->is_error(); + + if (error) + goto end; + + thd->lex->set_trg_event_type_for_tables(); + + error= mysql_execute_command(thd); + + if (error == 0 && thd->spcont == NULL) + general_log_write(thd, COM_STMT_EXECUTE, + thd->query, thd->query_length); + +end: + lex_end(thd->lex); + + return error; +} + /*************************************************************************** Prepared_statement ****************************************************************************/ @@ -3259,81 +3376,42 @@ reexecute: } -/** - Parse and execute a query string. Does not prepare the query. - - An implementation of "EXECUTE IMMEDIATE" syntax of Dynamic SQL. - Allows to execute a statement from within another statement. - The main property of the implementation is that it does not - affect the environment -- i.e. you can run many - ::execute_immediate() without having to cleanup/reset THD in - between. -*/ - bool -Prepared_statement::execute_immediate(const char *query, uint length) +Prepared_statement::execute_server_runnable(Server_runnable *server_runnable) { Statement stmt_backup; bool error; + Query_arena *save_stmt_arena= thd->stmt_arena; + Item_change_list save_change_list= thd->change_list; state= CONVENTIONAL_EXECUTION; - if (!(lex = new (mem_root) st_lex_local)) + if (!(lex= new (mem_root) st_lex_local)) return TRUE; thd->set_n_backup_statement(this, &stmt_backup); + thd->set_n_backup_active_arena(this, &stmt_backup); + thd->stmt_arena= this; + thd->change_list.empty(); - if (alloc_query(thd, query, length)) - { - thd->set_statement(&stmt_backup); - return TRUE; - } - /* - Expanded query is needed for slow logging, so we want thd->query - to point at it even after we restore from backup. This is ok, as - expanded query was allocated in thd->mem_root. - */ - stmt_backup.query= thd->query; - stmt_backup.query_length= thd->query_length; - - Parser_state parser_state(thd, thd->query, thd->query_length); - - parser_state.m_lip.multi_statements= FALSE; - lex_start(thd); - - error= parse_sql(thd, &parser_state, NULL) || thd->is_error(); - - - if (lex->sql_command == SQLCOM_PREPARE || - lex->sql_command == SQLCOM_EXECUTE || - (lex->sql_command == SQLCOM_CHANGE_DB && is_sql_prepare())) - { - my_error(ER_PS_NO_RECURSION, MYF(0)); - error= 1; - } - - if (error) - { - thd->set_statement(&stmt_backup); - return TRUE; - } - - lex->set_trg_event_type_for_tables(); + error= server_runnable->execute_server_code(thd); - if (query_cache_send_result_to_client(thd, thd->query, - thd->query_length) <= 0) - { - error= mysql_execute_command(thd); - } + delete lex->sphead; + lex->sphead= 0; + /* The order is important */ + lex->unit.cleanup(); + close_thread_tables(thd); + thd->cleanup_after_query(); - cleanup_stmt(); - lex_end(thd->lex); + thd->restore_active_arena(this, &stmt_backup); + thd->restore_backup_statement(this, &stmt_backup); + thd->stmt_arena= save_stmt_arena; - thd->set_statement(&stmt_backup); + DBUG_ASSERT(thd->change_list.is_empty()); + thd->change_list= save_change_list; + save_change_list.empty(); - if (error == 0 && thd->spcont == NULL) - general_log_write(thd, COM_STMT_EXECUTE, - thd->query, thd->query_length); + /* Items and memory will freed in destructor */ return error; } === modified file 'sql/sql_string.h' --- a/sql/sql_string.h 2008-08-20 10:29:58 +0000 +++ b/sql/sql_string.h 2008-11-24 23:00:01 +0000 @@ -113,6 +113,11 @@ public: (void) realloc(str_length); return Ptr; } + LEX_STRING lex_string() const + { + LEX_STRING lex_string = { (char*) ptr(), length() }; + return lex_string; + } void set(String &str,uint32 offset,uint32 arg_length) { === modified file 'sql/sql_yacc.yy' --- a/sql/sql_yacc.yy 2008-11-06 18:39:27 +0000 +++ b/sql/sql_yacc.yy 2008-11-19 16:32:01 +0000 @@ -1485,7 +1485,7 @@ query: Lex_input_stream *lip = YYLIP; if ((YYTHD->client_capabilities & CLIENT_MULTI_QUERIES) && - ! lip->stmt_prepare_mode && + lip->multi_statements && ! lip->eof()) { /*