mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 15:12:02 +00:00
Add converting step for 'join using'
This commit is contained in:
parent
4650dcdbb0
commit
4c36cd1737
2
contrib/hyperscan
vendored
2
contrib/hyperscan
vendored
@ -1 +1 @@
|
||||
Subproject commit e9f08df0213fc637aac0a5bbde9beeaeba2fe9fa
|
||||
Subproject commit 3907fd00ee8b2538739768fa9533f8635a276531
|
@ -42,14 +42,13 @@
|
||||
|
||||
#include <DataTypes/DataTypeFactory.h>
|
||||
#include <Parsers/parseQuery.h>
|
||||
#include <Interpreters/interpretSubquery.h>
|
||||
#include <Interpreters/DatabaseAndTableWithAlias.h>
|
||||
#include <Interpreters/misc.h>
|
||||
|
||||
#include <Interpreters/ActionsVisitor.h>
|
||||
|
||||
#include <Interpreters/GlobalSubqueriesVisitor.h>
|
||||
#include <Interpreters/GetAggregatesVisitor.h>
|
||||
#include <Interpreters/GlobalSubqueriesVisitor.h>
|
||||
#include <Interpreters/interpretSubquery.h>
|
||||
#include <Interpreters/join_common.h>
|
||||
#include <Interpreters/misc.h>
|
||||
|
||||
#include <IO/Operators.h>
|
||||
#include <IO/WriteBufferFromString.h>
|
||||
@ -714,23 +713,32 @@ ArrayJoinActionPtr SelectQueryExpressionAnalyzer::appendArrayJoin(ExpressionActi
|
||||
return array_join;
|
||||
}
|
||||
|
||||
bool SelectQueryExpressionAnalyzer::appendJoinLeftKeys(ExpressionActionsChain & chain, bool only_types)
|
||||
bool SelectQueryExpressionAnalyzer::appendJoinLeftKeys(ExpressionActionsChain & chain, bool only_types, Block & block)
|
||||
{
|
||||
ExpressionActionsChain::Step & step = chain.lastStep(columns_after_array_join);
|
||||
|
||||
getRootActions(analyzedJoin().leftKeysList(), only_types, step.actions());
|
||||
ExpressionActionsPtr actions = std::make_shared<ExpressionActions>(step.actions());
|
||||
actions->execute(block);
|
||||
return true;
|
||||
}
|
||||
|
||||
JoinPtr SelectQueryExpressionAnalyzer::appendJoin(ExpressionActionsChain & chain)
|
||||
JoinPtr
|
||||
SelectQueryExpressionAnalyzer::appendJoin(ExpressionActionsChain & chain, const Block & sample_block, ActionsDAGPtr & before_join_dag)
|
||||
{
|
||||
JoinPtr table_join = makeTableJoin(*syntax->ast_join);
|
||||
JoinCommon::JoinConvertActions converting_actions;
|
||||
JoinPtr table_join = makeTableJoin(*syntax->ast_join, sample_block, converting_actions);
|
||||
|
||||
if (converting_actions.first)
|
||||
{
|
||||
before_join_dag = ActionsDAG::merge(std::move(*before_join_dag->clone()), std::move(*converting_actions.first->clone()));
|
||||
|
||||
chain.steps.push_back(std::make_unique<ExpressionActionsChain::ExpressionActionsStep>(converting_actions.first));
|
||||
chain.addStep();
|
||||
}
|
||||
|
||||
ExpressionActionsChain::Step & step = chain.lastStep(columns_after_array_join);
|
||||
|
||||
chain.steps.push_back(std::make_unique<ExpressionActionsChain::JoinStep>(
|
||||
syntax->analyzed_join, table_join, step.getResultColumns()));
|
||||
|
||||
chain.steps.push_back(std::make_unique<ExpressionActionsChain::JoinStep>(syntax->analyzed_join, table_join, step.getResultColumns()));
|
||||
chain.addStep();
|
||||
return table_join;
|
||||
}
|
||||
@ -795,7 +803,9 @@ static std::shared_ptr<IJoin> makeJoin(std::shared_ptr<TableJoin> analyzed_join,
|
||||
return std::make_shared<JoinSwitcher>(analyzed_join, sample_block);
|
||||
}
|
||||
|
||||
JoinPtr SelectQueryExpressionAnalyzer::makeTableJoin(const ASTTablesInSelectQueryElement & join_element)
|
||||
JoinPtr SelectQueryExpressionAnalyzer::makeTableJoin(const ASTTablesInSelectQueryElement & join_element,
|
||||
const Block & left_sample_block,
|
||||
JoinCommon::JoinConvertActions & converting_actions)
|
||||
{
|
||||
/// Two JOINs are not supported with the same subquery, but different USINGs.
|
||||
auto join_hash = join_element.getTreeHash();
|
||||
@ -831,7 +841,17 @@ JoinPtr SelectQueryExpressionAnalyzer::makeTableJoin(const ASTTablesInSelectQuer
|
||||
}
|
||||
|
||||
/// TODO You do not need to set this up when JOIN is only needed on remote servers.
|
||||
subquery_for_join.setJoinActions(joined_block_actions); /// changes subquery_for_join.sample_block inside
|
||||
subquery_for_join.addJoinActions(joined_block_actions); /// changes subquery_for_join.sample_block inside
|
||||
|
||||
const Block & right_sample_block = subquery_for_join.sample_block;
|
||||
bool has_using = syntax->analyzed_join->hasUsing();
|
||||
converting_actions = JoinCommon::columnsNeedConvert(
|
||||
left_sample_block, syntax->analyzed_join->keyNamesLeft(),
|
||||
right_sample_block, syntax->analyzed_join->keyNamesRight(),
|
||||
has_using);
|
||||
if (converting_actions.second)
|
||||
subquery_for_join.addJoinActions(std::make_shared<ExpressionActions>(converting_actions.second));
|
||||
|
||||
subquery_for_join.join = makeJoin(syntax->analyzed_join, subquery_for_join.sample_block, context);
|
||||
|
||||
/// Do not make subquery for join over dictionary.
|
||||
@ -1425,10 +1445,10 @@ ExpressionAnalysisResult::ExpressionAnalysisResult(
|
||||
|
||||
if (query_analyzer.hasTableJoin())
|
||||
{
|
||||
query_analyzer.appendJoinLeftKeys(chain, only_types || !first_stage);
|
||||
|
||||
Block left_block_sample = source_header;
|
||||
query_analyzer.appendJoinLeftKeys(chain, only_types || !first_stage, left_block_sample);
|
||||
before_join = chain.getLastActions();
|
||||
join = query_analyzer.appendJoin(chain);
|
||||
join = query_analyzer.appendJoin(chain, left_block_sample, before_join);
|
||||
chain.addStep();
|
||||
}
|
||||
|
||||
|
@ -1,15 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <DataStreams/IBlockStream_fwd.h>
|
||||
#include <Columns/FilterDescription.h>
|
||||
#include <DataStreams/IBlockStream_fwd.h>
|
||||
#include <Interpreters/AggregateDescription.h>
|
||||
#include <Interpreters/WindowDescription.h>
|
||||
#include <Interpreters/TreeRewriter.h>
|
||||
#include <Interpreters/DatabaseCatalog.h>
|
||||
#include <Interpreters/SubqueryForSet.h>
|
||||
#include <Interpreters/TreeRewriter.h>
|
||||
#include <Interpreters/join_common.h>
|
||||
#include <Parsers/IAST_fwd.h>
|
||||
#include <Storages/IStorage_fwd.h>
|
||||
#include <Storages/SelectQueryInfo.h>
|
||||
#include <Interpreters/DatabaseCatalog.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
@ -313,7 +315,8 @@ private:
|
||||
/// Create Set-s that we make from IN section to use index on them.
|
||||
void makeSetsForIndex(const ASTPtr & node);
|
||||
|
||||
JoinPtr makeTableJoin(const ASTTablesInSelectQueryElement & join_element);
|
||||
JoinPtr makeTableJoin(const ASTTablesInSelectQueryElement & join_element, const Block & left_sample_block,
|
||||
JoinCommon::JoinConvertActions & converting_actions);
|
||||
|
||||
const ASTSelectQuery * getAggregatingQuery() const;
|
||||
|
||||
@ -333,8 +336,8 @@ private:
|
||||
|
||||
/// Before aggregation:
|
||||
ArrayJoinActionPtr appendArrayJoin(ExpressionActionsChain & chain, ActionsDAGPtr & before_array_join, bool only_types);
|
||||
bool appendJoinLeftKeys(ExpressionActionsChain & chain, bool only_types);
|
||||
JoinPtr appendJoin(ExpressionActionsChain & chain);
|
||||
bool appendJoinLeftKeys(ExpressionActionsChain & chain, bool only_types, Block & block);
|
||||
JoinPtr appendJoin(ExpressionActionsChain & chain, const Block & sample_block, ActionsDAGPtr & before_join_dag);
|
||||
/// Add preliminary rows filtration. Actions are created in other expression analyzer to prevent any possible alias injection.
|
||||
void appendPreliminaryFilter(ExpressionActionsChain & chain, ActionsDAGPtr actions_dag, String column_name);
|
||||
/// remove_filter is set in ExpressionActionsChain::finalize();
|
||||
|
@ -994,12 +994,8 @@ void InterpreterSelectQuery::executeImpl(QueryPlan & query_plan, const BlockInpu
|
||||
|
||||
if (expressions.hasJoin())
|
||||
{
|
||||
Block join_result_sample;
|
||||
JoinPtr join = expressions.join;
|
||||
|
||||
join_result_sample = JoiningTransform::transformHeader(
|
||||
query_plan.getCurrentDataStream().header, expressions.join);
|
||||
|
||||
QueryPlanStepPtr join_step = std::make_unique<JoinStep>(
|
||||
query_plan.getCurrentDataStream(),
|
||||
expressions.join);
|
||||
@ -1009,6 +1005,7 @@ void InterpreterSelectQuery::executeImpl(QueryPlan & query_plan, const BlockInpu
|
||||
|
||||
if (expressions.join_has_delayed_stream)
|
||||
{
|
||||
const Block & join_result_sample = query_plan.getCurrentDataStream().header;
|
||||
auto stream = std::make_shared<LazyNonJoinedBlockInputStream>(*join, join_result_sample, settings.max_block_size);
|
||||
auto source = std::make_shared<SourceFromInputStream>(std::move(stream));
|
||||
auto add_non_joined_rows_step = std::make_unique<AddingDelayedSourceStep>(
|
||||
|
@ -39,10 +39,20 @@ void SubqueryForSet::renameColumns(Block & block)
|
||||
}
|
||||
}
|
||||
|
||||
void SubqueryForSet::setJoinActions(ExpressionActionsPtr actions)
|
||||
void SubqueryForSet::addJoinActions(ExpressionActionsPtr actions)
|
||||
{
|
||||
actions->execute(sample_block);
|
||||
joined_block_actions = actions;
|
||||
if (joined_block_actions == nullptr)
|
||||
{
|
||||
joined_block_actions = actions;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto new_dag = ActionsDAG::merge(
|
||||
std::move(*joined_block_actions->getActionsDAG().clone()),
|
||||
std::move(*actions->getActionsDAG().clone()));
|
||||
joined_block_actions = std::make_shared<ExpressionActions>(new_dag);
|
||||
}
|
||||
}
|
||||
|
||||
bool SubqueryForSet::insertJoinedBlock(Block & block)
|
||||
|
@ -40,7 +40,7 @@ struct SubqueryForSet
|
||||
void makeSource(std::shared_ptr<InterpreterSelectWithUnionQuery> & interpreter,
|
||||
NamesWithAliases && joined_block_aliases_);
|
||||
|
||||
void setJoinActions(ExpressionActionsPtr actions);
|
||||
void addJoinActions(ExpressionActionsPtr actions);
|
||||
|
||||
bool insertJoinedBlock(Block & block);
|
||||
void setTotals(Block totals);
|
||||
|
@ -1,9 +1,11 @@
|
||||
#include <Interpreters/join_common.h>
|
||||
#include <Interpreters/TableJoin.h>
|
||||
#include <Interpreters/ActionsDAG.h>
|
||||
#include <Columns/ColumnNullable.h>
|
||||
#include <Columns/ColumnLowCardinality.h>
|
||||
#include <DataTypes/DataTypeNullable.h>
|
||||
#include <DataTypes/DataTypeLowCardinality.h>
|
||||
#include <DataTypes/getLeastSupertype.h>
|
||||
#include <DataStreams/materializeBlock.h>
|
||||
#include <IO/WriteHelpers.h>
|
||||
|
||||
@ -283,6 +285,82 @@ void addDefaultValues(IColumn & column, const DataTypePtr & type, size_t count)
|
||||
type->insertDefaultInto(column);
|
||||
}
|
||||
|
||||
bool typesEqualUpToNullability(DataTypePtr left_type, DataTypePtr right_type)
|
||||
{
|
||||
DataTypePtr left_type_strict = removeNullable(recursiveRemoveLowCardinality(left_type));
|
||||
DataTypePtr right_type_strict = removeNullable(recursiveRemoveLowCardinality(right_type));
|
||||
return left_type_strict->equals(*right_type_strict);
|
||||
}
|
||||
|
||||
JoinConvertActions columnsNeedConvert(const Block & left_block, const Names & left_keys,
|
||||
const Block & right_block, const Names & right_keys,
|
||||
bool has_using)
|
||||
{
|
||||
assert(left_keys.size() == right_keys.size());
|
||||
|
||||
/// only JOIN USING supported
|
||||
if (!has_using)
|
||||
return {};
|
||||
|
||||
Block left_block_dst = left_block;
|
||||
Block right_block_dst = right_block;
|
||||
|
||||
std::unordered_set<std::string_view> visited_left;
|
||||
std::unordered_set<std::string_view> visited_right;
|
||||
bool any_need_cast = false;
|
||||
for (size_t i = 0; i < left_keys.size(); ++i)
|
||||
{
|
||||
if (visited_left.contains(left_keys[i]) || visited_right.contains(right_keys[i]))
|
||||
{
|
||||
/// if one column joined with multiple different others do not perform conversion
|
||||
/// e.g. `JOIN ... ON t1.a == t2.a AND t1.a == t2.b`
|
||||
return {};
|
||||
}
|
||||
visited_left.insert(left_keys[i]);
|
||||
visited_right.insert(right_keys[i]);
|
||||
|
||||
DataTypePtr ltype = left_block.getByName(left_keys[i]).type;
|
||||
DataTypePtr rtype = right_block.getByName(right_keys[i]).type;
|
||||
|
||||
if (typesEqualUpToNullability(ltype, rtype))
|
||||
continue;
|
||||
|
||||
any_need_cast = true;
|
||||
DataTypePtr supertype;
|
||||
try
|
||||
{
|
||||
supertype = DB::getLeastSupertype({ltype, rtype});
|
||||
}
|
||||
catch (DB::Exception &)
|
||||
{
|
||||
throw Exception("Type mismatch of columns to JOIN by: "
|
||||
+ left_keys[i] + ": " + ltype->getName() + " at left, "
|
||||
+ right_keys[i] + ": " + rtype->getName() + " at right",
|
||||
ErrorCodes::TYPE_MISMATCH);
|
||||
}
|
||||
auto & lcol_dst = left_block_dst.getByName(left_keys[i]);
|
||||
auto & rcol_dst = right_block_dst.getByName(right_keys[i]);
|
||||
lcol_dst.column = rcol_dst.column = nullptr;
|
||||
lcol_dst.type = rcol_dst.type = supertype;
|
||||
}
|
||||
|
||||
if (!any_need_cast)
|
||||
return {};
|
||||
|
||||
auto convert_left_actions_dag = ActionsDAG::makeConvertingActions(
|
||||
left_block.getColumnsWithTypeAndName(),
|
||||
left_block_dst.getColumnsWithTypeAndName(),
|
||||
ActionsDAG::MatchColumnsMode::Name,
|
||||
true);
|
||||
auto convert_right_actions_dag = ActionsDAG::makeConvertingActions(
|
||||
right_block.getColumnsWithTypeAndName(),
|
||||
right_block_dst.getColumnsWithTypeAndName(),
|
||||
ActionsDAG::MatchColumnsMode::Name,
|
||||
true);
|
||||
|
||||
return std::make_pair(convert_left_actions_dag, convert_right_actions_dag);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
#include <Core/Block.h>
|
||||
#include <Interpreters/IJoin.h>
|
||||
#include <Interpreters/ActionsDAG.h>
|
||||
#include <Interpreters/ExpressionActions.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
@ -14,6 +16,8 @@ using ColumnRawPtrs = std::vector<const IColumn *>;
|
||||
namespace JoinCommon
|
||||
{
|
||||
|
||||
using JoinConvertActions = std::pair<ActionsDAGPtr, ActionsDAGPtr>;
|
||||
|
||||
void convertColumnToNullable(ColumnWithTypeAndName & column, bool low_card_nullability = false);
|
||||
void convertColumnsToNullable(Block & block, size_t starting_pos = 0);
|
||||
void removeColumnNullability(ColumnWithTypeAndName & column);
|
||||
@ -36,6 +40,9 @@ void joinTotals(const Block & totals, const Block & columns_to_add, const Names
|
||||
|
||||
void addDefaultValues(IColumn & column, const DataTypePtr & type, size_t count);
|
||||
|
||||
JoinConvertActions columnsNeedConvert(const Block & left_block, const Names & left_keys,
|
||||
const Block & right_block, const Names & right_keys,
|
||||
bool has_using);
|
||||
}
|
||||
|
||||
/// Creates result from right table data in RIGHT and FULL JOIN when keys are not present in left table.
|
||||
|
236
tests/queries/0_stateless/01674_join_implicit_cast.reference
Normal file
236
tests/queries/0_stateless/01674_join_implicit_cast.reference
Normal file
@ -0,0 +1,236 @@
|
||||
--- hash ---
|
||||
- full -
|
||||
-4 0 196
|
||||
-3 0 197
|
||||
-2 0 198
|
||||
-1 0 199
|
||||
0 0 200
|
||||
1 101 201
|
||||
2 102 202
|
||||
3 103 203
|
||||
4 104 204
|
||||
5 105 205
|
||||
6 106 \N
|
||||
7 107 \N
|
||||
8 108 \N
|
||||
9 109 \N
|
||||
10 110 \N
|
||||
- left -
|
||||
1 101 201
|
||||
2 102 202
|
||||
3 103 203
|
||||
4 104 204
|
||||
5 105 205
|
||||
6 106 \N
|
||||
7 107 \N
|
||||
8 108 \N
|
||||
9 109 \N
|
||||
10 110 \N
|
||||
- right -
|
||||
-4 0 196
|
||||
-3 0 197
|
||||
-2 0 198
|
||||
-1 0 199
|
||||
0 0 200
|
||||
1 101 201
|
||||
2 102 202
|
||||
3 103 203
|
||||
4 104 204
|
||||
5 105 205
|
||||
- inner -
|
||||
1 101 201
|
||||
2 102 202
|
||||
3 103 203
|
||||
4 104 204
|
||||
5 105 205
|
||||
- full -
|
||||
0 0 -4
|
||||
0 0 -3
|
||||
0 0 -2
|
||||
0 0 -1
|
||||
0 0 0
|
||||
1 1 1
|
||||
2 2 2
|
||||
3 3 3
|
||||
4 4 4
|
||||
5 5 5
|
||||
6 6 0
|
||||
7 7 0
|
||||
8 8 0
|
||||
9 9 0
|
||||
10 10 0
|
||||
- left -
|
||||
1 1 1
|
||||
2 2 2
|
||||
3 3 3
|
||||
4 4 4
|
||||
5 5 5
|
||||
6 6 0
|
||||
7 7 0
|
||||
8 8 0
|
||||
9 9 0
|
||||
10 10 0
|
||||
- right -
|
||||
0 0 -4
|
||||
0 0 -3
|
||||
0 0 -2
|
||||
0 0 -1
|
||||
0 0 0
|
||||
1 1 1
|
||||
2 2 2
|
||||
3 3 3
|
||||
4 4 4
|
||||
5 5 5
|
||||
- inner -
|
||||
1 1 1
|
||||
2 2 2
|
||||
3 3 3
|
||||
4 4 4
|
||||
5 5 5
|
||||
- types -
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
--- partial_merge ---
|
||||
- full -
|
||||
-4 0 196
|
||||
-3 0 197
|
||||
-2 0 198
|
||||
-1 0 199
|
||||
0 0 200
|
||||
1 101 201
|
||||
2 102 202
|
||||
3 103 203
|
||||
4 104 204
|
||||
5 105 205
|
||||
6 106 \N
|
||||
7 107 \N
|
||||
8 108 \N
|
||||
9 109 \N
|
||||
10 110 \N
|
||||
- left -
|
||||
1 101 201
|
||||
2 102 202
|
||||
3 103 203
|
||||
4 104 204
|
||||
5 105 205
|
||||
6 106 \N
|
||||
7 107 \N
|
||||
8 108 \N
|
||||
9 109 \N
|
||||
10 110 \N
|
||||
- right -
|
||||
-4 0 196
|
||||
-3 0 197
|
||||
-2 0 198
|
||||
-1 0 199
|
||||
0 0 200
|
||||
1 101 201
|
||||
2 102 202
|
||||
3 103 203
|
||||
4 104 204
|
||||
5 105 205
|
||||
- inner -
|
||||
1 101 201
|
||||
2 102 202
|
||||
3 103 203
|
||||
4 104 204
|
||||
5 105 205
|
||||
- full -
|
||||
0 0 -4
|
||||
0 0 -3
|
||||
0 0 -2
|
||||
0 0 -1
|
||||
0 0 0
|
||||
1 1 1
|
||||
2 2 2
|
||||
3 3 3
|
||||
4 4 4
|
||||
5 5 5
|
||||
6 6 0
|
||||
7 7 0
|
||||
8 8 0
|
||||
9 9 0
|
||||
10 10 0
|
||||
- left -
|
||||
1 1 1
|
||||
2 2 2
|
||||
3 3 3
|
||||
4 4 4
|
||||
5 5 5
|
||||
6 6 0
|
||||
7 7 0
|
||||
8 8 0
|
||||
9 9 0
|
||||
10 10 0
|
||||
- right -
|
||||
0 0 -4
|
||||
0 0 -3
|
||||
0 0 -2
|
||||
0 0 -1
|
||||
0 0 0
|
||||
1 1 1
|
||||
2 2 2
|
||||
3 3 3
|
||||
4 4 4
|
||||
5 5 5
|
||||
- inner -
|
||||
1 1 1
|
||||
2 2 2
|
||||
3 3 3
|
||||
4 4 4
|
||||
5 5 5
|
||||
- types -
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
--- hash ---
|
||||
- full -
|
||||
1 1
|
||||
2 2
|
||||
-1 1
|
||||
1 \N
|
||||
1 257
|
||||
1 -1
|
||||
- left -
|
||||
1 1
|
||||
2 2
|
||||
- right -
|
||||
1 1
|
||||
-1 1
|
||||
1 \N
|
||||
1 257
|
||||
1 -1
|
||||
- inner -
|
||||
1 1
|
||||
- types -
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
--- partial_merge ---
|
||||
- full -
|
||||
1 1
|
||||
2 2
|
||||
-1 1
|
||||
1 \N
|
||||
1 257
|
||||
1 -1
|
||||
- left -
|
||||
1 1
|
||||
2 2
|
||||
- right -
|
||||
1 1
|
||||
-1 1
|
||||
1 \N
|
||||
1 257
|
||||
1 -1
|
||||
- inner -
|
||||
1 1
|
||||
- types -
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
128
tests/queries/0_stateless/01674_join_implicit_cast.sql
Normal file
128
tests/queries/0_stateless/01674_join_implicit_cast.sql
Normal file
@ -0,0 +1,128 @@
|
||||
CREATE DATABASE IF NOT EXISTS test_01655;
|
||||
USE test_01655;
|
||||
|
||||
DROP TABLE IF EXISTS t1;
|
||||
DROP TABLE IF EXISTS t2;
|
||||
|
||||
CREATE TABLE t1 (a UInt16, b UInt16) ENGINE = TinyLog;
|
||||
CREATE TABLE t2 (a Int16, b Nullable(Int64)) ENGINE = TinyLog;
|
||||
|
||||
INSERT INTO t1 SELECT number as a, 100 + number as b FROM system.numbers LIMIT 1, 10;
|
||||
INSERT INTO t2 SELECT number - 5 as a, 200 + number - 5 as b FROM system.numbers LIMIT 1, 10;
|
||||
|
||||
SELECT '--- hash ---';
|
||||
SET join_algorithm = 'hash';
|
||||
|
||||
SELECT '- full -';
|
||||
SELECT a, b, t2.b FROM t1 FULL JOIN t2 USING (a) ORDER BY (a);
|
||||
SELECT '- left -';
|
||||
SELECT a, b, t2.b FROM t1 LEFT JOIN t2 USING (a) ORDER BY (a);
|
||||
SELECT '- right -';
|
||||
SELECT a, b, t2.b FROM t1 RIGHT JOIN t2 USING (a) ORDER BY (a);
|
||||
SELECT '- inner -';
|
||||
SELECT a, b, t2.b FROM t1 INNER JOIN t2 USING (a) ORDER BY (a);
|
||||
|
||||
SELECT '- full -';
|
||||
SELECT a, t1.a, t2.a FROM t1 FULL JOIN t2 USING (a) ORDER BY (t1.a, t2.a);
|
||||
SELECT '- left -';
|
||||
SELECT a, t1.a, t2.a FROM t1 LEFT JOIN t2 USING (a) ORDER BY (t1.a, t2.a);
|
||||
SELECT '- right -';
|
||||
SELECT a, t1.a, t2.a FROM t1 RIGHT JOIN t2 USING (a) ORDER BY (t1.a, t2.a);
|
||||
SELECT '- inner -';
|
||||
SELECT a, t1.a, t2.a FROM t1 INNER JOIN t2 USING (a) ORDER BY (t1.a, t2.a);
|
||||
|
||||
SELECT '- types -';
|
||||
SELECT any(toTypeName(a)) == 'Int32' AND any(toTypeName(t2.a)) == 'Int32' FROM t1 FULL JOIN t2 USING (a);
|
||||
SELECT any(toTypeName(a)) == 'Int32' AND any(toTypeName(t2.a)) == 'Int32' FROM t1 LEFT JOIN t2 USING (a);
|
||||
SELECT any(toTypeName(a)) == 'Int32' AND any(toTypeName(t2.a)) == 'Int32' FROM t1 RIGHT JOIN t2 USING (a);
|
||||
SELECT any(toTypeName(a)) == 'Int32' AND any(toTypeName(t2.a)) == 'Int32' FROM t1 INNER JOIN t2 USING (a);
|
||||
|
||||
SELECT * FROM t1 FULL JOIN t2 ON (t1.a == t2.a) ORDER BY (a); -- { serverError 53 }
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON(t1.a == t2.a) ORDER BY (a); -- { serverError 53 }
|
||||
SELECT * FROM t1 RIGHT JOIN t2 ON (t1.a == t2.a) ORDER BY (a); -- { serverError 53 }
|
||||
SELECT * FROM t1 INNER JOIN t2 ON (t1.a == t2.a) ORDER BY (a); -- { serverError 53 }
|
||||
|
||||
SELECT '--- partial_merge ---';
|
||||
|
||||
SET join_algorithm = 'partial_merge';
|
||||
|
||||
SELECT '- full -';
|
||||
SELECT a, b, t2.b FROM t1 FULL JOIN t2 USING (a) ORDER BY (a);
|
||||
SELECT '- left -';
|
||||
SELECT a, b, t2.b FROM t1 LEFT JOIN t2 USING (a) ORDER BY (a);
|
||||
SELECT '- right -';
|
||||
SELECT a, b, t2.b FROM t1 RIGHT JOIN t2 USING (a) ORDER BY (a);
|
||||
SELECT '- inner -';
|
||||
SELECT a, b, t2.b FROM t1 INNER JOIN t2 USING (a) ORDER BY (a);
|
||||
|
||||
|
||||
SELECT '- full -';
|
||||
SELECT a, t1.a, t2.a FROM t1 FULL JOIN t2 USING (a) ORDER BY (t1.a, t2.a);
|
||||
SELECT '- left -';
|
||||
SELECT a, t1.a, t2.a FROM t1 LEFT JOIN t2 USING (a) ORDER BY (t1.a, t2.a);
|
||||
SELECT '- right -';
|
||||
SELECT a, t1.a, t2.a FROM t1 RIGHT JOIN t2 USING (a) ORDER BY (t1.a, t2.a);
|
||||
SELECT '- inner -';
|
||||
SELECT a, t1.a, t2.a FROM t1 INNER JOIN t2 USING (a) ORDER BY (t1.a, t2.a);
|
||||
|
||||
SELECT '- types -';
|
||||
SELECT any(toTypeName(a)) == 'Int32' AND any(toTypeName(t2.a)) == 'Int32' FROM t1 FULL JOIN t2 USING (a);
|
||||
SELECT any(toTypeName(a)) == 'Int32' AND any(toTypeName(t2.a)) == 'Int32' FROM t1 LEFT JOIN t2 USING (a);
|
||||
SELECT any(toTypeName(a)) == 'Int32' AND any(toTypeName(t2.a)) == 'Int32' FROM t1 RIGHT JOIN t2 USING (a);
|
||||
SELECT any(toTypeName(a)) == 'Int32' AND any(toTypeName(t2.a)) == 'Int32' FROM t1 INNER JOIN t2 USING (a);
|
||||
|
||||
SELECT * FROM t1 FULL JOIN t2 ON (t1.a == t2.a) ORDER BY (a); -- { serverError 53 }
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON(t1.a == t2.a) ORDER BY (a); -- { serverError 53 }
|
||||
SELECT * FROM t1 RIGHT JOIN t2 ON (t1.a == t2.a) ORDER BY (a); -- { serverError 53 }
|
||||
SELECT * FROM t1 INNER JOIN t2 ON (t1.a == t2.a) ORDER BY (a); -- { serverError 53 }
|
||||
|
||||
DROP TABLE IF EXISTS t1;
|
||||
DROP TABLE IF EXISTS t2;
|
||||
|
||||
CREATE TABLE t1 (id Nullable(Int32), a UInt16, b UInt8) ENGINE = TinyLog;
|
||||
CREATE TABLE t2 (id Nullable(Int32), a Int16, b Nullable(Int64)) ENGINE = TinyLog;
|
||||
INSERT INTO t1 VALUES (0, 1, 1), (1, 2, 2);
|
||||
INSERT INTO t2 VALUES (2, -1, 1), (3, 1, NULL), (4, 1, 257), (5, 1, -1), (6, 1, 1);
|
||||
|
||||
SELECT '--- hash ---';
|
||||
|
||||
SELECT '- full -';
|
||||
SELECT a, b FROM t1 FULL JOIN t2 USING (a, b) ORDER BY ifNull(t1.id, t2.id);
|
||||
SELECT '- left -';
|
||||
SELECT a, b FROM t1 LEFT JOIN t2 USING (a, b) ORDER BY ifNull(t1.id, t2.id);
|
||||
SELECT '- right -';
|
||||
SELECT a, b FROM t1 RIGHT JOIN t2 USING (a, b) ORDER BY ifNull(t1.id, t2.id);
|
||||
SELECT '- inner -';
|
||||
SELECT a, b FROM t1 INNER JOIN t2 USING (a, b) ORDER BY ifNull(t1.id, t2.id);
|
||||
|
||||
SELECT '- types -';
|
||||
|
||||
SELECT any(toTypeName(a)) == 'Int32' AND any(toTypeName(b)) == 'Nullable(Int64)' FROM t1 FULL JOIN t2 USING (a, b);
|
||||
SELECT any(toTypeName(a)) == 'Int32' AND any(toTypeName(b)) == 'Nullable(Int64)' FROM t1 LEFT JOIN t2 USING (a, b);
|
||||
SELECT any(toTypeName(a)) == 'Int32' AND any(toTypeName(b)) == 'Nullable(Int64)' FROM t1 RIGHT JOIN t2 USING (a, b);
|
||||
SELECT any(toTypeName(a)) == 'Int32' AND any(toTypeName(b)) == 'Nullable(Int64)' FROM t1 INNER JOIN t2 USING (a, b);
|
||||
|
||||
SELECT '--- partial_merge ---';
|
||||
|
||||
SET join_algorithm = 'partial_merge';
|
||||
|
||||
SELECT '- full -';
|
||||
SELECT a, b FROM t1 FULL JOIN t2 USING (a, b) ORDER BY ifNull(t1.id, t2.id);
|
||||
SELECT '- left -';
|
||||
SELECT a, b FROM t1 LEFT JOIN t2 USING (a, b) ORDER BY ifNull(t1.id, t2.id);
|
||||
SELECT '- right -';
|
||||
SELECT a, b FROM t1 RIGHT JOIN t2 USING (a, b) ORDER BY ifNull(t1.id, t2.id);
|
||||
SELECT '- inner -';
|
||||
SELECT a, b FROM t1 INNER JOIN t2 USING (a, b) ORDER BY ifNull(t1.id, t2.id);
|
||||
|
||||
SELECT '- types -';
|
||||
|
||||
SELECT any(toTypeName(a)) == 'Int32' AND any(toTypeName(b)) == 'Nullable(Int64)' FROM t1 FULL JOIN t2 USING (a, b);
|
||||
SELECT any(toTypeName(a)) == 'Int32' AND any(toTypeName(b)) == 'Nullable(Int64)' FROM t1 LEFT JOIN t2 USING (a, b);
|
||||
SELECT any(toTypeName(a)) == 'Int32' AND any(toTypeName(b)) == 'Nullable(Int64)' FROM t1 RIGHT JOIN t2 USING (a, b);
|
||||
SELECT any(toTypeName(a)) == 'Int32' AND any(toTypeName(b)) == 'Nullable(Int64)' FROM t1 INNER JOIN t2 USING (a, b);
|
||||
|
||||
DROP TABLE IF EXISTS t1;
|
||||
DROP TABLE IF EXISTS t2;
|
||||
|
||||
DROP DATABASE IF EXISTS test_01655;
|
Loading…
Reference in New Issue
Block a user