aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/clickhouse/src/Interpreters/StorageID.h
blob: 96e3cefe00cd39da4451bbc6bd6b063acb7397f9 (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
#pragma once
#include <base/types.h>
#include <Core/UUID.h>
#include <tuple>
#include <Parsers/IAST_fwd.h>
#include <Core/QualifiedTableName.h>
#include <Common/Exception.h>

namespace Poco
{
namespace Util
{
class AbstractConfiguration; // NOLINT(cppcoreguidelines-virtual-class-destructor)
}
}

namespace DB
{

namespace ErrorCodes
{
    extern const int UNKNOWN_TABLE;
}

static constexpr char const * TABLE_WITH_UUID_NAME_PLACEHOLDER = "_";

class ASTQueryWithTableAndOutput;
class ASTTableIdentifier;
class Context;

// TODO(ilezhankin): refactor and merge |ASTTableIdentifier|
struct StorageID
{
    String database_name;
    String table_name;
    UUID uuid = UUIDHelpers::Nil;

    StorageID(const String & database, const String & table, UUID uuid_ = UUIDHelpers::Nil)
        : database_name(database), table_name(table), uuid(uuid_)
    {
        assertNotEmpty();
    }

    StorageID(const ASTQueryWithTableAndOutput & query); /// NOLINT
    StorageID(const ASTTableIdentifier & table_identifier_node); /// NOLINT
    StorageID(const ASTPtr & node); /// NOLINT

    explicit StorageID(const QualifiedTableName & qualified_name) : StorageID(qualified_name.database, qualified_name.table) { }

    String getDatabaseName() const;

    String getTableName() const;

    String getFullTableName() const;
    String getFullNameNotQuoted() const;

    String getNameForLogs() const;

    explicit operator bool () const
    {
        return !empty();
    }

    bool empty() const
    {
        return table_name.empty() && !hasUUID();
    }

    bool hasUUID() const
    {
        return uuid != UUIDHelpers::Nil;
    }

    bool hasDatabase() const { return !database_name.empty(); }

    bool operator==(const StorageID & rhs) const;

    void assertNotEmpty() const
    {
        // Can be triggered by user input, e.g. SELECT joinGetOrNull('', 'num', 500)
        if (empty())
            throw Exception(ErrorCodes::UNKNOWN_TABLE, "Both table name and UUID are empty");
        if (table_name.empty() && !database_name.empty())
            throw Exception(ErrorCodes::UNKNOWN_TABLE, "Table name is empty, but database name is not");
    }

    /// Avoid implicit construction of empty StorageID. However, it's needed for deferred initialization.
    static StorageID createEmpty() { return {}; }

    QualifiedTableName getQualifiedName() const { return {database_name, getTableName()}; }

    static StorageID fromDictionaryConfig(const Poco::Util::AbstractConfiguration & config,
                                          const String & config_prefix);

    /// If dictionary has UUID, then use it as dictionary name in ExternalLoader to allow dictionary renaming.
    /// ExternalDictnariesLoader::resolveDictionaryName(...) should be used to access such dictionaries by name.
    String getInternalDictionaryName() const { return getShortName(); }
    /// Get short, but unique, name.
    String getShortName() const;

    /// Calculates hash using only the database and table name of a StorageID.
    struct DatabaseAndTableNameHash
    {
        size_t operator()(const StorageID & storage_id) const
        {
            SipHash hash_state;
            hash_state.update(storage_id.database_name.data(), storage_id.database_name.size());
            hash_state.update(storage_id.table_name.data(), storage_id.table_name.size());
            return hash_state.get64();
        }
    };

    /// Checks if the database and table name of two StorageIDs are equal.
    struct DatabaseAndTableNameEqual
    {
        bool operator()(const StorageID & left, const StorageID & right) const
        {
            return (left.database_name == right.database_name) && (left.table_name == right.table_name);
        }
    };

private:
    StorageID() = default;
};

}

namespace fmt
{
    template <>
    struct formatter<DB::StorageID>
    {
        static constexpr auto parse(format_parse_context & ctx)
        {
            return ctx.begin();
        }

        template <typename FormatContext>
        auto format(const DB::StorageID & storage_id, FormatContext & ctx)
        {
            return fmt::format_to(ctx.out(), "{}", storage_id.getNameForLogs());
        }
    };
}