Server IP : 104.21.38.3 / Your IP : 162.158.170.55 Web Server : Apache System : Linux krdc-ubuntu-s-2vcpu-4gb-amd-blr1-01.localdomain 5.15.0-142-generic #152-Ubuntu SMP Mon May 19 10:54:31 UTC 2025 x86_64 User : www ( 1000) PHP Version : 7.4.33 Disable Function : passthru,exec,system,putenv,chroot,chgrp,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /www/server/mysql/src/client/dump/ |
Upload File : |
/* Copyright (c) 2015, 2023, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. 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, version 2.0, 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "mysql_crawler.h" #include "mysql_function.h" #include "stored_procedure.h" #include "table_definition_dump_task.h" #include "mysqldump_tool_chain_maker_options.h" #include "table_rows_dump_task.h" #include "table_deferred_indexes_dump_task.h" #include "event_scheduler_event.h" #include "privilege.h" #include "trigger.h" #include "view.h" #include "base/mysql_query_runner.h" #include <string> #include <vector> using std::string; using std::vector; using namespace Mysql::Tools::Dump; Mysql_crawler::Mysql_crawler(I_connection_provider* connection_provider, Mysql::I_callable<bool, const Mysql::Tools::Base::Message_data&>* message_handler, Simple_id_generator* object_id_generator, Mysql_chain_element_options* options, Mysqldump_tool_chain_maker_options* mysqldump_tool_cmaker_options, Mysql::Tools::Base::Abstract_program* program) : Abstract_crawler(message_handler, object_id_generator, program), Abstract_mysql_chain_element_extension( connection_provider, message_handler, options), m_mysqldump_tool_cmaker_options(mysqldump_tool_cmaker_options) {} void Mysql_crawler::enumerate_objects() { Mysql::Tools::Base::Mysql_query_runner* runner= this->get_runner(); std::vector<const Mysql::Tools::Base::Mysql_query_runner::Row*> gtid_mode; std::string gtid_value("OFF"); /* Check if the server is GTID enabled */ runner->run_query_store("SELECT @@global.gtid_mode", >id_mode); if (gtid_mode.size()) { std::vector<const Mysql::Tools::Base::Mysql_query_runner::Row*> ::iterator mode_it= gtid_mode.begin(); const Mysql::Tools::Base::Mysql_query_runner::Row& gtid_data= **mode_it; gtid_value= gtid_data[0]; } Mysql::Tools::Base::Mysql_query_runner::cleanup_result(>id_mode); /* get the GTID_EXECUTED value */ std::vector<const Mysql::Tools::Base::Mysql_query_runner::Row*> gtid_executed; runner->run_query_store("SELECT @@GLOBAL.GTID_EXECUTED", >id_executed); std::string gtid_output_val; if (gtid_executed.size()) { std::vector<const Mysql::Tools::Base::Mysql_query_runner::Row*> ::iterator gtid_executed_iter= gtid_executed.begin(); const Mysql::Tools::Base::Mysql_query_runner::Row& gtid_executed_val= **gtid_executed_iter; gtid_output_val= gtid_executed_val[0]; } Mysql::Tools::Base::Mysql_query_runner::cleanup_result(>id_executed); m_dump_start_task= new Dump_start_dump_task(gtid_value, gtid_output_val); m_dump_end_task= new Dump_end_dump_task(); m_tables_definition_ready_dump_task= new Tables_definition_ready_dump_task(); m_dump_end_task->add_dependency(m_dump_start_task); this->process_dump_task(m_dump_start_task); std::vector<const Mysql::Tools::Base::Mysql_query_runner::Row*> databases; runner->run_query_store("SHOW DATABASES", &databases); std::vector<Database* > db_list; std::vector<Database_end_dump_task* > db_end_task_list; for (std::vector<const Mysql::Tools::Base::Mysql_query_runner::Row*>::iterator it= databases.begin(); it != databases.end(); ++it) { std::string db_name= (**it)[0]; Database* database= new Database( this->generate_new_object_id(), db_name, this->get_create_statement(runner, "", db_name, "DATABASE IF NOT EXISTS").value()); m_current_database_start_dump_task= new Database_start_dump_task(database); Abstract_data_object* db_object = dynamic_cast<Abstract_data_object*>( m_current_database_start_dump_task->get_related_db_object()); /* This check is introduced so that only the database objects that are included in the dump are validated. */ if (!m_mysqldump_tool_cmaker_options->is_object_included_in_dump(db_object)) { delete m_current_database_start_dump_task; delete database; continue; } db_list.push_back(database); m_current_database_end_dump_task= new Database_end_dump_task(database); db_end_task_list.push_back(m_current_database_end_dump_task); m_current_database_start_dump_task->add_dependency(m_dump_start_task); m_dump_end_task->add_dependency(m_current_database_start_dump_task); m_dump_end_task->add_dependency(m_current_database_end_dump_task); this->process_dump_task(m_current_database_start_dump_task); this->enumerate_database_objects(*database); m_current_database_start_dump_task= NULL; } m_dump_end_task->add_dependency(m_tables_definition_ready_dump_task); this->process_dump_task(m_tables_definition_ready_dump_task); /* SHOW CREATE USER is introduced in 5.7.6 */ if (use_show_create_user) this->enumerate_users(); std::vector<Database* >::iterator it; std::vector<Database_end_dump_task* >::iterator it_end; for (it= db_list.begin(),it_end= db_end_task_list.begin(); ((it != db_list.end()) && (it_end != db_end_task_list.end())); ++it, ++it_end) { m_current_database_end_dump_task= *it_end; this->enumerate_views(**it); this->process_dump_task(m_current_database_end_dump_task); m_current_database_end_dump_task= NULL; } Mysql::Tools::Base::Mysql_query_runner::cleanup_result(&databases); this->process_dump_task(m_dump_end_task); this->report_crawler_completed(this); this->wait_for_tasks_completion(); delete runner; } void Mysql_crawler::enumerate_database_objects(const Database& db) { this->enumerate_tables(db); this->enumerate_functions<Mysql_function>(db, "FUNCTION"); this->enumerate_functions<Stored_procedure>(db, "PROCEDURE"); this->enumerate_event_scheduler_events(db); } void Mysql_crawler::enumerate_tables(const Database& db) { Mysql::Tools::Base::Mysql_query_runner* runner= this->get_runner(); std::vector<const Mysql::Tools::Base::Mysql_query_runner::Row*> tables; runner->run_query_store("SHOW TABLE STATUS FROM " + this->quote_name(db.get_name()), &tables); for (std::vector<const Mysql::Tools::Base::Mysql_query_runner::Row*>::iterator it= tables.begin(); it != tables.end(); ++it) { const Mysql::Tools::Base::Mysql_query_runner::Row& table_data= **it; std::string table_name= table_data[0]; // "Name" std::vector<const Mysql::Tools::Base::Mysql_query_runner::Row*> fields_data; runner->run_query_store("SHOW COLUMNS IN " + this->quote_name(table_name) + " FROM " + this->quote_name(db.get_name()), &fields_data); std::vector<Field> fields; for (std::vector<const Mysql::Tools::Base::Mysql_query_runner::Row*> ::iterator field_it= fields_data.begin(); field_it != fields_data.end(); ++field_it) { fields.push_back(Field((**field_it)[0], (**field_it)[1])); } Mysql::Tools::Base::Mysql_query_runner::cleanup_result(&fields_data); /* For views create a dummy view so that dependent objects are resolved when actually dumping views. */ if (table_data.is_value_null(1)) { std::string fake_view_ddl = "CREATE VIEW " + this->get_quoted_object_full_name(db.get_name(), table_name) + " AS SELECT\n"; for (std::vector<Field>::iterator field_iterator= fields.begin(); field_iterator != fields.end(); ++field_iterator) { fake_view_ddl+= " 1 AS " + this->quote_name(field_iterator->get_name()); if (field_iterator + 1 != fields.end()) fake_view_ddl += ",\n"; } View* fake_view= new View(this->generate_new_object_id(), table_name, db.get_name(), fake_view_ddl); fake_view->add_dependency(m_current_database_start_dump_task); m_current_database_end_dump_task->add_dependency(fake_view); m_tables_definition_ready_dump_task->add_dependency(fake_view); this->process_dump_task(fake_view); continue; } uint64 rows= table_data.is_value_null(4) ? 0 : atoll(table_data[4].c_str()); // "Rows" bool isInnoDB= table_data[1] == "InnoDB"; // "Engine" Table* table= new Table(this->generate_new_object_id(), table_name, db.get_name(), this->get_create_statement( runner, db.get_name(), table_name, "TABLE") .value(), fields, table_data[1], rows, (uint64)(rows * (isInnoDB ? 1.5 : 1)), atoll(table_data[6].c_str()) // "Data_length" ); Table_definition_dump_task* ddl_task= new Table_definition_dump_task(table); Table_rows_dump_task* rows_task= new Table_rows_dump_task(table); Table_deferred_indexes_dump_task* indexes_task= new Table_deferred_indexes_dump_task(table); ddl_task->add_dependency(m_current_database_start_dump_task); rows_task->add_dependency(ddl_task); indexes_task->add_dependency(rows_task); m_current_database_end_dump_task->add_dependency(indexes_task); m_tables_definition_ready_dump_task->add_dependency(ddl_task); this->process_dump_task(ddl_task); this->process_dump_task(rows_task); this->enumerate_table_triggers(*table, rows_task); this->process_dump_task(indexes_task); } Mysql::Tools::Base::Mysql_query_runner::cleanup_result(&tables); delete runner; } void Mysql_crawler::enumerate_views(const Database& db) { Mysql::Tools::Base::Mysql_query_runner* runner= this->get_runner(); std::vector<const Mysql::Tools::Base::Mysql_query_runner::Row*> tables; runner->run_query_store("SHOW TABLES FROM " + this->quote_name(db.get_name()), &tables); for (std::vector<const Mysql::Tools::Base::Mysql_query_runner::Row*>::iterator it= tables.begin(); it != tables.end(); ++it) { const Mysql::Tools::Base::Mysql_query_runner::Row& table_data= **it; std::string table_name= table_data[0]; // "View Name" std::vector<const Mysql::Tools::Base::Mysql_query_runner::Row*> check_view; runner->run_query_store("SELECT COUNT(*) FROM " + this->get_quoted_object_full_name("INFORMATION_SCHEMA", "VIEWS") + " WHERE TABLE_NAME= '" + runner->escape_string(table_name) + "' AND TABLE_SCHEMA= '" + runner->escape_string(db.get_name()) + "'", &check_view); for (std::vector<const Mysql::Tools::Base::Mysql_query_runner::Row*>::iterator view_it= check_view.begin(); view_it != check_view.end(); ++view_it) { const Mysql::Tools::Base::Mysql_query_runner::Row& is_view= **view_it; if (is_view[0] == "1") { /* Check if view dependent objects exists */ if (runner->run_query(std::string("LOCK TABLES ") + this->get_quoted_object_full_name(db.get_name(), table_name) + " READ") != 0) { Mysql::Tools::Base::Mysql_query_runner::cleanup_result(&check_view); Mysql::Tools::Base::Mysql_query_runner::cleanup_result(&tables); delete runner; return; } else runner->run_query(std::string("UNLOCK TABLES")); View* view= new View(this->generate_new_object_id(), table_name, db.get_name(), this->get_create_statement(runner, db.get_name(), table_name, "TABLE").value() ); m_current_database_end_dump_task->add_dependency(view); view->add_dependency(m_tables_definition_ready_dump_task); this->process_dump_task(view); } } Mysql::Tools::Base::Mysql_query_runner::cleanup_result(&check_view); } Mysql::Tools::Base::Mysql_query_runner::cleanup_result(&tables); delete runner; } template<typename TObject> void Mysql_crawler::enumerate_functions(const Database& db, std::string type) { Mysql::Tools::Base::Mysql_query_runner* runner= this->get_runner(); std::vector<const Mysql::Tools::Base::Mysql_query_runner::Row*> functions; runner->run_query_store("SHOW " + type + " STATUS WHERE db = '" + runner->escape_string(db.get_name()) + '\'', &functions); for (std::vector<const Mysql::Tools::Base::Mysql_query_runner::Row*>::iterator it= functions.begin(); it != functions.end(); ++it) { const Mysql::Tools::Base::Mysql_query_runner::Row& function_row= **it; TObject* function= new TObject(this->generate_new_object_id(), function_row[1], db.get_name(), "DELIMITER //\n" + this->get_create_statement( runner, db.get_name(), function_row[1], type, 2).value() + "//\n" + "DELIMITER ;\n"); function->add_dependency(m_current_database_start_dump_task); m_current_database_end_dump_task->add_dependency(function); this->process_dump_task(function); } Mysql::Tools::Base::Mysql_query_runner::cleanup_result(&functions); delete runner; } void Mysql_crawler::enumerate_event_scheduler_events(const Database& db) { Mysql::Tools::Base::Mysql_query_runner* runner= this->get_runner(); // Workaround for "access denied" error fixed in 5.7.6. if (this->get_server_version() < 50706 && this->compare_no_case_latin_with_db_string( "performance_schema", db.get_name()) == 0) { return; } std::vector<const Mysql::Tools::Base::Mysql_query_runner::Row*> events; runner->run_query_store("SHOW EVENTS FROM " + this->get_quoted_object_full_name(&db), &events); for (std::vector<const Mysql::Tools::Base::Mysql_query_runner::Row*>::iterator it= events.begin(); it != events.end(); ++it) { const Mysql::Tools::Base::Mysql_query_runner::Row& event_row= **it; Event_scheduler_event* event= new Event_scheduler_event(this->generate_new_object_id(), event_row[1], db.get_name(), "DELIMITER //\n" + this->get_create_statement( runner, db.get_name(), event_row[1], "EVENT", 3).value() + "//\n" + "DELIMITER ;\n"); event->add_dependency(m_current_database_start_dump_task); m_current_database_end_dump_task->add_dependency(event); this->process_dump_task(event); } Mysql::Tools::Base::Mysql_query_runner::cleanup_result(&events); delete runner; } void Mysql_crawler::enumerate_users() { Mysql::Tools::Base::Mysql_query_runner* runner= this->get_runner(); std::vector<const Mysql::Tools::Base::Mysql_query_runner::Row*> users; runner->run_query_store( "SELECT CONCAT(QUOTE(user),'@',QUOTE(host)) FROM mysql.user", &users); for (std::vector<const Mysql::Tools::Base::Mysql_query_runner::Row*>::iterator it= users.begin(); it != users.end(); ++it) { const Mysql::Tools::Base::Mysql_query_runner::Row& user_row= **it; std::vector<const Mysql::Tools::Base::Mysql_query_runner::Row*> create_user; std::vector<const Mysql::Tools::Base::Mysql_query_runner::Row*> user_grants; if (runner->run_query_store( "SHOW CREATE USER " + user_row[0], &create_user)) return; if (runner->run_query_store( "SHOW GRANTS FOR " + user_row[0], &user_grants)) return; Abstract_dump_task* previous_grant= m_dump_start_task; std::vector<const Mysql::Tools::Base::Mysql_query_runner::Row*> ::iterator it1= create_user.begin(); const Mysql::Tools::Base::Mysql_query_runner::Row& create_row= **it1; std::string user= create_row[0]; for (std::vector<const Mysql::Tools::Base::Mysql_query_runner::Row*> ::iterator it2= user_grants.begin(); it2 != user_grants.end(); ++it2) { const Mysql::Tools::Base::Mysql_query_runner::Row& grant_row= **it2; user+= std::string(";\n" + grant_row[0]); } Privilege* grant= new Privilege( this->generate_new_object_id(), user_row[0], user); grant->add_dependency(previous_grant); grant->add_dependency(m_tables_definition_ready_dump_task); m_dump_end_task->add_dependency(grant); this->process_dump_task(grant); previous_grant= grant; Mysql::Tools::Base::Mysql_query_runner::cleanup_result(&create_user); Mysql::Tools::Base::Mysql_query_runner::cleanup_result(&user_grants); } Mysql::Tools::Base::Mysql_query_runner::cleanup_result(&users); delete runner; } void Mysql_crawler::enumerate_table_triggers( const Table& table, Abstract_dump_task* dependency) { // Triggers were supported since 5.0.9 if (this->get_server_version() < 50009) return; Mysql::Tools::Base::Mysql_query_runner* runner= this->get_runner(); std::vector<const Mysql::Tools::Base::Mysql_query_runner::Row*> triggers; runner->run_query_store("SHOW TRIGGERS FROM " + this->quote_name(table.get_schema()) + " LIKE '" + runner->escape_string(table.get_name()) + '\'', &triggers); for (std::vector<const Mysql::Tools::Base::Mysql_query_runner::Row*>::iterator it= triggers.begin(); it != triggers.end(); ++it) { const Mysql::Tools::Base::Mysql_query_runner::Row& trigger_row= **it; Trigger* trigger= new Trigger(this->generate_new_object_id(), trigger_row[0], table.get_schema(), "DELIMITER //\n" + this->get_version_specific_statement( this->get_create_statement( runner, table.get_schema(), trigger_row[0], "TRIGGER", 2).value(), "TRIGGER", "50017", "50003") + "\n//\n" + "DELIMITER ;\n", &table); trigger->add_dependency(dependency); m_current_database_end_dump_task->add_dependency(trigger); this->process_dump_task(trigger); } Mysql::Tools::Base::Mysql_query_runner::cleanup_result(&triggers); delete runner; } std::string Mysql_crawler::get_version_specific_statement( std::string create_string, const std::string& keyword, std::string main_version, std::string definer_version) { size_t keyword_pos= create_string.find(" " + keyword); size_t definer_pos= create_string.find(" DEFINER"); if (keyword_pos != std::string::npos && definer_pos != std::string::npos && definer_pos < keyword_pos) { create_string.insert(keyword_pos, "*/ /*!" + main_version); create_string.insert(definer_pos, "*/ /*!" + definer_version); } return "/*!" + main_version + ' ' + create_string + " */"; }