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