unittest/modules/instance_cache_t.cc (3,495 lines of code) (raw):

/* * Copyright (c) 2020, 2024, 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 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 "modules/util/dump/instance_cache.h" #include <array> #include <set> #include <string> #include "unittest/gtest_clean.h" #include "unittest/test_utils.h" #include "mysqlshdk/libs/utils/utils_string.h" #include "modules/util/dump/indexes.h" namespace mysqlsh { namespace dump { namespace tests { namespace { using common::Filtering_options; using mysqlshdk::utils::Version; void verify(const Instance_cache &cache, const std::string &name, const Instance_cache::Schema &expected) { const auto it = cache.schemas.find(name); ASSERT_TRUE(cache.schemas.end() != it) << "cache does not contain schema `" << name << "`"; const auto keys = [](const auto &m) { std::set<std::string> s; for (const auto &e : m) { s.emplace(e.first); } return s; }; EXPECT_EQ(keys(expected.tables), keys(it->second.tables)); EXPECT_EQ(keys(expected.views), keys(it->second.views)); } template <typename C> ::testing::AssertionResult contains(const C &map, const std::string &name) { std::set<std::string> objects; for (const auto &e : map) { objects.emplace(e.first); } if (map.end() != map.find(name)) { return ::testing::AssertionSuccess() << "Object found: " << name << ", contents: " << shcore::str_join(objects, ", "); } else { return ::testing::AssertionFailure() << "Object not found: " << name << ", contents: " << shcore::str_join(objects, ", "); } } } // namespace class Instance_cache_test : public Shell_core_test_wrapper { protected: void SetUp() override { Shell_core_test_wrapper::SetUp(); m_session = connect_session(); cleanup(); } void TearDown() override { cleanup(); m_session->close(); Shell_core_test_wrapper::TearDown(); } static std::shared_ptr<mysqlshdk::db::ISession> connect_session() { auto session = mysqlshdk::db::mysql::Session::create(); session->connect(shcore::get_connection_options(_mysql_uri)); return session; } std::shared_ptr<mysqlshdk::db::ISession> m_session; private: void cleanup() const { m_session->execute("DROP USER IF EXISTS first;"); m_session->execute("DROP USER IF EXISTS second;"); m_session->execute("DROP USER IF EXISTS third;"); m_session->execute("DROP SCHEMA IF EXISTS first;"); m_session->execute("DROP SCHEMA IF EXISTS second;"); m_session->execute("DROP SCHEMA IF EXISTS third;"); m_session->execute("DROP SCHEMA IF EXISTS First;"); m_session->execute("DROP SCHEMA IF EXISTS Second;"); } }; TEST_F(Instance_cache_test, filter_schemas_and_tables) { { // setup m_session->execute("CREATE SCHEMA first;"); m_session->execute("CREATE TABLE first.one (id INT);"); m_session->execute("CREATE TABLE first.two (id INT);"); m_session->execute("CREATE VIEW first.three AS SELECT * FROM first.one;"); m_session->execute("CREATE SCHEMA second;"); m_session->execute("CREATE TABLE second.one (id INT);"); m_session->execute("CREATE TABLE second.two (id INT);"); m_session->execute("CREATE VIEW second.three AS SELECT * FROM second.one;"); m_session->execute("CREATE SCHEMA third;"); m_session->execute("CREATE TABLE third.one (id INT);"); m_session->execute("CREATE TABLE third.two (id INT);"); m_session->execute("CREATE VIEW third.three AS SELECT * FROM third.one;"); } { SCOPED_TRACE("all filters are empty"); Filtering_options filters; const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}, {"two", {}}}; first.views = {{"three", {}}}; verify(cache, "first", first); Instance_cache::Schema second; second.tables = {{"one", {}}, {"two", {}}}; second.views = {{"three", {}}}; verify(cache, "second", second); Instance_cache::Schema third; third.tables = {{"one", {}}, {"two", {}}}; third.views = {{"three", {}}}; verify(cache, "third", third); } { SCOPED_TRACE("exclude table from non-existing schema"); Filtering_options filters; filters.tables().exclude("fourth", "four"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}, {"two", {}}}; first.views = {{"three", {}}}; verify(cache, "first", first); Instance_cache::Schema second; second.tables = {{"one", {}}, {"two", {}}}; second.views = {{"three", {}}}; verify(cache, "second", second); Instance_cache::Schema third; third.tables = {{"one", {}}, {"two", {}}}; third.views = {{"three", {}}}; verify(cache, "third", third); } { SCOPED_TRACE("exclude non-existing table"); Filtering_options filters; filters.tables().exclude("third", "four"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}, {"two", {}}}; first.views = {{"three", {}}}; verify(cache, "first", first); Instance_cache::Schema second; second.tables = {{"one", {}}, {"two", {}}}; second.views = {{"three", {}}}; verify(cache, "second", second); Instance_cache::Schema third; third.tables = {{"one", {}}, {"two", {}}}; third.views = {{"three", {}}}; verify(cache, "third", third); } { SCOPED_TRACE("exclude existing table"); Filtering_options filters; filters.tables().exclude("third", "two"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}, {"two", {}}}; first.views = {{"three", {}}}; verify(cache, "first", first); Instance_cache::Schema second; second.tables = {{"one", {}}, {"two", {}}}; second.views = {{"three", {}}}; verify(cache, "second", second); Instance_cache::Schema third; third.tables = {{"one", {}}}; third.views = {{"three", {}}}; verify(cache, "third", third); } { SCOPED_TRACE( "exclude existing, non-existing table and a table in non-existing " "schema"); Filtering_options filters; filters.tables().exclude("third", std::array{"two", "four"}); filters.tables().exclude("fourth", "four"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}, {"two", {}}}; first.views = {{"three", {}}}; verify(cache, "first", first); Instance_cache::Schema second; second.tables = {{"one", {}}, {"two", {}}}; second.views = {{"three", {}}}; verify(cache, "second", second); Instance_cache::Schema third; third.tables = {{"one", {}}}; third.views = {{"three", {}}}; verify(cache, "third", third); } { SCOPED_TRACE("exclude existing tables/views from the same schema"); Filtering_options filters; filters.tables().exclude("third", std::array{"two", "three"}); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}, {"two", {}}}; first.views = {{"three", {}}}; verify(cache, "first", first); Instance_cache::Schema second; second.tables = {{"one", {}}, {"two", {}}}; second.views = {{"three", {}}}; verify(cache, "second", second); Instance_cache::Schema third; third.tables = {{"one", {}}}; verify(cache, "third", third); } { SCOPED_TRACE("exclude all tables/views from the same schema"); Filtering_options filters; filters.tables().exclude("third", std::array{"one", "two", "three"}); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}, {"two", {}}}; first.views = {{"three", {}}}; verify(cache, "first", first); Instance_cache::Schema second; second.tables = {{"one", {}}, {"two", {}}}; second.views = {{"three", {}}}; verify(cache, "second", second); Instance_cache::Schema third; verify(cache, "third", third); } { SCOPED_TRACE("exclude existing tables/views from different schemas"); Filtering_options filters; filters.tables().exclude("first", "one"); filters.tables().exclude("second", "two"); filters.tables().exclude("third", "three"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"two", {}}}; first.views = {{"three", {}}}; verify(cache, "first", first); Instance_cache::Schema second; second.tables = {{"one", {}}}; second.views = {{"three", {}}}; verify(cache, "second", second); Instance_cache::Schema third; third.tables = {{"one", {}}, {"two", {}}}; verify(cache, "third", third); } { SCOPED_TRACE("include table from non-existing schema"); Filtering_options filters; filters.tables().include("fourth", "four"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; verify(cache, "first", first); Instance_cache::Schema second; verify(cache, "second", second); Instance_cache::Schema third; verify(cache, "third", third); } { SCOPED_TRACE("include non-existing table"); Filtering_options filters; filters.tables().include("third", "four"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; verify(cache, "first", first); Instance_cache::Schema second; verify(cache, "second", second); Instance_cache::Schema third; verify(cache, "third", third); } { SCOPED_TRACE("include existing table"); Filtering_options filters; filters.tables().include("third", "two"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema third; third.tables = {{"two", {}}}; verify(cache, "third", third); } { SCOPED_TRACE("include existing and non-existing tables"); Filtering_options filters; filters.tables().include("third", std::array{"two", "four"}); filters.tables().include("fourth", "four"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema third; third.tables = {{"two", {}}}; verify(cache, "third", third); } { SCOPED_TRACE("include existing table and view from the same schema"); Filtering_options filters; filters.tables().include("third", std::array{"two", "three"}); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema third; third.tables = {{"two", {}}}; third.views = {{"three", {}}}; verify(cache, "third", third); } { SCOPED_TRACE("include existing tables/views from different schemas"); Filtering_options filters; filters.tables().include("first", "one"); filters.tables().include("second", "two"); filters.tables().include("third", "three"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}}; verify(cache, "first", first); Instance_cache::Schema second; second.tables = {{"two", {}}}; verify(cache, "second", second); Instance_cache::Schema third; third.views = {{"three", {}}}; verify(cache, "third", third); } { SCOPED_TRACE("include and exclude the same existing table"); Filtering_options filters; filters.tables().include("third", "two"); filters.tables().exclude("third", "two"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; verify(cache, "first", first); Instance_cache::Schema second; verify(cache, "second", second); Instance_cache::Schema third; verify(cache, "third", third); } { SCOPED_TRACE("include and exclude the same existing table + some more"); Filtering_options filters; filters.tables().include("third", "two"); filters.tables().exclude("second", "two"); filters.tables().exclude("third", "two"); filters.tables().exclude("fourth", "four"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; verify(cache, "first", first); Instance_cache::Schema second; verify(cache, "second", second); Instance_cache::Schema third; verify(cache, "third", third); } { SCOPED_TRACE( "include and exclude existing tables/views from different schemas"); Filtering_options filters; filters.tables().include("first", "one"); filters.tables().include("second", "two"); filters.tables().include("third", "three"); filters.tables().exclude("first", "three"); filters.tables().exclude("second", "two"); filters.tables().exclude("third", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}}; verify(cache, "first", first); Instance_cache::Schema third; third.views = {{"three", {}}}; verify(cache, "third", third); } { SCOPED_TRACE("exclude non-existing schema"); Filtering_options filters; filters.schemas().exclude("fourth"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}, {"two", {}}}; first.views = {{"three", {}}}; verify(cache, "first", first); Instance_cache::Schema second; second.tables = {{"one", {}}, {"two", {}}}; second.views = {{"three", {}}}; verify(cache, "second", second); Instance_cache::Schema third; third.tables = {{"one", {}}, {"two", {}}}; third.views = {{"three", {}}}; verify(cache, "third", third); } { SCOPED_TRACE("exclude existing schema"); Filtering_options filters; filters.schemas().exclude("third"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}, {"two", {}}}; first.views = {{"three", {}}}; verify(cache, "first", first); Instance_cache::Schema second; second.tables = {{"one", {}}, {"two", {}}}; second.views = {{"three", {}}}; verify(cache, "second", second); EXPECT_FALSE(contains(cache.schemas, "third")); } { SCOPED_TRACE("exclude existing and non-existing schemas"); Filtering_options filters; filters.schemas().exclude(std::array{"third", "fourth"}); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}, {"two", {}}}; first.views = {{"three", {}}}; verify(cache, "first", first); Instance_cache::Schema second; second.tables = {{"one", {}}, {"two", {}}}; second.views = {{"three", {}}}; verify(cache, "second", second); EXPECT_FALSE(contains(cache.schemas, "third")); } { SCOPED_TRACE("exclude multiple existing schemas"); Filtering_options filters; filters.schemas().exclude(std::array{"second", "third"}); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}, {"two", {}}}; first.views = {{"three", {}}}; verify(cache, "first", first); EXPECT_FALSE(contains(cache.schemas, "second")); EXPECT_FALSE(contains(cache.schemas, "third")); } { SCOPED_TRACE( "exclude non-existing schema and a table in another non-existing " "schema"); Filtering_options filters; filters.schemas().exclude("fourth"); filters.tables().exclude("fifth", "five"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}, {"two", {}}}; first.views = {{"three", {}}}; verify(cache, "first", first); Instance_cache::Schema second; second.tables = {{"one", {}}, {"two", {}}}; second.views = {{"three", {}}}; verify(cache, "second", second); Instance_cache::Schema third; third.tables = {{"one", {}}, {"two", {}}}; third.views = {{"three", {}}}; verify(cache, "third", third); } { SCOPED_TRACE("exclude non-existing schema and a non-existing table"); Filtering_options filters; filters.schemas().exclude("fourth"); filters.tables().exclude("third", "four"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}, {"two", {}}}; first.views = {{"three", {}}}; verify(cache, "first", first); Instance_cache::Schema second; second.tables = {{"one", {}}, {"two", {}}}; second.views = {{"three", {}}}; verify(cache, "second", second); Instance_cache::Schema third; third.tables = {{"one", {}}, {"two", {}}}; third.views = {{"three", {}}}; verify(cache, "third", third); } { SCOPED_TRACE("exclude non-existing schema and an existing table"); Filtering_options filters; filters.schemas().exclude("fourth"); filters.tables().exclude("third", "three"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}, {"two", {}}}; first.views = {{"three", {}}}; verify(cache, "first", first); Instance_cache::Schema second; second.tables = {{"one", {}}, {"two", {}}}; second.views = {{"three", {}}}; verify(cache, "second", second); Instance_cache::Schema third; third.tables = {{"one", {}}, {"two", {}}}; verify(cache, "third", third); } { SCOPED_TRACE( "exclude existing schema and an existing table in the same schema"); Filtering_options filters; filters.schemas().exclude("third"); filters.tables().exclude("third", "three"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}, {"two", {}}}; first.views = {{"three", {}}}; verify(cache, "first", first); Instance_cache::Schema second; second.tables = {{"one", {}}, {"two", {}}}; second.views = {{"three", {}}}; verify(cache, "second", second); EXPECT_FALSE(contains(cache.schemas, "third")); } { SCOPED_TRACE( "exclude existing schema and an existing table in another schema"); Filtering_options filters; filters.schemas().exclude("third"); filters.tables().exclude("second", "two"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}, {"two", {}}}; first.views = {{"three", {}}}; verify(cache, "first", first); Instance_cache::Schema second; second.tables = {{"one", {}}}; second.views = {{"three", {}}}; verify(cache, "second", second); EXPECT_FALSE(contains(cache.schemas, "third")); } { SCOPED_TRACE("exclude non-existing schema, include existing table"); Filtering_options filters; filters.schemas().exclude("fourth"); filters.tables().include("second", "two"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema second; second.tables = {{"two", {}}}; verify(cache, "second", second); } { SCOPED_TRACE( "exclude existing schema, include existing table in another schema"); Filtering_options filters; filters.schemas().exclude("third"); filters.tables().include("second", "two"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema second; second.tables = {{"two", {}}}; verify(cache, "second", second); } { SCOPED_TRACE( "exclude existing schema, include existing table in the same schema"); Filtering_options filters; filters.schemas().exclude("second"); filters.tables().include("second", "two"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; verify(cache, "first", first); EXPECT_FALSE(contains(cache.schemas, "second")); Instance_cache::Schema third; verify(cache, "third", third); } { SCOPED_TRACE( "exclude an existing schema, an existing table, include tables"); Filtering_options filters; filters.schemas().exclude("second"); filters.tables().include("second", "two"); filters.tables().include("third", "three"); filters.tables().exclude("third", "three"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; verify(cache, "first", first); EXPECT_FALSE(contains(cache.schemas, "second")); Instance_cache::Schema third; verify(cache, "third", third); } { SCOPED_TRACE( "exclude an existing schema, an existing table, include more tables"); Filtering_options filters; filters.schemas().exclude("second"); filters.tables().include("first", "one"); filters.tables().include("second", "two"); filters.tables().include("third", "three"); filters.tables().exclude("third", "three"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}}; verify(cache, "first", first); } { SCOPED_TRACE("include non-existing schema -> empty result set"); Filtering_options filters; filters.schemas().include("fourth"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_TRUE(cache.schemas.empty()); } { SCOPED_TRACE("include existing schema"); Filtering_options filters; filters.schemas().include("third"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema third; third.tables = {{"one", {}}, {"two", {}}}; third.views = {{"three", {}}}; verify(cache, "third", third); } { SCOPED_TRACE("include existing and non-existing schemas"); Filtering_options filters; filters.schemas().include(std::array{"third", "fourth"}); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema third; third.tables = {{"one", {}}, {"two", {}}}; third.views = {{"three", {}}}; verify(cache, "third", third); } { SCOPED_TRACE("include multiple existing schemas"); Filtering_options filters; filters.schemas().include(std::array{"first", "third"}); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(2, cache.schemas.size()); Instance_cache::Schema first; first.tables = {{"one", {}}, {"two", {}}}; first.views = {{"three", {}}}; verify(cache, "first", first); Instance_cache::Schema third; third.tables = {{"one", {}}, {"two", {}}}; third.views = {{"three", {}}}; verify(cache, "third", third); } { SCOPED_TRACE("include existing schema, exclude non-existing one"); Filtering_options filters; filters.schemas().include("third"); filters.schemas().exclude("fourth"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema third; third.tables = {{"one", {}}, {"two", {}}}; third.views = {{"three", {}}}; verify(cache, "third", third); } { SCOPED_TRACE("include and exclude the same schema -> empty result set"); Filtering_options filters; filters.schemas().include("third"); filters.schemas().exclude("third"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_TRUE(cache.schemas.empty()); } { SCOPED_TRACE( "include and exclude the same schema + some more -> empty result set"); Filtering_options filters; filters.schemas().include("third"); filters.schemas().exclude(std::array{"first", "third"}); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_TRUE(cache.schemas.empty()); } { SCOPED_TRACE("exclude and include the same schema + some more"); Filtering_options filters; filters.schemas().include(std::array{"first", "third"}); filters.schemas().exclude("third"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema first; first.tables = {{"one", {}}, {"two", {}}}; first.views = {{"three", {}}}; verify(cache, "first", first); } { SCOPED_TRACE( "include non-existing schema, include existing table -> empty result " "set"); Filtering_options filters; filters.schemas().include("fourth"); filters.tables().include("first", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_TRUE(cache.schemas.empty()); } { SCOPED_TRACE( "include existing schema, include existing table in another schema"); Filtering_options filters; filters.schemas().include("third"); filters.tables().include("first", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema third; verify(cache, "third", third); } { SCOPED_TRACE( "include existing schema, include existing table in the same schema"); Filtering_options filters; filters.schemas().include("first"); filters.tables().include("first", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema first; first.tables = {{"one", {}}}; verify(cache, "first", first); } { SCOPED_TRACE( "include existing schemas, include existing table in one of the " "schemas"); Filtering_options filters; filters.schemas().include(std::array{"first", "second"}); filters.tables().include("first", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(2, cache.schemas.size()); Instance_cache::Schema first; first.tables = {{"one", {}}}; verify(cache, "first", first); Instance_cache::Schema second; verify(cache, "second", second); } { SCOPED_TRACE( "include existing schemas, include existing table in one of the " "schemas, exclude the other schema"); Filtering_options filters; filters.schemas().include(std::array{"first", "second"}); filters.schemas().exclude("second"); filters.tables().include("first", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema first; first.tables = {{"one", {}}}; verify(cache, "first", first); } { SCOPED_TRACE( "include existing schemas, include existing table in one of the " "schemas, exclude the same schema"); Filtering_options filters; filters.schemas().include(std::array{"first", "second"}); filters.schemas().exclude("first"); filters.tables().include("first", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema second; verify(cache, "second", second); } { SCOPED_TRACE( "include existing schema, exclude table in non-existing schema"); Filtering_options filters; filters.schemas().include("third"); filters.tables().exclude("fourth", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema third; third.tables = {{"one", {}}, {"two", {}}}; third.views = {{"three", {}}}; verify(cache, "third", third); } { SCOPED_TRACE( "include existing schema, exclude non-existing table in another " "schema"); Filtering_options filters; filters.schemas().include("third"); filters.tables().exclude("second", "four"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema third; third.tables = {{"one", {}}, {"two", {}}}; third.views = {{"three", {}}}; verify(cache, "third", third); } { SCOPED_TRACE( "include existing schema, exclude non-existing table in the same " "schema"); Filtering_options filters; filters.schemas().include("third"); filters.tables().exclude("third", "four"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema third; third.tables = {{"one", {}}, {"two", {}}}; third.views = {{"three", {}}}; verify(cache, "third", third); } { SCOPED_TRACE("include existing schema, exclude table in the same schema"); Filtering_options filters; filters.schemas().include("third"); filters.tables().exclude("third", "two"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema third; third.tables = {{"one", {}}}; third.views = {{"three", {}}}; verify(cache, "third", third); } { SCOPED_TRACE( "include existing schema, exclude table/view in the same schema"); Filtering_options filters; filters.schemas().include("third"); filters.tables().exclude("third", std::array{"two", "three"}); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema third; third.tables = {{"one", {}}}; verify(cache, "third", third); } { SCOPED_TRACE("a little bit of everything"); Filtering_options filters; filters.schemas().include(std::array{"first", "third"}); filters.schemas().exclude("third"); filters.tables().include("first", std::array{"two", "three"}); filters.tables().include("third", "one"); filters.tables().exclude("first", "two"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema first; first.views = {{"three", {}}}; verify(cache, "first", first); } } TEST_F(Instance_cache_test, schema_collation) { { // setup m_session->execute("CREATE SCHEMA first COLLATE utf8mb4_polish_ci;"); m_session->execute("CREATE SCHEMA second COLLATE utf8mb4_bin;"); m_session->execute("CREATE SCHEMA third COLLATE utf8mb4_unicode_ci;"); } { SCOPED_TRACE("test collations"); Filtering_options filters; const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ("utf8mb4_polish_ci", cache.schemas.at("first").collation); EXPECT_EQ("utf8mb4_bin", cache.schemas.at("second").collation); EXPECT_EQ("utf8mb4_unicode_ci", cache.schemas.at("third").collation); } } TEST_F(Instance_cache_test, table_metadata) { { // setup m_session->execute("CREATE SCHEMA first;"); m_session->execute( "CREATE TABLE first.one (id INT) " "ENGINE = InnoDB " "PARTITION BY KEY (id)" ";"); m_session->execute( "CREATE TABLE first.two (id INT) " "ENGINE = MyISAM " "COMMENT = 'qwerty\\'asdfg'" ";"); m_session->execute("CREATE SCHEMA second;"); m_session->execute( "CREATE TABLE second.three (id INT) " "ENGINE = BLACKHOLE " "COMMENT = 'important table'" ";"); } { SCOPED_TRACE("test table metadata"); Filtering_options filters; const auto cache = Instance_cache_builder(m_session, filters).build(); { const auto &one = cache.schemas.at("first").tables.at("one"); EXPECT_EQ("InnoDB", one.engine); EXPECT_EQ("", one.comment); EXPECT_EQ("partitioned", one.create_options); } { const auto &two = cache.schemas.at("first").tables.at("two"); EXPECT_EQ("MyISAM", two.engine); EXPECT_EQ("qwerty'asdfg", two.comment); EXPECT_EQ("", two.create_options); } { const auto &three = cache.schemas.at("second").tables.at("three"); EXPECT_EQ("BLACKHOLE", three.engine); EXPECT_EQ("important table", three.comment); EXPECT_EQ("", three.create_options); } } } TEST_F(Instance_cache_test, view_metadata) { { // setup m_session->execute("CREATE SCHEMA first;"); m_session->execute("CREATE TABLE first.one (id INT);"); m_session->execute("CREATE SCHEMA second;"); m_session->execute("SET @@session.character_set_client = 'latin1';"); m_session->execute( "SET @@session.collation_connection = 'latin1_spanish_ci';"); m_session->execute("CREATE VIEW second.one AS SELECT * FROM first.one;"); m_session->execute("SET @@session.character_set_client = 'utf8mb4';"); m_session->execute( "SET @@session.collation_connection = 'utf8mb4_polish_ci';"); m_session->execute("CREATE VIEW second.two AS SELECT * FROM first.one;"); m_session->execute("CREATE SCHEMA third"); m_session->execute("SET @@session.character_set_client = 'binary';"); m_session->execute("SET @@session.collation_connection = 'binary';"); m_session->execute("CREATE VIEW third.three AS SELECT * FROM first.one;"); } { SCOPED_TRACE("test view metadata"); Filtering_options filters; const auto cache = Instance_cache_builder(m_session, filters).metadata({}).build(); { const auto &one = cache.schemas.at("second").views.at("one"); EXPECT_EQ("latin1", one.character_set_client); EXPECT_EQ("latin1_spanish_ci", one.collation_connection); ASSERT_EQ(1, one.all_columns.size()); EXPECT_EQ("id", one.all_columns[0].name); EXPECT_EQ("`id`", one.all_columns[0].quoted_name); } { const auto &two = cache.schemas.at("second").views.at("two"); EXPECT_EQ("utf8mb4", two.character_set_client); EXPECT_EQ("utf8mb4_polish_ci", two.collation_connection); } { const auto &three = cache.schemas.at("third").views.at("three"); EXPECT_EQ("binary", three.character_set_client); EXPECT_EQ("binary", three.collation_connection); } } } TEST_F(Instance_cache_test, table_columns) { { // setup m_session->execute("CREATE SCHEMA first;"); m_session->execute( "CREATE TABLE first.one (" "c0 INT NOT NULL, " "gen INT GENERATED ALWAYS AS (c0 + 1) VIRTUAL, " "c1 CHAR(32) " ");"); m_session->execute( "CREATE TABLE first.two (" "c0 TINYINT, " "c1 TINYINT UNSIGNED, " "c2 SMALLINT, " "c3 SMALLINT UNSIGNED, " "c4 MEDIUMINT, " "c5 MEDIUMINT UNSIGNED, " "c6 INT, " "c7 INT UNSIGNED, " "c8 INTEGER, " "c9 INTEGER UNSIGNED, " "c10 BIGINT, " "c11 BIGINT UNSIGNED, " "c12 DECIMAL(2,1), " "c13 DECIMAL(2,1) UNSIGNED, " "c14 NUMERIC(64,30), " "c15 NUMERIC(64,30) UNSIGNED, " "c16 REAL, " "c17 REAL UNSIGNED, " "c18 FLOAT, " "c19 FLOAT UNSIGNED, " "c20 DOUBLE, " "c21 DOUBLE UNSIGNED, " "c22 DATE, " "c23 TIME, " // explicitly set to NULL to avoid problems with // explicit_defaults_for_timestamp "c24 TIMESTAMP NULL, " "c25 DATETIME, " "c26 YEAR, " "c27 TINYBLOB, " "c28 BLOB, " "c29 MEDIUMBLOB, " "c30 LONGBLOB, " "c31 TINYTEXT, " "c32 TEXT, " "c33 MEDIUMTEXT, " "c34 LONGTEXT, " "c35 TINYTEXT BINARY, " "c36 TEXT BINARY, " "c37 MEDIUMTEXT BINARY, " "c38 LONGTEXT BINARY, " "c39 CHAR(32), " "c40 VARCHAR(32), " "c41 BINARY(32), " "c42 VARBINARY(32), " "c43 BIT(64), " "c44 ENUM('v1','v2','v3'), " "c45 SET('v1','v2','v3'), " "c46 JSON, " "c47 GEOMETRY, " "c48 POINT, " "c49 LINESTRING, " "c50 POLYGON, " "c51 MULTIPOINT, " "c52 MULTILINESTRING, " "c53 MULTIPOLYGON, " "c54 GEOMETRYCOLLECTION" ");"); m_session->execute("CREATE SCHEMA second;"); m_session->execute( "CREATE TABLE second.three (" "c0 INT, " "gen INT GENERATED ALWAYS AS (c0 + 2) STORED, " "c1 TINYBLOB NULL" ");"); if (_target_server_version >= Version(8, 0, 13)) { // EXTRA == DEFAULT_GENERATED m_session->execute( "CREATE TABLE second.four (" "c0 FLOAT DEFAULT (RAND() * RAND())" ");"); } if (_target_server_version >= Version(8, 0, 23)) { // INVISIBLE + GENERATED m_session->execute( "CREATE TABLE second.five (" "c0 INT NOT NULL INVISIBLE, " "gen INT GENERATED ALWAYS AS (c0 + 1) VIRTUAL INVISIBLE, " "c1 CHAR(32)" ");"); m_session->execute( "CREATE TABLE second.six (" "c0 INT INVISIBLE, " "gen INT GENERATED ALWAYS AS (c0 + 2) STORED INVISIBLE, " "c1 CHAR(32)" ");"); } } { using mysqlshdk::db::Type; SCOPED_TRACE("test table columns"); Filtering_options filters; const auto cache = Instance_cache_builder(m_session, filters).metadata({}).build(); const auto validate = [this, &cache](const std::string &schema, const std::string &table, const std::vector<bool> &csv_unsafe, const std::vector<bool> &nullable) { SCOPED_TRACE("testing table " + schema + "." + table); const auto &table_info = cache.schemas.at(schema).tables.at(table); const auto &actual = table_info.all_columns; const auto size = csv_unsafe.size(); const auto types = m_session->queryf( "SELECT " + shcore::str_join(actual, ",", [](const auto &c) { return c.quoted_name; }) + " FROM !.! LIMIT 0;", schema, table); ASSERT_EQ(size, actual.size()); ASSERT_EQ(size, nullable.size()); ASSERT_EQ(size, types->get_metadata().size()); for (std::size_t i = 0, idx = 0; i < size; ++i) { const auto column = actual[i].generated ? "gen" : "c" + std::to_string(idx); SCOPED_TRACE("checking column " + column); EXPECT_EQ(column, actual[i].name); EXPECT_EQ(shcore::quote_identifier(column), actual[i].quoted_name); EXPECT_EQ(csv_unsafe[i], actual[i].csv_unsafe); EXPECT_EQ(nullable[i], actual[i].nullable); EXPECT_EQ(types->get_metadata()[i].get_type(), actual[i].type); if (!actual[i].generated) { EXPECT_EQ(table_info.columns[idx++], &actual[i]); } } }; validate("first", "one", {false, false, false}, {false, true, true}); validate("first", "two", { false, // c0 TINYINT false, // c1 TINYINT UNSIGNED false, // c2 SMALLINT false, // c3 SMALLINT UNSIGNED false, // c4 MEDIUMINT false, // c5 MEDIUMINT UNSIGNED false, // c6 INT false, // c7 INT UNSIGNED false, // c8 INTEGER false, // c9 INTEGER UNSIGNED false, // c10 BIGINT false, // c11 BIGINT UNSIGNED false, // c12 DECIMAL(2,1) false, // c13 DECIMAL(2,1) UNSIGNED false, // c14 NUMERIC(64,30) false, // c15 NUMERIC(64,30) UNSIGNED false, // c16 REAL false, // c17 REAL UNSIGNED false, // c18 FLOAT false, // c19 FLOAT UNSIGNED false, // c20 DOUBLE false, // c21 DOUBLE UNSIGNED false, // c22 DATE false, // c23 TIME false, // c24 TIMESTAMP false, // c25 DATETIME false, // c26 YEAR true, // c27 TINYBLOB true, // c28 BLOB true, // c29 MEDIUMBLOB true, // c30 LONGBLOB false, // c31 TINYTEXT false, // c32 TEXT false, // c33 MEDIUMTEXT false, // c34 LONGTEXT false, // c35 TINYTEXT BINARY false, // c36 TEXT BINARY false, // c37 MEDIUMTEXT BINARY false, // c38 LONGTEXT BINARY false, // c39 CHAR(32) false, // c40 VARCHAR(32) true, // c41 BINARY(32) true, // c42 VARBINARY(32) true, // c43 BIT(64) false, // c44 ENUM('v1','v2','v3') false, // c45 SET('v1','v2','v3') false, // c46 JSON true, // c47 GEOMETRY true, // c48 POINT true, // c49 LINESTRING true, // c50 POLYGON true, // c51 MULTIPOINT true, // c52 MULTILINESTRING true, // c53 MULTIPOLYGON true, // c54 GEOMETRYCOLLECTION }, { true, // c0 TINYINT true, // c1 TINYINT UNSIGNED true, // c2 SMALLINT true, // c3 SMALLINT UNSIGNED true, // c4 MEDIUMINT true, // c5 MEDIUMINT UNSIGNED true, // c6 INT true, // c7 INT UNSIGNED true, // c8 INTEGER true, // c9 INTEGER UNSIGNED true, // c10 BIGINT true, // c11 BIGINT UNSIGNED true, // c12 DECIMAL(2,1) true, // c13 DECIMAL(2,1) UNSIGNED true, // c14 NUMERIC(64,30) true, // c15 NUMERIC(64,30) UNSIGNED true, // c16 REAL true, // c17 REAL UNSIGNED true, // c18 FLOAT true, // c19 FLOAT UNSIGNED true, // c20 DOUBLE true, // c21 DOUBLE UNSIGNED true, // c22 DATE true, // c23 TIME true, // c24 TIMESTAMP true, // c25 DATETIME true, // c26 YEAR true, // c27 TINYBLOB true, // c28 BLOB true, // c29 MEDIUMBLOB true, // c30 LONGBLOB true, // c31 TINYTEXT true, // c32 TEXT true, // c33 MEDIUMTEXT true, // c34 LONGTEXT true, // c35 TINYTEXT BINARY true, // c36 TEXT BINARY true, // c37 MEDIUMTEXT BINARY true, // c38 LONGTEXT BINARY true, // c39 CHAR(32) true, // c40 VARCHAR(32) true, // c41 BINARY(32) true, // c42 VARBINARY(32) true, // c43 BIT(64) true, // c44 ENUM('v1','v2','v3') true, // c45 SET('v1','v2','v3') true, // c46 JSON true, // c47 GEOMETRY true, // c48 POINT true, // c49 LINESTRING true, // c50 POLYGON true, // c51 MULTIPOINT true, // c52 MULTILINESTRING true, // c53 MULTIPOLYGON true, // c54 GEOMETRYCOLLECTION }); validate("second", "three", {false, false, true}, {true, true, true}); if (_target_server_version >= Version(8, 0, 13)) { validate("second", "four", {false}, {true}); } if (_target_server_version >= Version(8, 0, 23)) { validate("second", "five", {false, false, false}, {false, true, true}); validate("second", "six", {false, false, false}, {true, true, true}); } } } TEST_F(Instance_cache_test, table_indexes) { { // setup m_session->execute("CREATE SCHEMA first;"); m_session->execute( "CREATE TABLE first.one (" "id INT, data INT, hash INT, " "PRIMARY KEY (id, hash), " "UNIQUE INDEX (data, hash), " "INDEX (hash)" ");"); m_session->execute("CREATE SCHEMA second;"); m_session->execute( "CREATE TABLE second.two (" "id INT, data INT, hash INT, " "PRIMARY KEY (id, hash), " "UNIQUE INDEX (data, hash)" ");"); m_session->execute( "CREATE TABLE second.three (" "id INT, data INT, hash INT, " "PRIMARY KEY (id, hash), " "INDEX (hash)" ");"); m_session->execute( "CREATE TABLE second.four (" "id INT, data INT, hash INT, " "UNIQUE INDEX (data, hash), " "INDEX (hash)" ");"); m_session->execute("CREATE SCHEMA third;"); m_session->execute( "CREATE TABLE third.five (" "id INT, data INT, hash INT, " "PRIMARY KEY (id, hash)" ");"); m_session->execute( "CREATE TABLE third.six (" "id INT, data INT, hash INT, " "UNIQUE INDEX (data, hash)" ");"); m_session->execute( "CREATE TABLE third.seven (" "id INT, data INT, hash INT, " "INDEX (hash)" ");"); // shorter index is used m_session->execute( "CREATE TABLE third.eight (" "id INT, data INT, hash INT, " "UNIQUE INDEX b (data, hash), " "UNIQUE INDEX a (hash)" ");"); m_session->execute( "CREATE TABLE third.nine (" "id INT, data INT, hash INT, " "UNIQUE INDEX a (data, hash), " "UNIQUE INDEX b (hash)" ");"); // shorter index is used even though it's not an integer m_session->execute( "CREATE TABLE third.ten (" "id INT, data INT, hash VARCHAR(32), " "UNIQUE INDEX b (data, hash), " "UNIQUE INDEX a (hash)" ");"); m_session->execute( "CREATE TABLE third.eleven (" "id INT, data INT, hash VARCHAR(32), " "UNIQUE INDEX a (data, hash), " "UNIQUE INDEX b (hash)" ");"); // PK is used even though unique index is shorter m_session->execute( "CREATE TABLE third.twelve (" "id INT, data INT, hash INT, " "PRIMARY KEY (data, hash), " "UNIQUE INDEX a (id)" ");"); // integer-based index is used m_session->execute( "CREATE TABLE third.thirteen (" "id INT, data INT, hash VARCHAR(32), " "UNIQUE INDEX b (data), " "UNIQUE INDEX a (hash)" ");"); m_session->execute( "CREATE TABLE third.fourteen (" "id INT, data INT, hash VARCHAR(32), " "UNIQUE INDEX a (data), " "UNIQUE INDEX b (hash)" ");"); m_session->execute( "CREATE TABLE third.fifteen (" "id INT, data INT, hash VARCHAR(32), " "UNIQUE INDEX b (data, hash), " "UNIQUE INDEX a (id, data)" ");"); m_session->execute( "CREATE TABLE third.sixteen (" "id INT, data INT, hash VARCHAR(32), " "UNIQUE INDEX a (data, hash), " "UNIQUE INDEX b (id, data)" ");"); // generated index m_session->execute( "CREATE TABLE third.seventeen (" "data INT, gen INT GENERATED ALWAYS AS (data + 2) STORED, " "PRIMARY KEY (gen)" ");"); m_session->execute( "CREATE TABLE third.eighteen (" "data INT, gen INT GENERATED ALWAYS AS (data + 2) STORED, " "UNIQUE INDEX a (gen)" ");"); // NOT NULL index is used m_session->execute( "CREATE TABLE third.nineteen (" "id INT NOT NULL, data INT, hash VARCHAR(32), " "UNIQUE INDEX b (data), " "UNIQUE INDEX a (id)" ");"); m_session->execute( "CREATE TABLE third.twenty (" "id INT NOT NULL, data INT, hash VARCHAR(32), " "UNIQUE INDEX a (data), " "UNIQUE INDEX b (id)" ");"); m_session->execute( "CREATE TABLE third.`twenty-one` (" "id INT NOT NULL, data VARCHAR(32), hash VARCHAR(32) NOT NULL, " "UNIQUE INDEX b (data), " "UNIQUE INDEX a (hash)" ");"); m_session->execute( "CREATE TABLE third.`twenty-two` (" "id INT NOT NULL, data VARCHAR(32), hash VARCHAR(32) NOT NULL, " "UNIQUE INDEX a (data), " "UNIQUE INDEX b (hash)" ");"); m_session->execute( "CREATE TABLE third.`twenty-three` (" "id INT NOT NULL, data VARCHAR(32), hash VARCHAR(32) NOT NULL, " "UNIQUE INDEX b (id, data), " "UNIQUE INDEX a (id, hash)" ");"); m_session->execute( "CREATE TABLE third.`twenty-four` (" "id INT, data VARCHAR(32), hash VARCHAR(32) NOT NULL, " "UNIQUE INDEX a (id, data), " "UNIQUE INDEX b (id, hash)" ");"); } { SCOPED_TRACE("test table indexes"); Filtering_options filters; const auto cache = Instance_cache_builder(m_session, filters).metadata({}).build(); const auto validate = [&cache](const std::string &schema, const std::string &table, const std::vector<std::string> &expected_columns, bool expected_pke) { SCOPED_TRACE("testing table " + schema + "." + table); const auto actual = select_index(cache.schemas.at(schema).tables.at(table)); const auto size = expected_columns.size(); EXPECT_EQ(expected_pke, actual.second); ASSERT_EQ(size, actual.first ? actual.first->columns().size() : 0); for (std::size_t i = 0; i < size; ++i) { EXPECT_EQ(expected_columns[i], actual.first->columns()[i]->name); } }; validate("first", "one", {"id", "hash"}, true); validate("second", "two", {"id", "hash"}, true); validate("second", "three", {"id", "hash"}, true); validate("second", "four", {"data", "hash"}, false); validate("third", "five", {"id", "hash"}, true); validate("third", "six", {"data", "hash"}, false); validate("third", "seven", {}, false); validate("third", "eight", {"hash"}, false); validate("third", "nine", {"hash"}, false); validate("third", "ten", {"hash"}, false); validate("third", "eleven", {"hash"}, false); validate("third", "twelve", {"data", "hash"}, true); validate("third", "thirteen", {"data"}, false); validate("third", "fourteen", {"data"}, false); validate("third", "fifteen", {"id", "data"}, false); validate("third", "sixteen", {"id", "data"}, false); validate("third", "seventeen", {"gen"}, true); validate("third", "eighteen", {"gen"}, false); validate("third", "nineteen", {"id"}, true); validate("third", "twenty", {"id"}, true); validate("third", "twenty-one", {"hash"}, true); validate("third", "twenty-two", {"hash"}, true); validate("third", "twenty-three", {"id", "hash"}, true); validate("third", "twenty-four", {"id", "hash"}, false); } } TEST_F(Instance_cache_test, table_histograms) { if (_target_server_version < Version(8, 0, 0)) { SKIP_TEST("This test requires running against MySQL server version 8.0"); } { // setup m_session->execute("CREATE SCHEMA first;"); m_session->execute("CREATE TABLE first.one (id INT, data INT);"); m_session->execute("ANALYZE TABLE first.one UPDATE HISTOGRAM ON id;"); m_session->execute( "ANALYZE TABLE first.one UPDATE HISTOGRAM ON data " "WITH 50 buckets;"); m_session->execute("CREATE TABLE first.two (id INT, data INT);"); m_session->execute("CREATE SCHEMA second;"); m_session->execute("CREATE TABLE second.three (id INT, data INT);"); m_session->execute( "ANALYZE TABLE second.three UPDATE HISTOGRAM ON data,id " "WITH 25 buckets;"); } { SCOPED_TRACE("test table histograms"); Filtering_options filters; const auto cache = Instance_cache_builder(m_session, filters).metadata({}).build(); const auto validate = [&cache](const std::string &schema, const std::string &table, const std::vector<Instance_cache::Histogram> &expected) { SCOPED_TRACE("testing table " + schema + "." + table); const auto &actual = cache.schemas.at(schema).tables.at(table).histograms; const auto size = expected.size(); ASSERT_EQ(size, actual.size()); for (std::size_t i = 0; i < size; ++i) { EXPECT_EQ(expected[i].column, actual[i].column); EXPECT_EQ(expected[i].buckets, actual[i].buckets); } }; validate("first", "one", {{"data", 50}, {"id", 100}}); validate("first", "two", {}); validate("second", "three", {{"data", 25}, {"id", 25}}); } } #if defined(_WIN32) || defined(__APPLE__) TEST_F(Instance_cache_test, filter_schemas_and_tables_case_sensitive) { { // setup // on Windows: lower_case_table_names is 1, names are stored in lowercase, // comparison is NOT case-sensitive // on Mac: lower_case_table_names is 2, names are stored as given, // comparison is NOT case-sensitive. InnoDB table names and view // names are stored in lowercase, as for lower_case_table_names=1. // 'first' and 'First' cannot be created at the same time, we're using // lowercase names to match what is actually created by the server // we're forcing case-sensitive comparison, lowercase names should match // what's in the DB, uppercase should not match anything m_session->execute("CREATE SCHEMA first;"); m_session->execute("CREATE TABLE first.one (id INT);"); m_session->execute("CREATE VIEW first.two AS SELECT * FROM first.one;"); m_session->execute("CREATE SCHEMA second;"); m_session->execute("CREATE TABLE second.one (id INT);"); m_session->execute("CREATE VIEW second.two AS SELECT * FROM second.one;"); } { SCOPED_TRACE("all filters are empty"); Filtering_options filters; const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}}; first.views = {{"two", {}}}; verify(cache, "first", first); Instance_cache::Schema second; second.tables = {{"one", {}}}; second.views = {{"two", {}}}; verify(cache, "second", second); EXPECT_FALSE(contains(cache.schemas, "FIRST")); EXPECT_FALSE(contains(cache.schemas, "SECOND")); } { SCOPED_TRACE("include schema"); Filtering_options filters; filters.schemas().include("first"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema first; first.tables = {{"one", {}}}; first.views = {{"two", {}}}; verify(cache, "first", first); } { SCOPED_TRACE("include schema - uppercase"); Filtering_options filters; filters.schemas().include("FIRST"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_TRUE(cache.schemas.empty()); } { SCOPED_TRACE("include table"); Filtering_options filters; filters.tables().include("first", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}}; verify(cache, "first", first); EXPECT_FALSE(contains(cache.schemas, "FIRST")); Instance_cache::Schema second; verify(cache, "second", second); EXPECT_FALSE(contains(cache.schemas, "SECOND")); } { SCOPED_TRACE("include table - schema uppercase"); Filtering_options filters; filters.tables().include("FIRST", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; verify(cache, "first", first); EXPECT_FALSE(contains(cache.schemas, "FIRST")); Instance_cache::Schema second; verify(cache, "second", second); EXPECT_FALSE(contains(cache.schemas, "SECOND")); } { SCOPED_TRACE("include table - table uppercase"); Filtering_options filters; filters.tables().include("first", "ONE"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; verify(cache, "first", first); EXPECT_FALSE(contains(cache.schemas, "FIRST")); Instance_cache::Schema second; verify(cache, "second", second); EXPECT_FALSE(contains(cache.schemas, "SECOND")); } { SCOPED_TRACE("include view"); Filtering_options filters; filters.tables().include("first", "two"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.views = {{"two", {}}}; verify(cache, "first", first); EXPECT_FALSE(contains(cache.schemas, "FIRST")); Instance_cache::Schema second; verify(cache, "second", second); EXPECT_FALSE(contains(cache.schemas, "SECOND")); } { SCOPED_TRACE("include view - schema uppercase"); Filtering_options filters; filters.tables().include("FIRST", "two"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; verify(cache, "first", first); EXPECT_FALSE(contains(cache.schemas, "FIRST")); Instance_cache::Schema second; verify(cache, "second", second); EXPECT_FALSE(contains(cache.schemas, "SECOND")); } { SCOPED_TRACE("include view - view uppercase"); Filtering_options filters; filters.tables().include("first", "TWO"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; verify(cache, "first", first); EXPECT_FALSE(contains(cache.schemas, "FIRST")); Instance_cache::Schema second; verify(cache, "second", second); EXPECT_FALSE(contains(cache.schemas, "SECOND")); } { SCOPED_TRACE("exclude schema"); Filtering_options filters; filters.schemas().exclude("first"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_FALSE(contains(cache.schemas, "first")); EXPECT_FALSE(contains(cache.schemas, "FIRST")); Instance_cache::Schema second; second.tables = {{"one", {}}}; second.views = {{"two", {}}}; verify(cache, "second", second); EXPECT_FALSE(contains(cache.schemas, "SECOND")); } { SCOPED_TRACE("exclude schema - uppercase"); Filtering_options filters; filters.schemas().exclude("FIRST"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}}; first.views = {{"two", {}}}; verify(cache, "first", first); EXPECT_FALSE(contains(cache.schemas, "FIRST")); Instance_cache::Schema second; second.tables = {{"one", {}}}; second.views = {{"two", {}}}; verify(cache, "second", second); EXPECT_FALSE(contains(cache.schemas, "SECOND")); } { SCOPED_TRACE("exclude table"); Filtering_options filters; filters.tables().exclude("first", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.views = {{"two", {}}}; verify(cache, "first", first); EXPECT_FALSE(contains(cache.schemas, "FIRST")); Instance_cache::Schema second; second.tables = {{"one", {}}}; second.views = {{"two", {}}}; verify(cache, "second", second); EXPECT_FALSE(contains(cache.schemas, "SECOND")); } { SCOPED_TRACE("exclude table - schema uppercase"); Filtering_options filters; filters.tables().exclude("FIRST", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}}; first.views = {{"two", {}}}; verify(cache, "first", first); EXPECT_FALSE(contains(cache.schemas, "FIRST")); Instance_cache::Schema second; second.tables = {{"one", {}}}; second.views = {{"two", {}}}; verify(cache, "second", second); EXPECT_FALSE(contains(cache.schemas, "SECOND")); } { SCOPED_TRACE("exclude table - table uppercase"); Filtering_options filters; filters.tables().exclude("first", "ONE"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}}; first.views = {{"two", {}}}; verify(cache, "first", first); EXPECT_FALSE(contains(cache.schemas, "FIRST")); Instance_cache::Schema second; second.tables = {{"one", {}}}; second.views = {{"two", {}}}; verify(cache, "second", second); EXPECT_FALSE(contains(cache.schemas, "SECOND")); } { SCOPED_TRACE("exclude view"); Filtering_options filters; filters.tables().exclude("first", "two"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}}; verify(cache, "first", first); EXPECT_FALSE(contains(cache.schemas, "FIRST")); Instance_cache::Schema second; second.tables = {{"one", {}}}; second.views = {{"two", {}}}; verify(cache, "second", second); EXPECT_FALSE(contains(cache.schemas, "SECOND")); } { SCOPED_TRACE("exclude view - schema uppercase"); Filtering_options filters; filters.tables().exclude("FIRST", "two"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}}; first.views = {{"two", {}}}; verify(cache, "first", first); EXPECT_FALSE(contains(cache.schemas, "FIRST")); Instance_cache::Schema second; second.tables = {{"one", {}}}; second.views = {{"two", {}}}; verify(cache, "second", second); EXPECT_FALSE(contains(cache.schemas, "SECOND")); } { SCOPED_TRACE("exclude view - view uppercase"); Filtering_options filters; filters.tables().exclude("first", "TWO"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}}; first.views = {{"two", {}}}; verify(cache, "first", first); EXPECT_FALSE(contains(cache.schemas, "FIRST")); Instance_cache::Schema second; second.tables = {{"one", {}}}; second.views = {{"two", {}}}; verify(cache, "second", second); EXPECT_FALSE(contains(cache.schemas, "SECOND")); } { SCOPED_TRACE("include schema, include table"); Filtering_options filters; filters.schemas().include("first"); filters.tables().include("first", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema first; first.tables = {{"one", {}}}; verify(cache, "first", first); } { SCOPED_TRACE("include schema, include table - schema uppercase"); Filtering_options filters; filters.schemas().include("first"); filters.tables().include("FIRST", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema first; verify(cache, "first", first); } { SCOPED_TRACE("include schema, include table - table uppercase"); Filtering_options filters; filters.schemas().include("first"); filters.tables().include("first", "ONE"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema first; verify(cache, "first", first); } { SCOPED_TRACE("include schema, exclude schema"); Filtering_options filters; filters.schemas().include("first"); filters.schemas().exclude("first"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_TRUE(cache.schemas.empty()); } { SCOPED_TRACE("include schema, exclude schema - uppercase"); Filtering_options filters; filters.schemas().include("first"); filters.schemas().exclude("FIRST"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema first; first.tables = {{"one", {}}}; first.views = {{"two", {}}}; verify(cache, "first", first); } { SCOPED_TRACE("include schema, exclude table"); Filtering_options filters; filters.schemas().include("first"); filters.tables().exclude("first", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema first; first.views = {{"two", {}}}; verify(cache, "first", first); } { SCOPED_TRACE("include schema, exclude table - schema uppercase"); Filtering_options filters; filters.schemas().include("first"); filters.tables().exclude("FIRST", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema first; first.tables = {{"one", {}}}; first.views = {{"two", {}}}; verify(cache, "first", first); } { SCOPED_TRACE("include schema, exclude table - table uppercase"); Filtering_options filters; filters.schemas().include("first"); filters.tables().exclude("first", "ONE"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema first; first.tables = {{"one", {}}}; first.views = {{"two", {}}}; verify(cache, "first", first); } { SCOPED_TRACE("include table, exclude the same schema"); Filtering_options filters; filters.schemas().exclude("first"); filters.tables().include("first", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_FALSE(contains(cache.schemas, "first")); EXPECT_FALSE(contains(cache.schemas, "FIRST")); Instance_cache::Schema second; verify(cache, "second", second); EXPECT_FALSE(contains(cache.schemas, "SECOND")); } { SCOPED_TRACE("include table, exclude schema - uppercase"); Filtering_options filters; filters.schemas().exclude("FIRST"); filters.tables().include("first", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}}; verify(cache, "first", first); EXPECT_FALSE(contains(cache.schemas, "FIRST")); Instance_cache::Schema second; verify(cache, "second", second); EXPECT_FALSE(contains(cache.schemas, "SECOND")); } { SCOPED_TRACE("include table, exclude the same table"); Filtering_options filters; filters.tables().include("first", "one"); filters.tables().exclude("first", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; verify(cache, "first", first); EXPECT_FALSE(contains(cache.schemas, "FIRST")); Instance_cache::Schema second; verify(cache, "second", second); EXPECT_FALSE(contains(cache.schemas, "SECOND")); } { SCOPED_TRACE("include table, exclude table - schema uppercase"); Filtering_options filters; filters.tables().include("first", "one"); filters.tables().exclude("FIRST", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}}; verify(cache, "first", first); EXPECT_FALSE(contains(cache.schemas, "FIRST")); Instance_cache::Schema second; verify(cache, "second", second); EXPECT_FALSE(contains(cache.schemas, "SECOND")); } { SCOPED_TRACE("include table, exclude table - table uppercase"); Filtering_options filters; filters.tables().include("first", "one"); filters.tables().exclude("first", "ONE"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}}; verify(cache, "first", first); EXPECT_FALSE(contains(cache.schemas, "FIRST")); Instance_cache::Schema second; verify(cache, "second", second); EXPECT_FALSE(contains(cache.schemas, "SECOND")); } { SCOPED_TRACE("exclude schema, exclude table in the same schema"); Filtering_options filters; filters.schemas().exclude("first"); filters.tables().exclude("first", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_FALSE(contains(cache.schemas, "first")); EXPECT_FALSE(contains(cache.schemas, "FIRST")); Instance_cache::Schema second; second.tables = {{"one", {}}}; second.views = {{"two", {}}}; verify(cache, "second", second); EXPECT_FALSE(contains(cache.schemas, "SECOND")); } { SCOPED_TRACE("exclude schema, exclude table - schema uppercase"); Filtering_options filters; filters.schemas().exclude("first"); filters.tables().exclude("FIRST", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_FALSE(contains(cache.schemas, "first")); EXPECT_FALSE(contains(cache.schemas, "FIRST")); Instance_cache::Schema second; second.tables = {{"one", {}}}; second.views = {{"two", {}}}; verify(cache, "second", second); EXPECT_FALSE(contains(cache.schemas, "SECOND")); } { SCOPED_TRACE("exclude schema, exclude table - table uppercase"); Filtering_options filters; filters.schemas().exclude("first"); filters.tables().exclude("first", "ONE"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_FALSE(contains(cache.schemas, "first")); EXPECT_FALSE(contains(cache.schemas, "FIRST")); Instance_cache::Schema second; second.tables = {{"one", {}}}; second.views = {{"two", {}}}; verify(cache, "second", second); EXPECT_FALSE(contains(cache.schemas, "SECOND")); } { SCOPED_TRACE("include schema, include table, exclude schema"); Filtering_options filters; filters.schemas().include("first"); filters.schemas().exclude("second"); filters.tables().include("first", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema first; first.tables = {{"one", {}}}; verify(cache, "first", first); } { SCOPED_TRACE("include schema, include table, exclude schema - uppercase"); Filtering_options filters; filters.schemas().include("first"); filters.schemas().exclude("SECOND"); filters.tables().include("first", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema first; first.tables = {{"one", {}}}; verify(cache, "first", first); } { SCOPED_TRACE("include schema, include table, exclude table"); Filtering_options filters; filters.schemas().include("first"); filters.tables().include("first", "one"); filters.tables().exclude("first", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema first; verify(cache, "first", first); } { SCOPED_TRACE( "include schema, include table, exclude table - schema uppercase"); Filtering_options filters; filters.schemas().include("first"); filters.tables().include("first", "one"); filters.tables().exclude("FIRST", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema first; first.tables = {{"one", {}}}; verify(cache, "first", first); } { SCOPED_TRACE( "include schema, include table, exclude table - table uppercase"); Filtering_options filters; filters.schemas().include("first"); filters.tables().include("first", "one"); filters.tables().exclude("first", "ONE"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema first; first.tables = {{"one", {}}}; verify(cache, "first", first); } { SCOPED_TRACE("include table, exclude schema, exclude table"); Filtering_options filters; filters.schemas().exclude("second"); filters.tables().include("first", "one"); filters.tables().exclude("second", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}}; verify(cache, "first", first); EXPECT_FALSE(contains(cache.schemas, "FIRST")); EXPECT_FALSE(contains(cache.schemas, "second")); EXPECT_FALSE(contains(cache.schemas, "SECOND")); } { SCOPED_TRACE( "include table, exclude schema, exclude table - schema uppercase"); Filtering_options filters; filters.schemas().exclude("second"); filters.tables().include("first", "one"); filters.tables().exclude("SECOND", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}}; verify(cache, "first", first); EXPECT_FALSE(contains(cache.schemas, "FIRST")); EXPECT_FALSE(contains(cache.schemas, "second")); EXPECT_FALSE(contains(cache.schemas, "SECOND")); } { SCOPED_TRACE( "include table, exclude schema, exclude table - table uppercase"); Filtering_options filters; filters.schemas().exclude("second"); filters.tables().include("first", "one"); filters.tables().exclude("second", "ONE"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}}; verify(cache, "first", first); EXPECT_FALSE(contains(cache.schemas, "FIRST")); EXPECT_FALSE(contains(cache.schemas, "second")); EXPECT_FALSE(contains(cache.schemas, "SECOND")); } { SCOPED_TRACE("all filters"); Filtering_options filters; filters.schemas().include("first"); filters.schemas().exclude("second"); filters.tables().include("first", "one"); filters.tables().exclude("first", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema first; verify(cache, "first", first); } { SCOPED_TRACE("all filters - schema uppercase"); Filtering_options filters; filters.schemas().include("first"); filters.schemas().exclude("second"); filters.tables().include("first", "one"); filters.tables().exclude("FIRST", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema first; first.tables = {{"one", {}}}; verify(cache, "first", first); } { SCOPED_TRACE("all filters - table uppercase"); Filtering_options filters; filters.schemas().include("first"); filters.schemas().exclude("second"); filters.tables().include("first", "one"); filters.tables().exclude("first", "ONE"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema first; first.tables = {{"one", {}}}; verify(cache, "first", first); } } #else TEST_F(Instance_cache_test, filter_schemas_and_tables_case_sensitive) { { // setup // on Unix: lower_case_table_names is 0, names are stored as given, // comparison is case-sensitive m_session->execute("CREATE SCHEMA first;"); m_session->execute("CREATE TABLE first.one (id INT);"); m_session->execute("CREATE TABLE first.One (id INT);"); m_session->execute("CREATE VIEW first.two AS SELECT * FROM first.one;"); m_session->execute("CREATE VIEW first.Two AS SELECT * FROM first.One;"); m_session->execute("CREATE SCHEMA First;"); m_session->execute("CREATE TABLE First.one (id INT);"); m_session->execute("CREATE TABLE First.One (id INT);"); m_session->execute("CREATE VIEW First.two AS SELECT * FROM First.one;"); m_session->execute("CREATE VIEW First.Two AS SELECT * FROM First.One;"); } { SCOPED_TRACE("all filters are empty"); Filtering_options filters; const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}, {"One", {}}}; first.views = {{"two", {}}, {"Two", {}}}; verify(cache, "first", first); Instance_cache::Schema First; First.tables = {{"one", {}}, {"One", {}}}; First.views = {{"two", {}}, {"Two", {}}}; verify(cache, "First", First); } { SCOPED_TRACE("include schema"); Filtering_options filters; filters.schemas().include("first"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema first; first.tables = {{"one", {}}, {"One", {}}}; first.views = {{"two", {}}, {"Two", {}}}; verify(cache, "first", first); } { SCOPED_TRACE("include table"); Filtering_options filters; filters.tables().include("first", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}}; verify(cache, "first", first); Instance_cache::Schema First; verify(cache, "First", First); } { SCOPED_TRACE("include view"); Filtering_options filters; filters.tables().include("first", "Two"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.views = {{"Two", {}}}; verify(cache, "first", first); Instance_cache::Schema First; verify(cache, "First", First); } { SCOPED_TRACE("exclude schema"); Filtering_options filters; filters.schemas().exclude("First"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}, {"One", {}}}; first.views = {{"two", {}}, {"Two", {}}}; verify(cache, "first", first); EXPECT_FALSE(contains(cache.schemas, "First")); } { SCOPED_TRACE("exclude table"); Filtering_options filters; filters.tables().exclude("first", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"One", {}}}; first.views = {{"two", {}}, {"Two", {}}}; verify(cache, "first", first); Instance_cache::Schema First; First.tables = {{"one", {}}, {"One", {}}}; First.views = {{"two", {}}, {"Two", {}}}; verify(cache, "First", First); } { SCOPED_TRACE("exclude view"); Filtering_options filters; filters.tables().exclude("first", "Two"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}, {"One", {}}}; first.views = {{"two", {}}}; verify(cache, "first", first); Instance_cache::Schema First; First.tables = {{"one", {}}, {"One", {}}}; First.views = {{"two", {}}, {"Two", {}}}; verify(cache, "First", First); } { SCOPED_TRACE("include schema, include table in the same schema"); Filtering_options filters; filters.schemas().include("first"); filters.tables().include("first", "One"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema first; first.tables = {{"One", {}}}; verify(cache, "first", first); } { SCOPED_TRACE("include schema, include table in another schema"); Filtering_options filters; filters.schemas().include("first"); filters.tables().include("First", "One"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema first; verify(cache, "first", first); } { SCOPED_TRACE("include schema, exclude another schema"); Filtering_options filters; filters.schemas().include("first"); filters.schemas().exclude("First"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema first; first.tables = {{"one", {}}, {"One", {}}}; first.views = {{"two", {}}, {"Two", {}}}; verify(cache, "first", first); } { SCOPED_TRACE("include schema, exclude the same schema"); Filtering_options filters; filters.schemas().include("First"); filters.schemas().exclude("First"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_TRUE(cache.schemas.empty()); } { SCOPED_TRACE("include schema, exclude table in the same schema"); Filtering_options filters; filters.schemas().include("first"); filters.tables().exclude("first", "One"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema first; first.tables = {{"one", {}}}; first.views = {{"two", {}}, {"Two", {}}}; verify(cache, "first", first); } { SCOPED_TRACE("include schema, exclude table in another schema"); Filtering_options filters; filters.schemas().include("first"); filters.tables().exclude("First", "One"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema first; first.tables = {{"one", {}}, {"One", {}}}; first.views = {{"two", {}}, {"Two", {}}}; verify(cache, "first", first); } { SCOPED_TRACE("include table, exclude the same schema"); Filtering_options filters; filters.schemas().exclude("first"); filters.tables().include("first", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_FALSE(contains(cache.schemas, "first")); Instance_cache::Schema First; verify(cache, "First", First); } { SCOPED_TRACE("include table, exclude another schema"); Filtering_options filters; filters.schemas().exclude("First"); filters.tables().include("first", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}}; verify(cache, "first", first); EXPECT_FALSE(contains(cache.schemas, "First")); } { SCOPED_TRACE("include table, exclude the same table"); Filtering_options filters; filters.tables().include("first", "one"); filters.tables().exclude("first", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; verify(cache, "first", first); Instance_cache::Schema First; verify(cache, "First", First); } { SCOPED_TRACE("include table, exclude another table"); Filtering_options filters; filters.tables().include("first", "one"); filters.tables().exclude("first", "One"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"one", {}}}; verify(cache, "first", first); Instance_cache::Schema First; verify(cache, "First", First); } { SCOPED_TRACE("exclude schema, exclude table in the same schema"); Filtering_options filters; filters.schemas().exclude("first"); filters.tables().exclude("first", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_FALSE(contains(cache.schemas, "first")); Instance_cache::Schema First; First.tables = {{"one", {}}, {"One", {}}}; First.views = {{"two", {}}, {"Two", {}}}; verify(cache, "First", First); } { SCOPED_TRACE("exclude schema, exclude table in another schema"); Filtering_options filters; filters.schemas().exclude("first"); filters.tables().exclude("First", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_FALSE(contains(cache.schemas, "first")); Instance_cache::Schema First; First.tables = {{"One", {}}}; First.views = {{"two", {}}, {"Two", {}}}; verify(cache, "First", First); } { SCOPED_TRACE("include schema, include table, exclude schema"); Filtering_options filters; filters.schemas().include("first"); filters.schemas().exclude("First"); filters.tables().include("first", "One"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema first; first.tables = {{"One", {}}}; verify(cache, "first", first); } { SCOPED_TRACE("include schema, include table, exclude table"); Filtering_options filters; filters.schemas().include("first"); filters.tables().include("first", "One"); filters.tables().exclude("first", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema first; first.tables = {{"One", {}}}; verify(cache, "first", first); } { SCOPED_TRACE("include table, exclude schema, exclude table"); Filtering_options filters; filters.schemas().exclude("First"); filters.tables().include("first", "One"); filters.tables().exclude("first", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); Instance_cache::Schema first; first.tables = {{"One", {}}}; verify(cache, "first", first); EXPECT_FALSE(contains(cache.schemas, "First")); } { SCOPED_TRACE("all filters"); Filtering_options filters; filters.schemas().include("first"); filters.schemas().exclude("First"); filters.tables().include("first", "One"); filters.tables().exclude("first", "one"); const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_EQ(1, cache.schemas.size()); Instance_cache::Schema first; first.tables = {{"One", {}}}; verify(cache, "first", first); } } #endif TEST_F(Instance_cache_test, bug32540460) { // create some number of schemas, only one of them contains a table and a view // this is not guaranteed to reproduce the bug, as tables and views are held // in an unordered map const std::size_t schemas = 50; // select schema which is going to hold a table and a view, it should not be // the last one const std::string target_schema = "test_schema_" + std::to_string(rand() % (schemas - 1)); // exclude all existing schemas, to make sure only newly created ones are in // the result std::unordered_set<std::string> excluded_schemas; const auto cleanup = [this](std::size_t s) { for (std::size_t i = 0; i < s; ++i) { m_session->execute("DROP SCHEMA IF EXISTS test_schema_" + std::to_string(i)); } }; cleanup(schemas); { // fetch existing schemas const auto result = m_session->query("SELECT SCHEMA_NAME FROM information_schema.schemata"); while (const auto row = result->fetch_one()) { excluded_schemas.emplace(row->get_string(0)); } // create new schemas for (std::size_t i = 0; i < schemas; ++i) { m_session->execute("CREATE SCHEMA test_schema_" + std::to_string(i)); } // create table and view in one of the schemas m_session->execute("CREATE TABLE " + target_schema + ".one (id INT);"); m_session->execute("CREATE VIEW " + target_schema + ".two AS SELECT * FROM " + target_schema + ".one;"); } { // create the cache, do not fetch metadata, this will return just list of // schemas, tables and views Filtering_options filters; filters.schemas().exclude(excluded_schemas); auto cache = Instance_cache_builder(m_session, filters).build(); // recreate the cache, use the existing one, fetch metadata auto builder = Instance_cache_builder(m_session, filters, std::move(cache)); cache = builder.metadata({}).build(); EXPECT_EQ(schemas, cache.schemas.size()); Instance_cache::Schema target; target.tables = {{"one", {}}}; target.views = {{"two", {}}}; verify(cache, target_schema, target); EXPECT_FALSE( cache.schemas.at(target_schema).tables.at("one").columns.empty()); EXPECT_FALSE(cache.schemas.at(target_schema) .views.at("two") .collation_connection.empty()); } cleanup(schemas); } TEST_F(Instance_cache_test, filter_events) { { // setup m_session->execute("CREATE SCHEMA first;"); m_session->execute( "CREATE EVENT first.one ON SCHEDULE EVERY 1 YEAR DO SELECT 1;"); m_session->execute( "CREATE EVENT first.two ON SCHEDULE EVERY 1 YEAR DO SELECT 1;"); m_session->execute("CREATE SCHEMA second;"); m_session->execute( "CREATE EVENT second.one ON SCHEDULE EVERY 1 YEAR DO SELECT 1;"); m_session->execute( "CREATE EVENT second.two ON SCHEDULE EVERY 1 YEAR DO SELECT 1;"); m_session->execute("CREATE SCHEMA third;"); m_session->execute( "CREATE EVENT third.one ON SCHEDULE EVERY 1 YEAR DO SELECT 1;"); m_session->execute( "CREATE EVENT third.two ON SCHEDULE EVERY 1 YEAR DO SELECT 1;"); } const auto EXPECT_EVENTS = [](const Instance_cache &cache, const std::string &schema, const std::unordered_set<std::string> &expected) { SCOPED_TRACE("schema: " + schema); const auto it = cache.schemas.find(schema); ASSERT_TRUE(cache.schemas.end() != it) << "cache does not contain schema `" << schema << "`"; EXPECT_EQ(expected, it->second.events); }; { SCOPED_TRACE("all filters are empty"); Filtering_options filters; const auto cache = Instance_cache_builder(m_session, filters).events().build(); EXPECT_EVENTS(cache, "first", {"one", "two"}); EXPECT_EVENTS(cache, "second", {"one", "two"}); EXPECT_EVENTS(cache, "third", {"one", "two"}); } { SCOPED_TRACE("exclude event from non-existing schema"); Filtering_options filters; filters.events().exclude("fourth", "four"); const auto cache = Instance_cache_builder(m_session, filters).events().build(); EXPECT_EVENTS(cache, "first", {"one", "two"}); EXPECT_EVENTS(cache, "second", {"one", "two"}); EXPECT_EVENTS(cache, "third", {"one", "two"}); } { SCOPED_TRACE("exclude non-existing event"); Filtering_options filters; filters.events().exclude("third", "four"); const auto cache = Instance_cache_builder(m_session, filters).events().build(); EXPECT_EVENTS(cache, "first", {"one", "two"}); EXPECT_EVENTS(cache, "second", {"one", "two"}); EXPECT_EVENTS(cache, "third", {"one", "two"}); } { SCOPED_TRACE("exclude existing event"); Filtering_options filters; filters.events().exclude("third", "two"); const auto cache = Instance_cache_builder(m_session, filters).events().build(); EXPECT_EVENTS(cache, "first", {"one", "two"}); EXPECT_EVENTS(cache, "second", {"one", "two"}); EXPECT_EVENTS(cache, "third", {"one"}); } { SCOPED_TRACE( "exclude existing, non-existing event and an event in non-existing " "schema"); Filtering_options filters; filters.events().exclude("third", std::array{"two", "four"}); filters.events().exclude("fourth", "four"); const auto cache = Instance_cache_builder(m_session, filters).events().build(); EXPECT_EVENTS(cache, "first", {"one", "two"}); EXPECT_EVENTS(cache, "second", {"one", "two"}); EXPECT_EVENTS(cache, "third", {"one"}); } { SCOPED_TRACE("exclude all events from the same schema"); Filtering_options filters; filters.events().exclude("third", std::array{"one", "two", "three"}); const auto cache = Instance_cache_builder(m_session, filters).events().build(); EXPECT_EVENTS(cache, "first", {"one", "two"}); EXPECT_EVENTS(cache, "second", {"one", "two"}); EXPECT_EVENTS(cache, "third", {}); } { SCOPED_TRACE("exclude existing events from different schemas"); Filtering_options filters; filters.events().exclude("first", "one"); filters.events().exclude("second", "two"); filters.events().exclude("third", "one"); const auto cache = Instance_cache_builder(m_session, filters).events().build(); EXPECT_EVENTS(cache, "first", {"two"}); EXPECT_EVENTS(cache, "second", {"one"}); EXPECT_EVENTS(cache, "third", {"two"}); } { SCOPED_TRACE("include event from non-existing schema"); Filtering_options filters; filters.events().include("fourth", "four"); const auto cache = Instance_cache_builder(m_session, filters).events().build(); EXPECT_EVENTS(cache, "first", {}); EXPECT_EVENTS(cache, "second", {}); EXPECT_EVENTS(cache, "third", {}); } { SCOPED_TRACE("include non-existing event"); Filtering_options filters; filters.events().include("third", "four"); const auto cache = Instance_cache_builder(m_session, filters).events().build(); EXPECT_EVENTS(cache, "first", {}); EXPECT_EVENTS(cache, "second", {}); EXPECT_EVENTS(cache, "third", {}); } { SCOPED_TRACE("include existing event"); Filtering_options filters; filters.events().include("third", "two"); const auto cache = Instance_cache_builder(m_session, filters).events().build(); EXPECT_EVENTS(cache, "first", {}); EXPECT_EVENTS(cache, "second", {}); EXPECT_EVENTS(cache, "third", {"two"}); } { SCOPED_TRACE("include existing and non-existing events"); Filtering_options filters; filters.events().include("third", std::array{"two", "four"}); filters.events().include("fourth", "four"); const auto cache = Instance_cache_builder(m_session, filters).events().build(); EXPECT_EVENTS(cache, "first", {}); EXPECT_EVENTS(cache, "second", {}); EXPECT_EVENTS(cache, "third", {"two"}); } { SCOPED_TRACE("include existing events from the same schema"); Filtering_options filters; filters.events().include("third", std::array{"one", "two"}); const auto cache = Instance_cache_builder(m_session, filters).events().build(); EXPECT_EVENTS(cache, "first", {}); EXPECT_EVENTS(cache, "second", {}); EXPECT_EVENTS(cache, "third", {"one", "two"}); } { SCOPED_TRACE("include existing events from different schemas"); Filtering_options filters; filters.events().include("first", "one"); filters.events().include("second", "two"); filters.events().include("third", "three"); const auto cache = Instance_cache_builder(m_session, filters).events().build(); EXPECT_EVENTS(cache, "first", {"one"}); EXPECT_EVENTS(cache, "second", {"two"}); EXPECT_EVENTS(cache, "third", {}); } { SCOPED_TRACE("include and exclude the same existing event"); Filtering_options filters; filters.events().include("third", "two"); filters.events().exclude("third", "two"); const auto cache = Instance_cache_builder(m_session, filters).events().build(); EXPECT_EVENTS(cache, "first", {}); EXPECT_EVENTS(cache, "second", {}); EXPECT_EVENTS(cache, "third", {}); } { SCOPED_TRACE("include and exclude the same existing event + some more"); Filtering_options filters; filters.events().include("third", "two"); filters.events().exclude("second", "two"); filters.events().exclude("third", "two"); filters.events().exclude("fourth", "four"); const auto cache = Instance_cache_builder(m_session, filters).events().build(); EXPECT_EVENTS(cache, "first", {}); EXPECT_EVENTS(cache, "second", {}); EXPECT_EVENTS(cache, "third", {}); } { SCOPED_TRACE("include and exclude existing events from different schemas"); Filtering_options filters; filters.events().include("first", "one"); filters.events().include("second", "two"); filters.events().include("third", "two"); filters.events().exclude("first", "two"); filters.events().exclude("second", "two"); filters.events().exclude("third", "one"); const auto cache = Instance_cache_builder(m_session, filters).events().build(); EXPECT_EVENTS(cache, "first", {"one"}); EXPECT_EVENTS(cache, "second", {}); EXPECT_EVENTS(cache, "third", {"two"}); } } TEST_F(Instance_cache_test, filter_routines) { { // setup m_session->execute("CREATE SCHEMA first;"); m_session->execute( "CREATE FUNCTION first.one() RETURNS INT DETERMINISTIC RETURN 1;"); m_session->execute("CREATE PROCEDURE first.two() DETERMINISTIC BEGIN END;"); m_session->execute("CREATE SCHEMA second;"); m_session->execute( "CREATE PROCEDURE second.one() DETERMINISTIC BEGIN END;"); m_session->execute( "CREATE FUNCTION second.two() RETURNS INT DETERMINISTIC RETURN 1;"); m_session->execute("CREATE SCHEMA third;"); m_session->execute( "CREATE FUNCTION third.one() RETURNS INT DETERMINISTIC RETURN 1;"); m_session->execute("CREATE PROCEDURE third.two() DETERMINISTIC BEGIN END;"); } const auto EXPECT_ROUTINES = [](const Instance_cache &cache, const std::string &schema, const std::unordered_set<std::string> &expected) { SCOPED_TRACE("schema: " + schema); const auto it = cache.schemas.find(schema); ASSERT_TRUE(cache.schemas.end() != it) << "cache does not contain schema `" << schema << "`"; std::unordered_set<std::string> routines = it->second.functions; routines.insert(it->second.procedures.begin(), it->second.procedures.end()); EXPECT_EQ(expected, routines); }; { SCOPED_TRACE("all filters are empty"); Filtering_options filters; const auto cache = Instance_cache_builder(m_session, filters).routines().build(); EXPECT_ROUTINES(cache, "first", {"one", "two"}); EXPECT_ROUTINES(cache, "second", {"one", "two"}); EXPECT_ROUTINES(cache, "third", {"one", "two"}); } { SCOPED_TRACE("exclude routine from non-existing schema"); Filtering_options filters; filters.routines().exclude("fourth", "four"); const auto cache = Instance_cache_builder(m_session, filters).routines().build(); EXPECT_ROUTINES(cache, "first", {"one", "two"}); EXPECT_ROUTINES(cache, "second", {"one", "two"}); EXPECT_ROUTINES(cache, "third", {"one", "two"}); } { SCOPED_TRACE("exclude non-existing routine"); Filtering_options filters; filters.routines().exclude("third", "four"); const auto cache = Instance_cache_builder(m_session, filters).routines().build(); EXPECT_ROUTINES(cache, "first", {"one", "two"}); EXPECT_ROUTINES(cache, "second", {"one", "two"}); EXPECT_ROUTINES(cache, "third", {"one", "two"}); } { SCOPED_TRACE("exclude existing routine"); Filtering_options filters; filters.routines().exclude("third", "two"); const auto cache = Instance_cache_builder(m_session, filters).routines().build(); EXPECT_ROUTINES(cache, "first", {"one", "two"}); EXPECT_ROUTINES(cache, "second", {"one", "two"}); EXPECT_ROUTINES(cache, "third", {"one"}); } { SCOPED_TRACE( "exclude existing, non-existing routine and a routine in non-existing " "schema"); Filtering_options filters; filters.routines().exclude("third", std::array{"two", "four"}); filters.routines().exclude("fourth", "four"); const auto cache = Instance_cache_builder(m_session, filters).routines().build(); EXPECT_ROUTINES(cache, "first", {"one", "two"}); EXPECT_ROUTINES(cache, "second", {"one", "two"}); EXPECT_ROUTINES(cache, "third", {"one"}); } { SCOPED_TRACE("exclude all routines from the same schema"); Filtering_options filters; filters.routines().exclude("third", std::array{"one", "two", "three"}); const auto cache = Instance_cache_builder(m_session, filters).routines().build(); EXPECT_ROUTINES(cache, "first", {"one", "two"}); EXPECT_ROUTINES(cache, "second", {"one", "two"}); EXPECT_ROUTINES(cache, "third", {}); } { SCOPED_TRACE("exclude existing routines from different schemas"); Filtering_options filters; filters.routines().exclude("first", "one"); filters.routines().exclude("second", "two"); filters.routines().exclude("third", "one"); const auto cache = Instance_cache_builder(m_session, filters).routines().build(); EXPECT_ROUTINES(cache, "first", {"two"}); EXPECT_ROUTINES(cache, "second", {"one"}); EXPECT_ROUTINES(cache, "third", {"two"}); } { SCOPED_TRACE("include routine from non-existing schema"); Filtering_options filters; filters.routines().include("fourth", "four"); const auto cache = Instance_cache_builder(m_session, filters).routines().build(); EXPECT_ROUTINES(cache, "first", {}); EXPECT_ROUTINES(cache, "second", {}); EXPECT_ROUTINES(cache, "third", {}); } { SCOPED_TRACE("include non-existing routine"); Filtering_options filters; filters.routines().include("third", "four"); const auto cache = Instance_cache_builder(m_session, filters).routines().build(); EXPECT_ROUTINES(cache, "first", {}); EXPECT_ROUTINES(cache, "second", {}); EXPECT_ROUTINES(cache, "third", {}); } { SCOPED_TRACE("include existing routine"); Filtering_options filters; filters.routines().include("third", "two"); const auto cache = Instance_cache_builder(m_session, filters).routines().build(); EXPECT_ROUTINES(cache, "first", {}); EXPECT_ROUTINES(cache, "second", {}); EXPECT_ROUTINES(cache, "third", {"two"}); } { SCOPED_TRACE("include existing and non-existing routines"); Filtering_options filters; filters.routines().include("third", std::array{"two", "four"}); filters.routines().include("fourth", "four"); const auto cache = Instance_cache_builder(m_session, filters).routines().build(); EXPECT_ROUTINES(cache, "first", {}); EXPECT_ROUTINES(cache, "second", {}); EXPECT_ROUTINES(cache, "third", {"two"}); } { SCOPED_TRACE("include existing routines from the same schema"); Filtering_options filters; filters.routines().include("third", std::array{"one", "two"}); const auto cache = Instance_cache_builder(m_session, filters).routines().build(); EXPECT_ROUTINES(cache, "first", {}); EXPECT_ROUTINES(cache, "second", {}); EXPECT_ROUTINES(cache, "third", {"one", "two"}); } { SCOPED_TRACE("include existing routines from different schemas"); Filtering_options filters; filters.routines().include("first", "one"); filters.routines().include("second", "two"); filters.routines().include("third", "three"); const auto cache = Instance_cache_builder(m_session, filters).routines().build(); EXPECT_ROUTINES(cache, "first", {"one"}); EXPECT_ROUTINES(cache, "second", {"two"}); EXPECT_ROUTINES(cache, "third", {}); } { SCOPED_TRACE("include and exclude the same existing routine"); Filtering_options filters; filters.routines().include("third", "two"); filters.routines().exclude("third", "two"); const auto cache = Instance_cache_builder(m_session, filters).routines().build(); EXPECT_ROUTINES(cache, "first", {}); EXPECT_ROUTINES(cache, "second", {}); EXPECT_ROUTINES(cache, "third", {}); } { SCOPED_TRACE("include and exclude the same existing routine + some more"); Filtering_options filters; filters.routines().include("third", "two"); filters.routines().exclude("second", "two"); filters.routines().exclude("third", "two"); filters.routines().exclude("fourth", "four"); const auto cache = Instance_cache_builder(m_session, filters).routines().build(); EXPECT_ROUTINES(cache, "first", {}); EXPECT_ROUTINES(cache, "second", {}); EXPECT_ROUTINES(cache, "third", {}); } { SCOPED_TRACE( "include and exclude existing routines from different schemas"); Filtering_options filters; filters.routines().include("first", "one"); filters.routines().include("second", "two"); filters.routines().include("third", "two"); filters.routines().exclude("first", "two"); filters.routines().exclude("second", "two"); filters.routines().exclude("third", "one"); const auto cache = Instance_cache_builder(m_session, filters).routines().build(); EXPECT_ROUTINES(cache, "first", {"one"}); EXPECT_ROUTINES(cache, "second", {}); EXPECT_ROUTINES(cache, "third", {"two"}); } } TEST_F(Instance_cache_test, filter_triggers) { { // setup m_session->execute("CREATE SCHEMA first;"); m_session->execute("CREATE TABLE first.one (id INT);"); m_session->execute( "CREATE TRIGGER first.t1 AFTER DELETE ON first.one FOR EACH ROW BEGIN " "END;"); m_session->execute( "CREATE TRIGGER first.t2 AFTER DELETE ON first.one FOR EACH ROW BEGIN " "END;"); m_session->execute("CREATE TABLE first.two (id INT);"); m_session->execute( "CREATE TRIGGER first.t3 AFTER DELETE ON first.two FOR EACH ROW BEGIN " "END;"); m_session->execute( "CREATE TRIGGER first.t4 AFTER DELETE ON first.two FOR EACH ROW BEGIN " "END;"); m_session->execute("CREATE SCHEMA second;"); m_session->execute("CREATE TABLE second.one (id INT);"); m_session->execute( "CREATE TRIGGER second.t1 AFTER DELETE ON second.one FOR EACH ROW " "BEGIN END;"); m_session->execute( "CREATE TRIGGER second.t2 AFTER DELETE ON second.one FOR EACH ROW " "BEGIN END;"); m_session->execute("CREATE TABLE second.two (id INT);"); m_session->execute( "CREATE TRIGGER second.t3 AFTER DELETE ON second.two FOR EACH ROW " "BEGIN END;"); m_session->execute( "CREATE TRIGGER second.t4 AFTER DELETE ON second.two FOR EACH ROW " "BEGIN END;"); m_session->execute("CREATE SCHEMA third;"); m_session->execute("CREATE TABLE third.one (id INT);"); m_session->execute( "CREATE TRIGGER third.t1 AFTER DELETE ON third.one FOR EACH ROW BEGIN " "END;"); m_session->execute( "CREATE TRIGGER third.t2 AFTER DELETE ON third.one FOR EACH ROW BEGIN " "END;"); m_session->execute("CREATE TABLE third.two (id INT);"); m_session->execute( "CREATE TRIGGER third.t3 AFTER DELETE ON third.two FOR EACH ROW BEGIN " "END;"); m_session->execute( "CREATE TRIGGER third.t4 AFTER DELETE ON third.two FOR EACH ROW BEGIN " "END;"); } const auto EXPECT_TRIGGERS = [](const Instance_cache &cache, const std::string &schema, const std::string &table, const std::vector<std::string> &expected) { SCOPED_TRACE("schema: " + schema + ", table: " + table); const auto s = cache.schemas.find(schema); ASSERT_TRUE(cache.schemas.end() != s) << "cache does not contain schema `" << schema << "`"; const auto t = s->second.tables.find(table); ASSERT_TRUE(s->second.tables.end() != t) << "schema does not contain table `" << table << "`"; EXPECT_EQ(expected, t->second.triggers); }; { SCOPED_TRACE("all filters are empty"); Filtering_options filters; const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); EXPECT_TRIGGERS(cache, "first", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "first", "two", {"t3", "t4"}); EXPECT_TRIGGERS(cache, "second", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "second", "two", {"t3", "t4"}); EXPECT_TRIGGERS(cache, "third", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "third", "two", {"t3", "t4"}); } { SCOPED_TRACE("exclude trigger from non-existing schema"); Filtering_options filters; filters.triggers().exclude("fourth", "four", "t1"); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); EXPECT_TRIGGERS(cache, "first", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "first", "two", {"t3", "t4"}); EXPECT_TRIGGERS(cache, "second", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "second", "two", {"t3", "t4"}); EXPECT_TRIGGERS(cache, "third", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "third", "two", {"t3", "t4"}); } { SCOPED_TRACE( "exclude trigger from non-existing table (name does not match)"); Filtering_options filters; filters.triggers().exclude("third", "three", "t9"); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); EXPECT_TRIGGERS(cache, "first", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "first", "two", {"t3", "t4"}); EXPECT_TRIGGERS(cache, "second", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "second", "two", {"t3", "t4"}); EXPECT_TRIGGERS(cache, "third", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "third", "two", {"t3", "t4"}); } { SCOPED_TRACE("exclude trigger from non-existing table (name matches)"); Filtering_options filters; filters.triggers().exclude("third", "three", "t1"); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); EXPECT_TRIGGERS(cache, "first", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "first", "two", {"t3", "t4"}); EXPECT_TRIGGERS(cache, "second", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "second", "two", {"t3", "t4"}); EXPECT_TRIGGERS(cache, "third", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "third", "two", {"t3", "t4"}); } { SCOPED_TRACE("exclude non-existing trigger"); Filtering_options filters; filters.triggers().exclude("third", "one", "t7"); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); EXPECT_TRIGGERS(cache, "first", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "first", "two", {"t3", "t4"}); EXPECT_TRIGGERS(cache, "second", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "second", "two", {"t3", "t4"}); EXPECT_TRIGGERS(cache, "third", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "third", "two", {"t3", "t4"}); } { SCOPED_TRACE("exclude existing trigger"); Filtering_options filters; filters.triggers().exclude("third", "one", "t1"); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); EXPECT_TRIGGERS(cache, "first", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "first", "two", {"t3", "t4"}); EXPECT_TRIGGERS(cache, "second", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "second", "two", {"t3", "t4"}); EXPECT_TRIGGERS(cache, "third", "one", {"t2"}); EXPECT_TRIGGERS(cache, "third", "two", {"t3", "t4"}); } { SCOPED_TRACE("exclude existing trigger from another table"); Filtering_options filters; filters.triggers().exclude("third", "one", "t4"); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); EXPECT_TRIGGERS(cache, "first", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "first", "two", {"t3", "t4"}); EXPECT_TRIGGERS(cache, "second", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "second", "two", {"t3", "t4"}); EXPECT_TRIGGERS(cache, "third", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "third", "two", {"t3", "t4"}); } { SCOPED_TRACE( "exclude existing, non-existing trigger and a trigger in non-existing " "schema"); Filtering_options filters; filters.triggers().exclude("third", "one", "t1"); filters.triggers().exclude("third", "one", "t4"); filters.triggers().exclude("third", "one", "t7"); filters.triggers().exclude("fourth", "four", "t1"); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); EXPECT_TRIGGERS(cache, "first", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "first", "two", {"t3", "t4"}); EXPECT_TRIGGERS(cache, "second", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "second", "two", {"t3", "t4"}); EXPECT_TRIGGERS(cache, "third", "one", {"t2"}); EXPECT_TRIGGERS(cache, "third", "two", {"t3", "t4"}); } { SCOPED_TRACE("exclude all triggers from the same table"); Filtering_options filters; filters.triggers().exclude("third", "one", "t1"); filters.triggers().exclude("third", "one", "t2"); filters.triggers().exclude("third", "one", "t3"); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); EXPECT_TRIGGERS(cache, "first", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "first", "two", {"t3", "t4"}); EXPECT_TRIGGERS(cache, "second", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "second", "two", {"t3", "t4"}); EXPECT_TRIGGERS(cache, "third", "one", {}); EXPECT_TRIGGERS(cache, "third", "two", {"t3", "t4"}); } { SCOPED_TRACE("exclude all triggers from the same table (2)"); Filtering_options filters; filters.triggers().exclude("third", "one", ""); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); EXPECT_TRIGGERS(cache, "first", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "first", "two", {"t3", "t4"}); EXPECT_TRIGGERS(cache, "second", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "second", "two", {"t3", "t4"}); EXPECT_TRIGGERS(cache, "third", "one", {}); EXPECT_TRIGGERS(cache, "third", "two", {"t3", "t4"}); } { SCOPED_TRACE("exclude existing triggers from different schemas"); Filtering_options filters; filters.triggers().exclude("first", "one", "t1"); filters.triggers().exclude("first", "one", "t5"); filters.triggers().exclude("second", "two", "t3"); filters.triggers().exclude("second", "two", "t5"); filters.triggers().exclude("third", "one", ""); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); EXPECT_TRIGGERS(cache, "first", "one", {"t2"}); EXPECT_TRIGGERS(cache, "first", "two", {"t3", "t4"}); EXPECT_TRIGGERS(cache, "second", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "second", "two", {"t4"}); EXPECT_TRIGGERS(cache, "third", "one", {}); EXPECT_TRIGGERS(cache, "third", "two", {"t3", "t4"}); } { SCOPED_TRACE("include trigger from non-existing schema"); Filtering_options filters; filters.triggers().include("fourth", "four", "t1"); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); EXPECT_TRIGGERS(cache, "first", "one", {}); EXPECT_TRIGGERS(cache, "first", "two", {}); EXPECT_TRIGGERS(cache, "second", "one", {}); EXPECT_TRIGGERS(cache, "second", "two", {}); EXPECT_TRIGGERS(cache, "third", "one", {}); EXPECT_TRIGGERS(cache, "third", "two", {}); } { SCOPED_TRACE( "include trigger from non-existing table (name does not match)"); Filtering_options filters; filters.triggers().include("third", "three", "t9"); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); EXPECT_TRIGGERS(cache, "first", "one", {}); EXPECT_TRIGGERS(cache, "first", "two", {}); EXPECT_TRIGGERS(cache, "second", "one", {}); EXPECT_TRIGGERS(cache, "second", "two", {}); EXPECT_TRIGGERS(cache, "third", "one", {}); EXPECT_TRIGGERS(cache, "third", "two", {}); } { SCOPED_TRACE("include trigger from non-existing table (name matches)"); Filtering_options filters; filters.triggers().include("third", "three", "t1"); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); EXPECT_TRIGGERS(cache, "first", "one", {}); EXPECT_TRIGGERS(cache, "first", "two", {}); EXPECT_TRIGGERS(cache, "second", "one", {}); EXPECT_TRIGGERS(cache, "second", "two", {}); EXPECT_TRIGGERS(cache, "third", "one", {}); EXPECT_TRIGGERS(cache, "third", "two", {}); } { SCOPED_TRACE("include non-existing trigger"); Filtering_options filters; filters.triggers().include("third", "one", "t7"); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); EXPECT_TRIGGERS(cache, "first", "one", {}); EXPECT_TRIGGERS(cache, "first", "two", {}); EXPECT_TRIGGERS(cache, "second", "one", {}); EXPECT_TRIGGERS(cache, "second", "two", {}); EXPECT_TRIGGERS(cache, "third", "one", {}); EXPECT_TRIGGERS(cache, "third", "two", {}); } { SCOPED_TRACE("include existing trigger"); Filtering_options filters; filters.triggers().include("third", "one", "t1"); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); EXPECT_TRIGGERS(cache, "first", "one", {}); EXPECT_TRIGGERS(cache, "first", "two", {}); EXPECT_TRIGGERS(cache, "second", "one", {}); EXPECT_TRIGGERS(cache, "second", "two", {}); EXPECT_TRIGGERS(cache, "third", "one", {"t1"}); EXPECT_TRIGGERS(cache, "third", "two", {}); } { SCOPED_TRACE("include existing trigger from another table"); Filtering_options filters; filters.triggers().include("third", "one", "t4"); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); EXPECT_TRIGGERS(cache, "first", "one", {}); EXPECT_TRIGGERS(cache, "first", "two", {}); EXPECT_TRIGGERS(cache, "second", "one", {}); EXPECT_TRIGGERS(cache, "second", "two", {}); EXPECT_TRIGGERS(cache, "third", "one", {}); EXPECT_TRIGGERS(cache, "third", "two", {}); } { SCOPED_TRACE("include all triggers"); Filtering_options filters; filters.triggers().include("third", "one", "t1"); filters.triggers().include("third", "one", "t2"); filters.triggers().include("third", "one", "t3"); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); EXPECT_TRIGGERS(cache, "first", "one", {}); EXPECT_TRIGGERS(cache, "first", "two", {}); EXPECT_TRIGGERS(cache, "second", "one", {}); EXPECT_TRIGGERS(cache, "second", "two", {}); EXPECT_TRIGGERS(cache, "third", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "third", "two", {}); } { SCOPED_TRACE("include all triggers (2)"); Filtering_options filters; filters.triggers().include("third", "one", ""); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); EXPECT_TRIGGERS(cache, "first", "one", {}); EXPECT_TRIGGERS(cache, "first", "two", {}); EXPECT_TRIGGERS(cache, "second", "one", {}); EXPECT_TRIGGERS(cache, "second", "two", {}); EXPECT_TRIGGERS(cache, "third", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "third", "two", {}); } { SCOPED_TRACE("include existing and non-existing triggers"); Filtering_options filters; filters.triggers().include("third", "one", "t1"); filters.triggers().include("third", "one", "t4"); filters.triggers().include("third", "one", "t7"); filters.triggers().include("fourth", "four", "t1"); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); EXPECT_TRIGGERS(cache, "first", "one", {}); EXPECT_TRIGGERS(cache, "first", "two", {}); EXPECT_TRIGGERS(cache, "second", "one", {}); EXPECT_TRIGGERS(cache, "second", "two", {}); EXPECT_TRIGGERS(cache, "third", "one", {"t1"}); EXPECT_TRIGGERS(cache, "third", "two", {}); } { SCOPED_TRACE("include existing triggers from different schemas"); Filtering_options filters; filters.triggers().include("first", "one", "t1"); filters.triggers().include("second", "two", "t3"); filters.triggers().include("third", "one", ""); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); EXPECT_TRIGGERS(cache, "first", "one", {"t1"}); EXPECT_TRIGGERS(cache, "first", "two", {}); EXPECT_TRIGGERS(cache, "second", "one", {}); EXPECT_TRIGGERS(cache, "second", "two", {"t3"}); EXPECT_TRIGGERS(cache, "third", "one", {"t1", "t2"}); EXPECT_TRIGGERS(cache, "third", "two", {}); } { SCOPED_TRACE("include and exclude the same existing triggers"); Filtering_options filters; filters.triggers().include("third", "one", "t1"); filters.triggers().exclude("third", "one", "t1"); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); EXPECT_TRIGGERS(cache, "first", "one", {}); EXPECT_TRIGGERS(cache, "first", "two", {}); EXPECT_TRIGGERS(cache, "second", "one", {}); EXPECT_TRIGGERS(cache, "second", "two", {}); EXPECT_TRIGGERS(cache, "third", "one", {}); EXPECT_TRIGGERS(cache, "third", "two", {}); } { SCOPED_TRACE("include and exclude triggers from the same table"); Filtering_options filters; filters.triggers().include("third", "one", ""); filters.triggers().exclude("third", "one", "t1"); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); EXPECT_TRIGGERS(cache, "first", "one", {}); EXPECT_TRIGGERS(cache, "first", "two", {}); EXPECT_TRIGGERS(cache, "second", "one", {}); EXPECT_TRIGGERS(cache, "second", "two", {}); EXPECT_TRIGGERS(cache, "third", "one", {"t2"}); EXPECT_TRIGGERS(cache, "third", "two", {}); } { SCOPED_TRACE("include and exclude triggers from the same table (2)"); Filtering_options filters; filters.triggers().include("third", "one", ""); filters.triggers().exclude("third", "one", ""); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); EXPECT_TRIGGERS(cache, "first", "one", {}); EXPECT_TRIGGERS(cache, "first", "two", {}); EXPECT_TRIGGERS(cache, "second", "one", {}); EXPECT_TRIGGERS(cache, "second", "two", {}); EXPECT_TRIGGERS(cache, "third", "one", {}); EXPECT_TRIGGERS(cache, "third", "two", {}); } { SCOPED_TRACE("include and exclude triggers from the same table (3)"); Filtering_options filters; filters.triggers().include("third", "one", "t1"); filters.triggers().exclude("third", "one", ""); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); EXPECT_TRIGGERS(cache, "first", "one", {}); EXPECT_TRIGGERS(cache, "first", "two", {}); EXPECT_TRIGGERS(cache, "second", "one", {}); EXPECT_TRIGGERS(cache, "second", "two", {}); EXPECT_TRIGGERS(cache, "third", "one", {}); EXPECT_TRIGGERS(cache, "third", "two", {}); } { SCOPED_TRACE("include and exclude the same existing triggers + some more"); Filtering_options filters; filters.triggers().include("third", "one", "t1"); filters.triggers().exclude("first", "one", "t1"); filters.triggers().exclude("third", "one", "t1"); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); EXPECT_TRIGGERS(cache, "first", "one", {}); EXPECT_TRIGGERS(cache, "first", "two", {}); EXPECT_TRIGGERS(cache, "second", "one", {}); EXPECT_TRIGGERS(cache, "second", "two", {}); EXPECT_TRIGGERS(cache, "third", "one", {}); EXPECT_TRIGGERS(cache, "third", "two", {}); } { SCOPED_TRACE( "include and exclude existing triggers from different schemas"); Filtering_options filters; filters.triggers().include("first", "one", "t1"); filters.triggers().include("second", "two", "t3"); filters.triggers().include("third", "one", ""); filters.triggers().exclude("first", "one", ""); filters.triggers().exclude("second", "two", "t3"); filters.triggers().exclude("third", "one", "t2"); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); EXPECT_TRIGGERS(cache, "first", "one", {}); EXPECT_TRIGGERS(cache, "first", "two", {}); EXPECT_TRIGGERS(cache, "second", "one", {}); EXPECT_TRIGGERS(cache, "second", "two", {}); EXPECT_TRIGGERS(cache, "third", "one", {"t1"}); EXPECT_TRIGGERS(cache, "third", "two", {}); } } TEST_F(Instance_cache_test, stats) { { // setup // schemas m_session->execute("CREATE SCHEMA first;"); m_session->execute("CREATE SCHEMA second;"); m_session->execute("CREATE SCHEMA third;"); // tables m_session->execute("CREATE TABLE first.one (id INT);"); m_session->execute("CREATE TABLE first.two (id INT);"); m_session->execute("CREATE TABLE second.one (id INT);"); m_session->execute("CREATE TABLE second.two (id INT);"); m_session->execute("CREATE TABLE third.one (id INT);"); m_session->execute("CREATE TABLE third.two (id INT);"); // views m_session->execute("CREATE VIEW first.three AS SELECT * FROM first.one;"); m_session->execute("CREATE VIEW second.three AS SELECT * FROM second.one;"); m_session->execute("CREATE VIEW third.three AS SELECT * FROM third.one;"); // events m_session->execute( "CREATE EVENT first.one ON SCHEDULE EVERY 1 YEAR DO SELECT 1;"); m_session->execute( "CREATE EVENT first.two ON SCHEDULE EVERY 1 YEAR DO SELECT 1;"); m_session->execute( "CREATE EVENT second.one ON SCHEDULE EVERY 1 YEAR DO SELECT 1;"); m_session->execute( "CREATE EVENT second.two ON SCHEDULE EVERY 1 YEAR DO SELECT 1;"); m_session->execute( "CREATE EVENT third.one ON SCHEDULE EVERY 1 YEAR DO SELECT 1;"); m_session->execute( "CREATE EVENT third.two ON SCHEDULE EVERY 1 YEAR DO SELECT 1;"); // routines m_session->execute( "CREATE FUNCTION first.one() RETURNS INT DETERMINISTIC RETURN 1;"); m_session->execute("CREATE PROCEDURE first.two() DETERMINISTIC BEGIN END;"); m_session->execute( "CREATE PROCEDURE second.one() DETERMINISTIC BEGIN END;"); m_session->execute( "CREATE FUNCTION second.two() RETURNS INT DETERMINISTIC RETURN 1;"); m_session->execute( "CREATE FUNCTION third.one() RETURNS INT DETERMINISTIC RETURN 1;"); m_session->execute("CREATE PROCEDURE third.two() DETERMINISTIC BEGIN END;"); // triggers m_session->execute( "CREATE TRIGGER first.t1 AFTER DELETE ON first.one FOR EACH ROW BEGIN " "END;"); m_session->execute( "CREATE TRIGGER first.t2 AFTER DELETE ON first.one FOR EACH ROW BEGIN " "END;"); m_session->execute( "CREATE TRIGGER first.t3 AFTER DELETE ON first.two FOR EACH ROW BEGIN " "END;"); m_session->execute( "CREATE TRIGGER first.t4 AFTER DELETE ON first.two FOR EACH ROW BEGIN " "END;"); m_session->execute( "CREATE TRIGGER second.t1 AFTER DELETE ON second.one FOR EACH ROW " "BEGIN END;"); m_session->execute( "CREATE TRIGGER second.t2 AFTER DELETE ON second.one FOR EACH ROW " "BEGIN END;"); m_session->execute( "CREATE TRIGGER second.t3 AFTER DELETE ON second.two FOR EACH ROW " "BEGIN END;"); m_session->execute( "CREATE TRIGGER second.t4 AFTER DELETE ON second.two FOR EACH ROW " "BEGIN END;"); m_session->execute( "CREATE TRIGGER third.t1 AFTER DELETE ON third.one FOR EACH ROW BEGIN " "END;"); m_session->execute( "CREATE TRIGGER third.t2 AFTER DELETE ON third.one FOR EACH ROW BEGIN " "END;"); m_session->execute( "CREATE TRIGGER third.t3 AFTER DELETE ON third.two FOR EACH ROW BEGIN " "END;"); m_session->execute( "CREATE TRIGGER third.t4 AFTER DELETE ON third.two FOR EACH ROW BEGIN " "END;"); // users m_session->execute("CREATE USER first;"); m_session->execute("CREATE USER second;"); m_session->execute("CREATE USER third;"); } const auto total_count = [this](const std::string &table, const std::string &where = {}, const std::string &column = "*") { auto sql = "SELECT COUNT(" + column + ") FROM information_schema." + table; if (!where.empty()) { sql += " WHERE " + where; } return m_session->query(sql)->fetch_one()->get_uint(0); }; Instance_cache::Stats expected_total; expected_total.schemas = total_count("schemata"); expected_total.tables = total_count("tables", "'BASE TABLE'=TABLE_TYPE"); expected_total.views = total_count("tables", "'VIEW'=TABLE_TYPE"); const auto total_users = total_count("user_privileges", {}, "DISTINCT grantee"); const auto EXPECT_STATS = [](const Instance_cache::Stats &expected, const Instance_cache::Stats &actual) { EXPECT_EQ(expected.schemas, actual.schemas); EXPECT_EQ(expected.tables, actual.tables); EXPECT_EQ(expected.views, actual.views); EXPECT_EQ(expected.events, actual.events); EXPECT_EQ(expected.routines, actual.routines); EXPECT_EQ(expected.triggers, actual.triggers); EXPECT_EQ(expected.users, actual.users); }; { SCOPED_TRACE("no filters - schemas and tables"); Filtering_options filters; const auto cache = Instance_cache_builder(m_session, filters).build(); EXPECT_STATS(expected_total, cache.total); EXPECT_STATS(expected_total, cache.filtered); } { SCOPED_TRACE("no filters - schemas, tables and events"); Filtering_options filters; const auto cache = Instance_cache_builder(m_session, filters).events().build(); expected_total.events = total_count("events"); expected_total.routines = 0; expected_total.triggers = 0; expected_total.users = 0; EXPECT_STATS(expected_total, cache.total); EXPECT_STATS(expected_total, cache.filtered); } { SCOPED_TRACE("no filters - schemas, tables and routines"); Filtering_options filters; const auto cache = Instance_cache_builder(m_session, filters).routines().build(); expected_total.events = 0; expected_total.routines = total_count("routines"); expected_total.triggers = 0; expected_total.users = 0; EXPECT_STATS(expected_total, cache.total); EXPECT_STATS(expected_total, cache.filtered); } { SCOPED_TRACE("no filters - schemas, tables and triggers"); Filtering_options filters; const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); expected_total.events = 0; expected_total.routines = 0; expected_total.triggers = total_count("triggers"); expected_total.users = 0; EXPECT_STATS(expected_total, cache.total); EXPECT_STATS(expected_total, cache.filtered); } { SCOPED_TRACE("no filters - schemas, tables and users"); Filtering_options filters; const auto cache = Instance_cache_builder(m_session, filters).users().build(); expected_total.events = 0; expected_total.routines = 0; expected_total.triggers = 0; expected_total.users = total_users; EXPECT_STATS(expected_total, cache.total); EXPECT_STATS(expected_total, cache.filtered); } { SCOPED_TRACE("filter users"); Filtering_options filters; filters.users().include( std::array{"'first'@'%'", "'second'@'%'", "'third'@'%'"}); const auto cache = Instance_cache_builder(m_session, filters).users().build(); expected_total.events = 0; expected_total.routines = 0; expected_total.triggers = 0; expected_total.users = total_users; EXPECT_STATS(expected_total, cache.total); expected_total.users = 3; EXPECT_STATS(expected_total, cache.filtered); } { SCOPED_TRACE("filter schemas + all tables"); Filtering_options filters; filters.schemas().include(std::array{"first", "second", "third"}); const auto cache = Instance_cache_builder(m_session, filters).build(); expected_total.tables = 6; expected_total.views = 3; expected_total.events = 0; expected_total.routines = 0; expected_total.triggers = 0; expected_total.users = 0; EXPECT_STATS(expected_total, cache.total); EXPECT_STATS({3, 6, 3}, cache.filtered); } { SCOPED_TRACE("filter schemas + filtered tables"); Filtering_options filters; filters.schemas().include(std::array{"first", "second", "third"}); filters.tables().include("first", std::array{"one", "three"}); filters.tables().include("third", "two"); const auto cache = Instance_cache_builder(m_session, filters).build(); expected_total.tables = 6; expected_total.views = 3; expected_total.events = 0; expected_total.routines = 0; expected_total.triggers = 0; expected_total.users = 0; EXPECT_STATS(expected_total, cache.total); EXPECT_STATS({3, 2, 1}, cache.filtered); } { SCOPED_TRACE("filter schemas + all events"); Filtering_options filters; filters.schemas().include(std::array{"first", "second", "third"}); const auto cache = Instance_cache_builder(m_session, filters).events().build(); expected_total.tables = 6; expected_total.views = 3; expected_total.events = 6; expected_total.routines = 0; expected_total.triggers = 0; expected_total.users = 0; EXPECT_STATS(expected_total, cache.total); EXPECT_STATS({3, 6, 3, 6}, cache.filtered); } { SCOPED_TRACE("filter schemas + filtered events"); Filtering_options filters; filters.schemas().include(std::array{"first", "second", "third"}); filters.events().include("first", "one"); filters.events().include("third", "two"); const auto cache = Instance_cache_builder(m_session, filters).events().build(); expected_total.tables = 6; expected_total.views = 3; expected_total.events = 6; expected_total.routines = 0; expected_total.triggers = 0; expected_total.users = 0; EXPECT_STATS(expected_total, cache.total); EXPECT_STATS({3, 6, 3, 2}, cache.filtered); } { SCOPED_TRACE("filter schemas + all routines"); Filtering_options filters; filters.schemas().include(std::array{"first", "second", "third"}); const auto cache = Instance_cache_builder(m_session, filters).routines().build(); expected_total.tables = 6; expected_total.views = 3; expected_total.events = 0; expected_total.routines = 6; expected_total.triggers = 0; expected_total.users = 0; EXPECT_STATS(expected_total, cache.total); EXPECT_STATS({3, 6, 3, 0, 6}, cache.filtered); } { SCOPED_TRACE("filter schemas + filtered routines"); Filtering_options filters; filters.schemas().include(std::array{"first", "second", "third"}); filters.routines().include("first", "one"); filters.routines().include("third", "two"); const auto cache = Instance_cache_builder(m_session, filters).routines().build(); expected_total.tables = 6; expected_total.views = 3; expected_total.events = 0; expected_total.routines = 6; expected_total.triggers = 0; expected_total.users = 0; EXPECT_STATS(expected_total, cache.total); EXPECT_STATS({3, 6, 3, 0, 2}, cache.filtered); } { SCOPED_TRACE("filter schemas + all triggers"); Filtering_options filters; filters.schemas().include(std::array{"first", "second", "third"}); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); expected_total.tables = 6; expected_total.views = 3; expected_total.events = 0; expected_total.routines = 0; expected_total.triggers = 12; expected_total.users = 0; EXPECT_STATS(expected_total, cache.total); EXPECT_STATS({3, 6, 3, 0, 0, 12}, cache.filtered); } { SCOPED_TRACE("filter schemas + filtered triggers"); Filtering_options filters; filters.schemas().include(std::array{"first", "second", "third"}); filters.triggers().include("first", "one", "t1"); filters.triggers().include("second", "two", "t3"); filters.triggers().include("third", "one", ""); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); expected_total.tables = 6; expected_total.views = 3; expected_total.events = 0; expected_total.routines = 0; expected_total.triggers = 12; expected_total.users = 0; EXPECT_STATS(expected_total, cache.total); EXPECT_STATS({3, 6, 3, 0, 0, 4}, cache.filtered); } { SCOPED_TRACE("filter schemas + filtered tables + all triggers"); Filtering_options filters; filters.schemas().include(std::array{"first", "second", "third"}); filters.tables().include("first", std::array{"one", "three"}); filters.tables().include("third", "two"); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); expected_total.tables = 6; expected_total.views = 3; expected_total.events = 0; expected_total.routines = 0; expected_total.triggers = 4; expected_total.users = 0; EXPECT_STATS(expected_total, cache.total); EXPECT_STATS({3, 2, 1, 0, 0, 4}, cache.filtered); } { SCOPED_TRACE("filter schemas + filtered tables + filtered triggers"); Filtering_options filters; filters.schemas().include(std::array{"first", "second", "third"}); filters.tables().include("first", std::array{"one", "three"}); filters.tables().include("third", "two"); filters.triggers().include("first", "one", "t1"); filters.triggers().include("third", "two", "t3"); const auto cache = Instance_cache_builder(m_session, filters).triggers().build(); expected_total.tables = 6; expected_total.views = 3; expected_total.events = 0; expected_total.routines = 0; expected_total.triggers = 4; expected_total.users = 0; EXPECT_STATS(expected_total, cache.total); EXPECT_STATS({3, 2, 1, 0, 0, 2}, cache.filtered); } } } // namespace tests } // namespace dump } // namespace mysqlsh