join_common.cpp 5.9 KB
Newer Older
1
#include <Interpreters/join_common.h>
C
chertus 已提交
2
#include <Columns/ColumnNullable.h>
C
chertus 已提交
3
#include <DataTypes/DataTypeNullable.h>
C
chertus 已提交
4
#include <DataTypes/DataTypeLowCardinality.h>
C
chertus 已提交
5
#include <DataStreams/materializeBlock.h>
C
chertus 已提交
6 7 8 9

namespace DB
{

C
chertus 已提交
10 11 12 13 14 15 16 17 18
namespace ErrorCodes
{
    extern const int TYPE_MISMATCH;
}


namespace JoinCommon
{

19
void convertColumnToNullable(ColumnWithTypeAndName & column, bool low_card_nullability)
C
chertus 已提交
20
{
21 22 23 24 25 26
    if (low_card_nullability && column.type->lowCardinality())
    {
        column.column = recursiveRemoveLowCardinality(column.column);
        column.type = recursiveRemoveLowCardinality(column.type);
    }

C
chertus 已提交
27 28 29 30 31 32 33 34 35 36 37 38 39 40
    if (column.type->isNullable() || !column.type->canBeInsideNullable())
        return;

    column.type = makeNullable(column.type);
    if (column.column)
        column.column = makeNullable(column.column);
}

void convertColumnsToNullable(Block & block, size_t starting_pos)
{
    for (size_t i = starting_pos; i < block.columns(); ++i)
        convertColumnToNullable(block.getByPosition(i));
}

C
chertus 已提交
41 42 43 44 45 46 47 48 49
/// @warning It assumes that every NULL has default value in nested column (or it does not matter)
void removeColumnNullability(ColumnWithTypeAndName & column)
{
    if (!column.type->isNullable())
        return;

    column.type = static_cast<const DataTypeNullable &>(*column.type).getNestedType();
    if (column.column)
    {
A
Alexey Milovidov 已提交
50
        const auto * nullable_column = checkAndGetColumn<ColumnNullable>(*column.column);
C
chertus 已提交
51
        ColumnPtr nested_column = nullable_column->getNestedColumnPtr();
52
        MutableColumnPtr mutable_column = IColumn::mutate(std::move(nested_column));
C
chertus 已提交
53 54 55 56
        column.column = std::move(mutable_column);
    }
}

57
ColumnRawPtrs materializeColumnsInplace(Block & block, const Names & names)
58 59 60
{
    ColumnRawPtrs ptrs;
    ptrs.reserve(names.size());
61

A
Alexey Milovidov 已提交
62
    for (const auto & column_name : names)
63 64 65 66 67 68 69 70 71 72 73 74
    {
        auto & column = block.getByName(column_name).column;
        column = recursiveRemoveLowCardinality(column->convertToFullColumnIfConst());
        ptrs.push_back(column.get());
    }

    return ptrs;
}

Columns materializeColumns(const Block & block, const Names & names)
{
    Columns materialized;
75 76
    materialized.reserve(names.size());

A
Alexey Milovidov 已提交
77
    for (const auto & column_name : names)
78 79 80 81 82
    {
        const auto & src_column = block.getByName(column_name).column;
        materialized.emplace_back(recursiveRemoveLowCardinality(src_column->convertToFullColumnIfConst()));
    }

83 84 85 86 87 88 89 90
    return materialized;
}

ColumnRawPtrs getRawPointers(const Columns & columns)
{
    ColumnRawPtrs ptrs;
    ptrs.reserve(columns.size());

A
Alexey Milovidov 已提交
91
    for (const auto & column : columns)
92 93
        ptrs.push_back(column.get());

94 95 96
    return ptrs;
}

97 98 99 100 101 102 103 104 105 106
void removeLowCardinalityInplace(Block & block)
{
    for (size_t i = 0; i < block.columns(); ++i)
    {
        auto & col = block.getByPosition(i);
        col.column = recursiveRemoveLowCardinality(col.column);
        col.type = recursiveRemoveLowCardinality(col.type);
    }
}

107
void splitAdditionalColumns(const Block & sample_block, const Names & key_names, Block & block_keys, Block & block_others)
C
chertus 已提交
108
{
109
    block_others = materializeBlock(sample_block);
C
chertus 已提交
110

111
    for (const String & column_name : key_names)
C
chertus 已提交
112
    {
113 114
        /// Extract right keys with correct keys order. There could be the same key names.
        if (!block_keys.has(column_name))
C
chertus 已提交
115
        {
116 117 118
            auto & col = block_others.getByName(column_name);
            block_keys.insert(col);
            block_others.erase(column_name);
C
chertus 已提交
119
        }
120 121
    }
}
C
chertus 已提交
122

123 124 125 126
ColumnRawPtrs extractKeysForJoin(const Block & block_keys, const Names & key_names)
{
    size_t keys_size = key_names.size();
    ColumnRawPtrs key_columns(keys_size);
C
chertus 已提交
127

128 129 130 131
    for (size_t i = 0; i < keys_size; ++i)
    {
        const String & column_name = key_names[i];
        key_columns[i] = block_keys.getByName(column_name).column.get();
C
chertus 已提交
132 133

        /// We will join only keys, where all components are not NULL.
A
Alexey Milovidov 已提交
134
        if (const auto * nullable = checkAndGetColumn<ColumnNullable>(*key_columns[i]))
C
chertus 已提交
135 136 137 138 139 140
            key_columns[i] = &nullable->getNestedColumn();
    }

    return key_columns;
}

C
chertus 已提交
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
void checkTypesOfKeys(const Block & block_left, const Names & key_names_left, const Block & block_right, const Names & key_names_right)
{
    size_t keys_size = key_names_left.size();

    for (size_t i = 0; i < keys_size; ++i)
    {
        DataTypePtr left_type = removeNullable(recursiveRemoveLowCardinality(block_left.getByName(key_names_left[i]).type));
        DataTypePtr right_type = removeNullable(recursiveRemoveLowCardinality(block_right.getByName(key_names_right[i]).type));

        if (!left_type->equals(*right_type))
            throw Exception("Type mismatch of columns to JOIN by: "
                + key_names_left[i] + " " + left_type->getName() + " at left, "
                + key_names_right[i] + " " + right_type->getName() + " at right",
                ErrorCodes::TYPE_MISMATCH);
    }
}

C
chertus 已提交
158 159 160 161 162 163 164 165 166 167
void createMissedColumns(Block & block)
{
    for (size_t i = 0; i < block.columns(); ++i)
    {
        auto & column = block.getByPosition(i);
        if (!column.column)
            column.column = column.type->createColumn();
    }
}

C
chertus 已提交
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
void joinTotals(const Block & totals, const Block & columns_to_add, const Names & key_names_right, Block & block)
{
    if (Block totals_without_keys = totals)
    {
        for (const auto & name : key_names_right)
            totals_without_keys.erase(totals_without_keys.getPositionByName(name));

        for (size_t i = 0; i < totals_without_keys.columns(); ++i)
            block.insert(totals_without_keys.safeGetByPosition(i));
    }
    else
    {
        /// We will join empty `totals` - from one row with the default values.

        for (size_t i = 0; i < columns_to_add.columns(); ++i)
        {
            const auto & col = columns_to_add.getByPosition(i);
            block.insert({
                col.type->createColumnConstWithDefaultValue(1)->convertToFullColumnIfConst(),
                col.type,
                col.name});
        }
    }
}

C
chertus 已提交
193
}
C
chertus 已提交
194
}