aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/clickhouse/src/Interpreters/IdentifierSemantic.h
blob: 178bd291beb4111cf095b53fd027cb35c31f31db (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
#pragma once

#include <Interpreters/Aliases.h>
#include <Interpreters/DatabaseAndTableWithAlias.h>
#include <Interpreters/InDepthNodeVisitor.h>
#include <Interpreters/QueryAliasesVisitor.h>
#include <Interpreters/getHeaderForProcessingStage.h>
#include <Interpreters/getTableExpressions.h>

namespace DB
{

class ASTIdentifier;
class ASTSelectQuery;

struct IdentifierSemanticImpl
{
    bool special = false;              /// for now it's 'not a column': tables, subselects and some special stuff like FORMAT
    bool can_be_alias = true;          /// if it's a cropped name it could not be an alias
    bool covered = false;              /// real (compound) name is hidden by an alias (short name)
    std::optional<size_t> membership;  /// table position in join
    String table = {};                 /// store table name for columns just to support legacy logic.
    bool legacy_compound = false;      /// true if identifier supposed to be comply for legacy |compound()| behavior
};

/// Static class to manipulate IdentifierSemanticImpl via ASTIdentifier
struct IdentifierSemantic
{
    enum class ColumnMatch
    {
        NoMatch,
        ColumnName,       /// column qualified with column names list
        AliasedTableName, /// column qualified with table name (but table has an alias so its priority is lower than TableName)
        TableName,        /// column qualified with table name
        DBAndTable,       /// column qualified with database and table name
        TableAlias,       /// column qualified with table alias
        Ambiguous,
    };

    /// @returns name for column identifiers
    static std::optional<String> getColumnName(const ASTIdentifier & node);
    static std::optional<String> getColumnName(const ASTPtr & ast);

    /// @returns name for 'not a column' identifiers
    static std::optional<String> extractNestedName(const ASTIdentifier & identifier, const String & table_name);

    static String extractNestedName(const ASTIdentifier & identifier, const DatabaseAndTableWithAlias & table);

    static ColumnMatch canReferColumnToTable(const ASTIdentifier & identifier, const DatabaseAndTableWithAlias & db_and_table);
    static ColumnMatch canReferColumnToTable(const ASTIdentifier & identifier, const TableWithColumnNamesAndTypes & table_with_columns);

    static void setColumnShortName(ASTIdentifier & identifier, const DatabaseAndTableWithAlias & db_and_table);
    static void setColumnLongName(ASTIdentifier & identifier, const DatabaseAndTableWithAlias & db_and_table);
    static bool canBeAlias(const ASTIdentifier & identifier);
    static void setMembership(ASTIdentifier &, size_t table_pos);
    static void coverName(ASTIdentifier &, const String & alias);
    static std::optional<ASTIdentifier> uncover(const ASTIdentifier & identifier);
    static std::optional<size_t> getMembership(const ASTIdentifier & identifier);
    static std::optional<size_t> chooseTable(const ASTIdentifier &, const std::vector<DatabaseAndTableWithAlias> & tables,
                            bool allow_ambiguous = false);
    static std::optional<size_t> chooseTable(const ASTIdentifier &, const TablesWithColumns & tables,
                            bool allow_ambiguous = false);
    static std::optional<size_t> chooseTableColumnMatch(const ASTIdentifier &, const TablesWithColumns & tables,
                            bool allow_ambiguous = false);

    static std::optional<size_t> getIdentMembership(const ASTIdentifier & ident, const std::vector<TableWithColumnNamesAndTypes> & tables);

    /// Collect common table membership for identifiers in expression
    /// If membership cannot be established or there are several identifies from different tables, return empty optional
    static std::optional<size_t>
    getIdentsMembership(ASTPtr ast, const std::vector<TableWithColumnNamesAndTypes> & tables, const Aliases & aliases);

private:
    static bool doesIdentifierBelongTo(const ASTIdentifier & identifier, const String & database, const String & table);
    static bool doesIdentifierBelongTo(const ASTIdentifier & identifier, const String & table);
};


/// Collect all identifies from AST recursively
class IdentifiersCollector
{
public:
    using ASTIdentifierPtr = const ASTIdentifier *;
    using ASTIdentifiers = std::vector<ASTIdentifierPtr>;
    struct Data
    {
        ASTIdentifiers idents;
    };

    static void visit(const ASTPtr & node, Data & data);
    static bool needChildVisit(const ASTPtr &, const ASTPtr &);
    static ASTIdentifiers collect(const ASTPtr & node);
};

/// Collect identifier table membership considering aliases
class IdentifierMembershipCollector
{
public:
    IdentifierMembershipCollector(const ASTSelectQuery & select, ContextPtr context);
    std::optional<size_t> getIdentsMembership(ASTPtr ast) const;

private:
    std::vector<TableWithColumnNamesAndTypes> tables;
    Aliases aliases;
};

/// Split expression `expr_1 AND expr_2 AND ... AND expr_n` into vector `[expr_1, expr_2, ..., expr_n]`
ASTs splitConjunctionsAst(const ASTPtr & node);
void splitConjunctionsAst(const ASTPtr & node, ASTs & result);

}