aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/clickhouse/src/Storages/ProjectionsDescription.h
blob: c48942eb0ec1152f0f371a750ef162e6235f9c36 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#pragma once

#include <Core/Types.h>

#include <memory>
#include <vector>
#include <Interpreters/ExpressionActions.h>
#include <Interpreters/AggregateDescription.h>
#include <Parsers/IAST_fwd.h>
#include <Storages/ColumnsDescription.h>

#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index_container.hpp>

namespace DB
{
struct StorageInMemoryMetadata;
using StorageMetadataPtr = std::shared_ptr<const StorageInMemoryMetadata>;

/// Description of projections for Storage
struct ProjectionDescription
{
    enum class Type
    {
        Normal,
        Aggregate,
    };

    static constexpr const char * MINMAX_COUNT_PROJECTION_NAME = "_minmax_count_projection";

    /// Definition AST of projection
    ASTPtr definition_ast;

    /// Subquery AST for projection calculation
    ASTPtr query_ast;

    /// Projection name
    String name;

    /// Projection type (normal, aggregate, etc.)
    Type type = Type::Normal;

    /// Columns which are required for query_ast.
    Names required_columns;

    Names getRequiredColumns() const { return required_columns; }

    /// Sample block with projection columns. (NOTE: columns in block are empty, but not nullptr)
    Block sample_block;

    Block sample_block_for_keys;

    StorageMetadataPtr metadata;

    size_t key_size = 0;

    bool is_minmax_count_projection = false;

    /// If a primary key expression is used in the minmax_count projection, store the name of max expression.
    String primary_key_max_column_name;

    /// Stores partition value indices of partition value row. It's needed because identical
    /// partition columns will appear only once in projection block, but every column will have a
    /// value in the partition value row. This vector holds the biggest value index of give
    /// partition columns.
    std::vector<size_t> partition_value_indices;

    /// Parse projection from definition AST
    static ProjectionDescription
    getProjectionFromAST(const ASTPtr & definition_ast, const ColumnsDescription & columns, ContextPtr query_context);

    static ProjectionDescription getMinMaxCountProjection(
        const ColumnsDescription & columns,
        ASTPtr partition_columns,
        const Names & minmax_columns,
        const ASTs & primary_key_asts,
        ContextPtr query_context);

    ProjectionDescription() = default;

    /// We need custom copy constructors because we don't want
    /// unintentionally share AST variables and modify them.
    ProjectionDescription(const ProjectionDescription & other) = delete;
    ProjectionDescription(ProjectionDescription && other) = default;
    ProjectionDescription & operator=(const ProjectionDescription & other) = delete;
    ProjectionDescription & operator=(ProjectionDescription && other) = default;

    ProjectionDescription clone() const;

    bool operator==(const ProjectionDescription & other) const;
    bool operator!=(const ProjectionDescription & other) const { return !(*this == other); }

    /// Recalculate projection with new columns because projection expression may change
    /// if something change in columns.
    void recalculateWithNewColumns(const ColumnsDescription & new_columns, ContextPtr query_context);

    bool isPrimaryKeyColumnPossiblyWrappedInFunctions(const ASTPtr & node) const;

    Block calculate(const Block & block, ContextPtr context) const;

    String getDirectoryName() const { return name + ".proj"; }
};

using ProjectionDescriptionRawPtr = const ProjectionDescription *;

/// All projections in storage
struct ProjectionsDescription : public IHints<1, ProjectionsDescription>
{
    ProjectionsDescription() = default;
    ProjectionsDescription(ProjectionsDescription && other) = default;
    ProjectionsDescription & operator=(ProjectionsDescription && other) = default;

    ProjectionsDescription clone() const;

    /// Convert description to string
    String toString() const;
    /// Parse description from string
    static ProjectionsDescription parse(const String & str, const ColumnsDescription & columns, ContextPtr query_context);

    /// Return common expression for all stored projections
    ExpressionActionsPtr getSingleExpressionForProjections(const ColumnsDescription & columns, ContextPtr query_context) const;

    bool operator==(const ProjectionsDescription & other) const { return projections == other.projections; }
    bool operator!=(const ProjectionsDescription & other) const { return !(*this == other); }

    auto begin() const { return projections.begin(); }
    auto end() const { return projections.end(); }

    size_t size() const { return projections.size(); }
    bool empty() const { return projections.empty(); }

    bool has(const String & projection_name) const;
    const ProjectionDescription & get(const String & projection_name) const;

    void
    add(ProjectionDescription && projection, const String & after_projection = String(), bool first = false, bool if_not_exists = false);
    void remove(const String & projection_name, bool if_exists);

    std::vector<String> getAllRegisteredNames() const override;

private:
    /// Keep the sequence of columns and allow to lookup by name.
    using Container = std::list<ProjectionDescription>;
    using Map = std::unordered_map<std::string, Container::iterator>;

    Container projections;
    Map map;
};

}