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;
}
//----------------------------------------------------------------------------------------------------------------------