Merge pull request #39674 from tonickkozlov/tonickkozlov/fix-default-database-resolution

Default database resolution in distributed reads
This commit is contained in:
Alexander Tokmakov 2022-08-05 13:09:15 +03:00 committed by GitHub
commit 65e1ce8ad1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 110 additions and 2 deletions

View File

@ -759,7 +759,22 @@ void TCPHandler::processTablesStatusRequest()
TablesStatusRequest request;
request.read(*in, client_tcp_protocol_version);
ContextPtr context_to_resolve_table_names = (session && session->sessionContext()) ? session->sessionContext() : server.context();
ContextPtr context_to_resolve_table_names;
if (is_interserver_mode)
{
/// In interserver mode session context does not exists, because authentication is done for each query.
/// We also cannot create query context earlier, because it cannot be created before authentication,
/// but query is not received yet. So we have to do this trick.
ContextMutablePtr fake_interserver_context = Context::createCopy(server.context());
if (!default_database.empty())
fake_interserver_context->setCurrentDatabase(default_database);
context_to_resolve_table_names = fake_interserver_context;
}
else
{
assert(session);
context_to_resolve_table_names = session->sessionContext();
}
TablesStatusResponse response;
for (const QualifiedTableName & table_name: request.tables)
@ -1354,7 +1369,7 @@ void TCPHandler::receiveQuery()
query_context = session->makeQueryContext(std::move(client_info));
/// Sets the default database if it wasn't set earlier for the session context.
if (!default_database.empty() && !session->sessionContext())
if (is_interserver_mode && !default_database.empty())
query_context->setCurrentDatabase(default_database);
if (state.part_uuids_to_ignore)

View File

@ -0,0 +1,18 @@
<clickhouse>
<remote_servers>
<secure>
<secret>foo</secret>
<node>
<host>node1</host>
<port>9000</port>
<default_database>r0</default_database>
</node>
<node>
<host>node2</host>
<port>9000</port>
<default_database>r1</default_database>
</node>
</secure>
</remote_servers>
</clickhouse>

View File

@ -0,0 +1,24 @@
<?xml version="1.0"?>
<clickhouse>
<profiles>
<default>
<prefer_localhost_replica>false</prefer_localhost_replica>
</default>
</profiles>
<users>
<default>
<password></password>
<networks>
<ip>::/0</ip>
</networks>
<profile>default</profile>
<quota>default</quota>
</default>
</users>
<quotas>
<default>
</default>
</quotas>
</clickhouse>

View File

@ -0,0 +1,51 @@
"""
This test is similar to test_cross_replication, except
in this test we write into per-node tables and read from the distributed table.
The default database in the distributed table definition is left empty on purpose to test
default database deduction.
"""
import pytest
from helpers.client import QueryRuntimeException
from helpers.cluster import ClickHouseCluster
from helpers.test_tools import TSV
from contextlib import contextmanager
def bootstrap(cluster):
for i, node in enumerate(list(cluster.instances.values())):
node.query(f"CREATE DATABASE IF NOT EXISTS r{i}")
node.query(f"CREATE TABLE r{i}.test_data(v UInt64) ENGINE = Memory()")
node.query(f"INSERT INTO r{i}.test_data SELECT * FROM numbers(10)")
node.query(
f"""CREATE TABLE default.test AS r{i}.test_data ENGINE = Distributed(secure, '', test_data, rand())"""
)
@contextmanager
def start_cluster():
cluster_disabled = ClickHouseCluster(__file__)
cluster_disabled.add_instance(
"node1",
main_configs=["configs/remote_servers.xml"],
user_configs=["configs/users.xml"],
)
cluster_disabled.add_instance(
"node2",
main_configs=["configs/remote_servers.xml"],
user_configs=["configs/users.xml"],
)
try:
cluster_disabled.start()
bootstrap(cluster_disabled)
yield cluster_disabled
finally:
cluster_disabled.shutdown()
def test_query():
with start_cluster() as cluster:
node1 = cluster.instances["node1"]
assert TSV(node1.query("SELECT count() FROM default.test")) == TSV("20")