From c4b82b7d8397ebd0f4b8d9d8ed3df566dfc308b0 Mon Sep 17 00:00:00 2001 From: Esa Korhonen Date: Tue, 26 Mar 2019 14:19:57 +0200 Subject: [PATCH] MXS-2359 Route statements with database but no table dependence Queries such as SHOW TABLES FROM db1 are now routed to the backend with db1. This gives the correct result as long as db1 is not sharded to multiple backends. --- Documentation/Routers/SchemaRouter.md | 8 ++- .../schemarouter/schemaroutersession.cc | 56 ++++++++++++------- 2 files changed, 43 insertions(+), 21 deletions(-) diff --git a/Documentation/Routers/SchemaRouter.md b/Documentation/Routers/SchemaRouter.md index 6efc167c6..51872ad08 100644 --- a/Documentation/Routers/SchemaRouter.md +++ b/Documentation/Routers/SchemaRouter.md @@ -233,8 +233,12 @@ answers correctly to the basic version of the query. Any modifiers such as `LIKE ignored. * `SHOW TABLES` is routed to the server with the current database. If using table-level -sharding, the results will be incomplete. Use `SHOW SHARDS` to get results from the router -itself. +sharding, the results will be incomplete. Similarly, `SHOW TABLES FROM db1` is routed to +the server with database `db1`, ignoring table sharding. Use `SHOW SHARDS` to get results +from the router itself. + +* `USE db1` is routed to the server with `db1`. If the database is divided to multiple +servers, only one server will get the command. ## Examples diff --git a/server/modules/routing/schemarouter/schemaroutersession.cc b/server/modules/routing/schemarouter/schemaroutersession.cc index a7c7ecb92..4b7bfa1d8 100644 --- a/server/modules/routing/schemarouter/schemaroutersession.cc +++ b/server/modules/routing/schemarouter/schemaroutersession.cc @@ -1630,41 +1630,59 @@ SERVER* SchemaRouterSession::get_query_target(GWBUF* buffer) int n_databases = 0; char** databases = qc_get_database_names(buffer, &n_databases); - for (int i = 0; i < n_databases; i++) + if (n_databases > 0) { - for (int j = 0; j < n_tables; j++) + // Prefer to select the route target by table. If no tables, route by database. + if (n_tables) { - SERVER* target = m_shard.get_location(tables[j]); - - if (target) + for (int i = 0; i < n_tables; i++) { - - if (rval && target != rval) + SERVER* target = m_shard.get_location(tables[i]); + if (target) { - MXS_ERROR("Query targets tables on servers '%s' and '%s'. " - "Cross server queries are not supported.", - rval->name, - target->name); - } - else if (rval == NULL) - { - rval = target; - MXS_INFO("Query targets table '%s' on server '%s'", - tables[j], - rval->name); + if (rval && target != rval) + { + MXS_ERROR("Query targets tables on servers '%s' and '%s'. " + "Cross server queries are not supported.", + rval->name, target->name); + } + else if (rval == NULL) + { + rval = target; + MXS_INFO("Query targets table '%s' on server '%s'", tables[i], rval->name); + } } } } + else if (rval == nullptr) + { + // Queries which target a database but no tables can have multiple targets. Select first one. + for (int i = 0; i < n_databases; i++) + { + SERVER* target = m_shard.get_location(databases[i]); + if (target) + { + rval = target; + break; + } + } + } + } + + // Free the databases and tables arrays. + for (int i = 0; i < n_databases; i++) + { MXS_FREE(databases[i]); } + MXS_FREE(databases); for (int i = 0; i < n_tables; i++) { MXS_FREE(tables[i]); } MXS_FREE(tables); - MXS_FREE(databases); + return rval; }