1 /*
2   Copyright (c) 2015, 2021, Oracle and/or its affiliates.
3 
4   This program is free software; you can redistribute it and/or modify
5   it under the terms of the GNU General Public License, version 2.0,
6   as published by the Free Software Foundation.
7 
8   This program is also distributed with certain software (including
9   but not limited to OpenSSL) that is licensed under separate terms,
10   as designated in a particular file or component or in included license
11   documentation.  The authors of MySQL hereby grant you an additional
12   permission to link the program and your derivative works with the
13   separately licensed software that they have included with MySQL.
14 
15   This program is distributed in the hope that it will be useful,
16   but WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18   GNU General Public License, version 2.0, for more details.
19 
20   You should have received a copy of the GNU General Public License
21   along with this program; if not, write to the Free Software
22   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #include "abstract_mysql_chain_element_extension.h"
26 #include <boost/algorithm/string.hpp>
27 #include <boost/bind.hpp>
28 #include <sstream>
29 
30 using namespace Mysql::Tools::Dump;
31 
Abstract_mysql_chain_element_extension(I_connection_provider * connection_provider,Mysql::I_callable<bool,const Mysql::Tools::Base::Message_data &> * message_handler,const Mysql_chain_element_options * options)32 Abstract_mysql_chain_element_extension::Abstract_mysql_chain_element_extension(
33   I_connection_provider* connection_provider,
34   Mysql::I_callable<bool, const Mysql::Tools::Base::Message_data&>*
35     message_handler, const Mysql_chain_element_options* options)
36   : m_connection_provider(connection_provider),
37   m_message_handler(message_handler),
38   m_options(options),
39   m_charset(options->get_program()->get_current_charset() != NULL
40     ? options->get_program()->get_current_charset()
41     : get_charset_by_csname(
42       MYSQL_UNIVERSAL_CLIENT_CHARSET, MY_CS_PRIMARY, MYF(MY_WME)))
43 {}
44 
45 Mysql::Tools::Base::Mysql_query_runner*
get_runner() const46   Abstract_mysql_chain_element_extension::get_runner() const
47 {
48   return m_connection_provider->get_runner(m_message_handler);
49 }
50 
51 I_connection_provider*
get_connection_provider() const52   Abstract_mysql_chain_element_extension::get_connection_provider() const
53 {
54   return m_connection_provider;
55 }
56 
get_server_version()57 uint64 Abstract_mysql_chain_element_extension::get_server_version()
58 {
59   Mysql::Tools::Base::Mysql_query_runner* runner= this->get_runner();
60   ulong version= mysql_get_server_version(runner->get_low_level_connection());
61   delete runner;
62   return version;
63 }
64 
get_server_version_string()65 std::string Abstract_mysql_chain_element_extension::get_server_version_string()
66 {
67   uint64 version= this->get_server_version();
68   std::ostringstream result;
69   result << ((version / (100 * 100)) % 100) << "."
70     << ((version / (100)) % 100) << "."
71     << ((version / (1)) % 100);
72   return result.str();
73 }
74 
75 int
compare_no_case_latin_with_db_string(const std::string & latin_name,const std::string & db_name)76   Abstract_mysql_chain_element_extension::compare_no_case_latin_with_db_string(
77     const std::string& latin_name, const std::string& db_name)
78 {
79   return my_strcasecmp(&my_charset_latin1, latin_name.c_str(),
80     db_name.c_str());
81 }
82 
83 Mysql::Nullable<std::string>
get_create_statement(Mysql::Tools::Base::Mysql_query_runner * runner,const std::string & database_name,const std::string & object_name,const std::string & object_type,uint field_id)84   Abstract_mysql_chain_element_extension::get_create_statement(
85     Mysql::Tools::Base::Mysql_query_runner* runner,
86     const std::string& database_name, const std::string& object_name,
87     const std::string& object_type, uint field_id/*= 1*/)
88 {
89   std::vector<const Mysql::Tools::Base::Mysql_query_runner::Row*> result;
90 
91   runner->run_query_store("SHOW CREATE " + object_type + " "
92     + this->get_quoted_object_full_name(database_name, object_name),
93     &result);
94 
95   Mysql::Nullable<std::string> res;
96   if (result.size() > 0)
97   {
98     if (object_type == "FUNCTION"
99         || object_type == "PROCEDURE"
100         || object_type == "TRIGGER")
101       res= (*result[0])[2];
102     else if (object_type == "EVENT")
103       res= (*result[0])[3];
104     else
105       res= (*result[0])[1];
106     /*
107      TODO: SHOW CREATE will not include schema name except for views
108            and triggers. Once fix is done from server below hack will
109            be removed.
110     */
111     if (database_name.size() > 0)
112     {
113       std::string obj_name_without_quote= this->quote_name(database_name)
114            + "." + object_name;
115       std::string obj_name_with_quote= this->quote_name(database_name)
116            + "." + this->quote_name(object_name);
117       size_t pos1= res.value().find(obj_name_without_quote);
118       size_t pos2= res.value().find(obj_name_with_quote);
119 
120       // if object name does not have db name then include it
121       if (pos1 == std::string::npos && pos2 == std::string::npos)
122       {
123         size_t pos= res.value().find(object_type);
124         if (pos != std::string::npos)
125         {
126           pos= pos + object_type.size() + 1;
127           res= res.value().substr(0, pos) + this->quote_name(database_name)
128               + "." + res.value().substr(pos);
129         }
130       }
131     }
132   }
133   Mysql::Tools::Base::Mysql_query_runner::cleanup_result(&result);
134   return res;
135 }
136 
quote_name(const std::string & name)137 std::string Abstract_mysql_chain_element_extension::quote_name(
138   const std::string& name)
139 {
140   char buff[MAX_NAME_LEN * 2 + 3]= { 0 };
141   const char* name_str= name.c_str();
142   Mysql::Tools::Base::Mysql_query_runner* runner= this->get_runner();
143   buff[0]= '`';
144   int len= mysql_real_escape_string_quote(runner->get_low_level_connection(),
145               buff+1, name_str, (ulong)name.size(), '`');
146   buff[len+1]= '`';
147   delete runner;
148   return std::string(buff);
149 }
150 
151 std::string
get_quoted_object_full_name(const Abstract_data_object * object)152   Abstract_mysql_chain_element_extension::get_quoted_object_full_name(
153     const Abstract_data_object* object)
154 {
155   return this->get_quoted_object_full_name(
156     object->get_schema(), object->get_name());
157 }
158 
159 std::string
get_quoted_object_full_name(const std::string & database_name,const std::string & object_name)160   Abstract_mysql_chain_element_extension::get_quoted_object_full_name(
161     const std::string& database_name, const std::string& object_name)
162 {
163   if (database_name != "")
164     return this->quote_name(database_name) + "."
165     + this->quote_name(object_name);
166   return this->quote_name(object_name);
167 }
168 
169 const Mysql_chain_element_options*
get_mysql_chain_element_options() const170   Abstract_mysql_chain_element_extension::get_mysql_chain_element_options()
171   const
172 {
173   return m_options;
174 }
175 
get_charset() const176 CHARSET_INFO* Abstract_mysql_chain_element_extension::get_charset() const
177 {
178   return m_charset;
179 }
180