aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/clickhouse/src/Analyzer/JoinNode.h
blob: 4f071e03856fee0d6b5c86dafd3e5359efe1e64c (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
153
154
155
156
157
158
159
160
161
162
163
164
165
#pragma once

#include <Core/Joins.h>

#include <Storages/IStorage_fwd.h>
#include <Storages/TableLockHolder.h>
#include <Storages/StorageSnapshot.h>

#include <Interpreters/Context_fwd.h>
#include <Interpreters/StorageID.h>

#include <Analyzer/IQueryTreeNode.h>

namespace DB
{

/** Join node represents join in query tree.
  *
  * For JOIN without join expression, JOIN expression is null.
  * Example: SELECT id FROM test_table_1 AS t1, test_table_2 AS t2;
  *
  * For JOIN with USING, JOIN expression contains list of identifier nodes. These nodes must be resolved
  * during query analysis pass.
  * Example: SELECT id FROM test_table_1 AS t1 INNER JOIN test_table_2 AS t2 USING (id);
  *
  * For JOIN with ON, JOIN expression contains single expression.
  * Example: SELECT id FROM test_table_1 AS t1 INNER JOIN test_table_2 AS t2 ON t1.id = t2.id;
  */
class JoinNode;
using JoinNodePtr = std::shared_ptr<JoinNode>;

class JoinNode final : public IQueryTreeNode
{
public:
    /** Construct join node with left table expression, right table expression and join expression.
      * Example: SELECT id FROM test_table_1 INNER JOIN test_table_2 ON expression.
      *
      * test_table_1 - left table expression.
      * test_table_2 - right table expression.
      * expression - join expression.
      */
    JoinNode(QueryTreeNodePtr left_table_expression_,
        QueryTreeNodePtr right_table_expression_,
        QueryTreeNodePtr join_expression_,
        JoinLocality locality_,
        JoinStrictness strictness_,
        JoinKind kind_);

    /// Get left table expression
    const QueryTreeNodePtr & getLeftTableExpression() const
    {
        return children[left_table_expression_child_index];
    }

    /// Get left table expression
    QueryTreeNodePtr & getLeftTableExpression()
    {
        return children[left_table_expression_child_index];
    }

    /// Get right table expression
    const QueryTreeNodePtr & getRightTableExpression() const
    {
        return children[right_table_expression_child_index];
    }

    /// Get right table expression
    QueryTreeNodePtr & getRightTableExpression()
    {
        return children[right_table_expression_child_index];
    }

    /// Returns true if join has join expression, false otherwise
    bool hasJoinExpression() const
    {
        return children[join_expression_child_index] != nullptr;
    }

    /// Get join expression
    const QueryTreeNodePtr & getJoinExpression() const
    {
        return children[join_expression_child_index];
    }

    /// Get join expression
    QueryTreeNodePtr & getJoinExpression()
    {
        return children[join_expression_child_index];
    }

    /// Returns true if join has USING join expression, false otherwise
    bool isUsingJoinExpression() const
    {
        return hasJoinExpression() && getJoinExpression()->getNodeType() == QueryTreeNodeType::LIST;
    }

    /// Returns true if join has ON join expression, false otherwise
    bool isOnJoinExpression() const
    {
        return hasJoinExpression() && getJoinExpression()->getNodeType() != QueryTreeNodeType::LIST;
    }

    /// Get join locality
    JoinLocality getLocality() const
    {
        return locality;
    }

    /// Set join locality
    void setLocality(JoinLocality locality_value)
    {
        locality = locality_value;
    }

    /// Get join strictness
    JoinStrictness getStrictness() const
    {
        return strictness;
    }

    /// Get join kind
    JoinKind getKind() const
    {
        return kind;
    }

    /// Convert join node to ASTTableJoin
    ASTPtr toASTTableJoin() const;

    QueryTreeNodeType getNodeType() const override
    {
        return QueryTreeNodeType::JOIN;
    }

    /*
     * Convert CROSS to INNER JOIN - changes JOIN kind and sets a new join expression
     * (that was moved from WHERE clause).
     * Expects the current kind to be CROSS (and join expression to be null because of that).
     */
    void crossToInner(const QueryTreeNodePtr & join_expression_);

    void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;

protected:
    bool isEqualImpl(const IQueryTreeNode & rhs) const override;

    void updateTreeHashImpl(HashState & state) const override;

    QueryTreeNodePtr cloneImpl() const override;

    ASTPtr toASTImpl(const ConvertToASTOptions & options) const override;

private:
    JoinLocality locality = JoinLocality::Unspecified;
    JoinStrictness strictness = JoinStrictness::Unspecified;
    JoinKind kind = JoinKind::Inner;

    static constexpr size_t left_table_expression_child_index = 0;
    static constexpr size_t right_table_expression_child_index = 1;
    static constexpr size_t join_expression_child_index = 2;
    static constexpr size_t children_size = join_expression_child_index + 1;
};

}