backend/wbpublic/grtdb/db_helpers.cpp (179 lines of code) (raw):

/* * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved. * * 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 designed to work 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 either included with * the program or referenced in the documentation. * 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 "db_helpers.h" #include "base/string_utilities.h" #include "grtpp_util.h" #include "base/log.h" using namespace base; //---------------------------------------------------------------------------------------------------------------------- std::string bec::get_host_identifier_for_connection(const db_mgmt_ConnectionRef &connection) { grt::DictRef params(connection->parameterValues()); std::string host_id; if (connection->driver().is_valid()) { std::string host_identifier = *connection->driver()->hostIdentifierTemplate(); for (grt::DictRef::const_iterator par = params.begin(); par != params.end(); ++par) { base::replaceStringInplace(host_identifier, "%" + par->first + "%", par->second.toString()); } return host_identifier; } else return connection->name(); } //---------------------------------------------------------------------------------------------------------------------- std::string bec::get_description_for_connection(const db_mgmt_ConnectionRef &connection) { std::string conn_type; std::string driver, server; grt::DictRef params(connection->parameterValues()); if (connection->driver().is_valid()) { driver = connection->driver()->name(); server = db_mgmt_RdbmsRef::cast_from(connection->driver()->owner())->caption(); } else return "Invalid Connection Description"; std::string user = params.get_string("userName"); if (g_str_has_suffix(driver.c_str(), "Socket")) { std::string path = base::trim(params.get_string("socket")); conn_type = base::strfmt("%s using local socket/pipe at \"%s\" with user %s", server.c_str(), path.empty() ? "default path" : path.c_str(), user.c_str()); } else if (g_str_has_suffix(driver.c_str(), "SSH")) { conn_type = base::strfmt("%s at %s:%i through SSH tunnel at %s@%s with user %s", server.c_str(), params.get_string("hostName").c_str(), (int)params.get_int("port"), params.get_string("sshUserName").c_str(), params.get_string("sshHost").c_str(), user.c_str()); } else { // TCP conn_type = base::strfmt("%s at %s:%i with user %s", server.c_str(), params.get_string("hostName").c_str(), (int)params.get_int("port"), user.c_str()); } return conn_type; } //---------------------------------------------------------------------------------------------------------------------- std::string bec::sanitize_server_version_number(const std::string &version) { int major, minor, release, patch; if (sscanf(version.c_str(), "%i.%i.%i-%i", &major, &minor, &release, &patch) == 4) { return base::strfmt("%i.%i.%i-%i", major, minor, release, patch); } else if (sscanf(version.c_str(), "%i.%i.%i", &major, &minor, &release) == 3) { return base::strfmt("%i.%i.%i", major, minor, release); } return version; } //---------------------------------------------------------------------------------------------------------------------- /** * Parses the given version string into its components and returns a GRT version class. * Unspecified components are set to -1 to allow for fuzzy comparisons. */ GrtVersionRef bec::parse_version(const std::string &target_version) { int major = 0, minor = -1, release = -1, build = -1; sscanf(target_version.c_str(), "%i.%i.%i.%i", &major, &minor, &release, &build); GrtVersionRef version(grt::Initialized); version->name("Version"); version->majorNumber(major); version->minorNumber(minor); version->releaseNumber(release); version->buildNumber(build); return version; } //---------------------------------------------------------------------------------------------------------------------- /** * Converts a grt version struct into a plain long usable by parsers. * Returns a default version number if the given version is invalid or has no major version. */ int bec::version_to_int(const GrtVersionRef &version) { if (!version.is_valid() || version->majorNumber() == -1) return 80000; size_t result = version->majorNumber() * 10000; if (version->minorNumber() > -1) result += version->minorNumber() * 100; if (version->releaseNumber() > -1) result += version->releaseNumber(); return (int)result; } //---------------------------------------------------------------------------------------------------------------------- /** * Converts a grt version struct into one of the version enums. */ MySQLVersion bec::versionToEnum(const GrtVersionRef &version) { if (!version.is_valid() || version->majorNumber() == -1) return MySQLVersion::Unknown; if (version->majorNumber() >= 8) return MySQLVersion::MySQL80; if (version->majorNumber() != 5) return MySQLVersion::Unknown; switch (version->minorNumber()) { case 6: return MySQLVersion::MySQL56; case 7: return MySQLVersion::MySQL57; default: return MySQLVersion::Unknown; } } //---------------------------------------------------------------------------------------------------------------------- /** * Converts the int form of a server version to a grt version ref. * The build member in the returned version is always -1. */ GrtVersionRef bec::intToVersion(int version) { int major = version / 10000, minor = (version / 100) % 100, release = version % 100, build = -1; GrtVersionRef version_(grt::Initialized); version_->name("Version"); version_->majorNumber(major); version_->minorNumber(minor); version_->releaseNumber(release); version_->buildNumber(build); return version_; } //---------------------------------------------------------------------------------------------------------------------- /** * Compares the given version numbers to see if a is equal to b. * In order to support wildcards, missing values are interpreted as matching, e.g. 5 is equal to 5.1 * and 5.1 is equal to 5.1.1. * * Do not use for comparing supported MySQL server versions. */ bool bec::version_equal(GrtVersionRef a, GrtVersionRef b) { // Major version number is always there. if (a->majorNumber() != b->majorNumber()) return false; if (a->minorNumber() == -1 || b->minorNumber() == -1) return true; if (a->minorNumber() != b->minorNumber()) return false; if (a->releaseNumber() == -1 || b->releaseNumber() == -1) return true; if (a->releaseNumber() != b->releaseNumber()) return false; if (a->buildNumber() == -1 || b->buildNumber() == -1) return true; if (a->buildNumber() != b->buildNumber()) return false; return true; } //---------------------------------------------------------------------------------------------------------------------- /** * This test is similar to the one above (except that it tests for greater-than relations). * For this however we have to treat unset values differently to handle cases like * 5 > 5.1 (false) or 5.1 > 5 (true) correctly. * * Do not use for comparing supported MySQL server versions. */ bool bec::version_greater(GrtVersionRef a, GrtVersionRef b) { if (a->majorNumber() > b->majorNumber()) // Major number should always be set. return true; if (a->majorNumber() == b->majorNumber()) { if (a->minorNumber() == -1) // An unset value can never be larger than anything else. return false; if (b->minorNumber() == -1) // An unset value is always smaller than any other set value. return true; if (a->minorNumber() > b->minorNumber()) return true; // Same approach for release + build numbers. if (a->minorNumber() == b->minorNumber()) { if (a->releaseNumber() == -1) return false; if (b->releaseNumber() == -1) return true; if (a->releaseNumber() > b->releaseNumber()) return true; if (a->releaseNumber() == b->releaseNumber()) { if (a->buildNumber() == -1) return false; if (b->buildNumber() == -1) return true; if (a->buildNumber() > b->buildNumber()) return true; } return false; } return false; } return false; } //---------------------------------------------------------------------------------------------------------------------- /** Checks if the given server version numbers is in the set of supported MySQL servers */ bool bec::is_supported_mysql_version(int mysql_major, int mysql_minor, int mysql_release) { return ((mysql_major == 5 && (mysql_minor == 6 || mysql_minor == 7)) || (mysql_major == 8 && mysql_minor == 0)); } //---------------------------------------------------------------------------------------------------------------------- bool bec::is_supported_mysql_version(const std::string &mysql_version) { int my_major = 0, my_minor = -1, my_release = -1, my_build = -1; sscanf(mysql_version.c_str(), "%i.%i.%i.%i", &my_major, &my_minor, &my_release, &my_build); return is_supported_mysql_version(my_major, my_minor, my_release); } //---------------------------------------------------------------------------------------------------------------------- /** Checks whether the version number supplied is in the known set of versions larger than it. Use for server version checks for features. */ bool bec::is_supported_mysql_version_at_least(int mysql_major, int mysql_minor, int mysql_release, int major, int minor, int release) { // if the version required is older (<) than 5.6, then any server that matches is fine // if the version required is newer (>=) than 5.6, then we can only guarantee that known servers versions have the // feature assert(mysql_major < 100 && mysql_minor < 100 && mysql_release < 1000); assert(major < 100 && minor < 100 && release < 1000); // assemble MMNNRRR unsigned int required = major * 100000 + minor * 1000 + (release < 0 ? 0 : release); // if the available release number is negative, that's meant to signify "any release number", so we make it the max // value possible unsigned int available = mysql_major * 100000 + mysql_minor * 1000 + (mysql_release < 0 ? 999 : mysql_release); if (major < 5 || (major == 5 && minor < 6) || (major == 8 && minor == 0)) { return (required <= available); } else if (is_supported_mysql_version(mysql_major, mysql_minor, mysql_release)) { return (required <= available); } return false; } //---------------------------------------------------------------------------------------------------------------------- bool bec::is_supported_mysql_version_at_least(const std::string &mysql_version, int major, int minor, int release) { int my_major = 0, my_minor = -1, my_release = -1, my_build = -1; sscanf(mysql_version.c_str(), "%i.%i.%i.%i", &my_major, &my_minor, &my_release, &my_build); return is_supported_mysql_version_at_least(my_major, my_minor, my_release, major, minor, release); } //---------------------------------------------------------------------------------------------------------------------- bool bec::is_supported_mysql_version_at_least(const GrtVersionRef &mysql_version, int major, int minor, int release) { if (mysql_version.is_valid()) return is_supported_mysql_version_at_least((int)mysql_version->majorNumber(), (int)mysql_version->minorNumber(), (int)mysql_version->releaseNumber(), major, minor, release); return false; } //----------------------------------------------------------------------------------------------------------------------