StorageSystemTables.cpp 18.4 KB
Newer Older
1 2 3 4
#include <Columns/ColumnString.h>
#include <Columns/ColumnsNumber.h>
#include <DataTypes/DataTypeString.h>
#include <DataTypes/DataTypeDateTime.h>
5
#include <DataTypes/DataTypeNullable.h>
6 7
#include <DataStreams/OneBlockInputStream.h>
#include <Storages/System/StorageSystemTables.h>
A
Alexey Milovidov 已提交
8
#include <Storages/VirtualColumnUtils.h>
9
#include <Databases/IDatabase.h>
10
#include <Access/ContextAccess.h>
11
#include <Interpreters/Context.h>
12 13 14
#include <Parsers/ASTCreateQuery.h>
#include <Parsers/queryToString.h>
#include <Common/typeid_cast.h>
15
#include <Common/StringUtils/StringUtils.h>
16
#include <DataTypes/DataTypesNumber.h>
17
#include <DataTypes/DataTypeArray.h>
G
Gleb Novikov 已提交
18
#include <Disks/StoragePolicy.h>
19 20
#include <Processors/Sources/SourceWithProgress.h>
#include <Processors/Pipe.h>
A
Alexander Tokmakov 已提交
21
#include <DataTypes/DataTypeUUID.h>
22 23 24 25 26


namespace DB
{

27 28
namespace ErrorCodes
{
A
Alexey Milovidov 已提交
29
    extern const int TABLE_IS_DROPPED;
30 31
}

32

33
StorageSystemTables::StorageSystemTables(const std::string & name_)
A
Alexander Tokmakov 已提交
34
    : IStorage({"system", name_})
35
{
36
    setColumns(ColumnsDescription(
A
Alexey Milovidov 已提交
37
    {
A
Alexey Milovidov 已提交
38 39
        {"database", std::make_shared<DataTypeString>()},
        {"name", std::make_shared<DataTypeString>()},
A
Alexander Tokmakov 已提交
40
        {"uuid", std::make_shared<DataTypeUUID>()},
A
Alexey Milovidov 已提交
41 42
        {"engine", std::make_shared<DataTypeString>()},
        {"is_temporary", std::make_shared<DataTypeUInt8>()},
I
Bugfix  
Igor Mineev 已提交
43
        {"data_paths", std::make_shared<DataTypeArray>(std::make_shared<DataTypeString>())},
44
        {"metadata_path", std::make_shared<DataTypeString>()},
45
        {"metadata_modification_time", std::make_shared<DataTypeDateTime>()},
46 47
        {"dependencies_database", std::make_shared<DataTypeArray>(std::make_shared<DataTypeString>())},
        {"dependencies_table", std::make_shared<DataTypeArray>(std::make_shared<DataTypeString>())},
48
        {"create_table_query", std::make_shared<DataTypeString>()},
49 50
        {"engine_full", std::make_shared<DataTypeString>()},
        {"partition_key", std::make_shared<DataTypeString>()},
51 52 53
        {"sorting_key", std::make_shared<DataTypeString>()},
        {"primary_key", std::make_shared<DataTypeString>()},
        {"sampling_key", std::make_shared<DataTypeString>()},
54
        {"storage_policy", std::make_shared<DataTypeString>()},
55
        {"total_rows", std::make_shared<DataTypeNullable>(std::make_shared<DataTypeUInt64>())},
56
        {"total_bytes", std::make_shared<DataTypeNullable>(std::make_shared<DataTypeUInt64>())},
57
    }));
58 59
}

60

61
static ColumnPtr getFilteredDatabases(const ASTPtr & query, const Context & context)
62
{
63
    MutableColumnPtr column = ColumnString::create();
64
    for (const auto & db : DatabaseCatalog::instance().getDatabases())
65
        column->insert(db.first);
66

67
    Block block { ColumnWithTypeAndName(std::move(column), std::make_shared<DataTypeString>(), "database") };
68
    VirtualColumnUtils::filterBlockWithQuery(query, block, context);
69
    return block.getByPosition(0).column;
70 71
}

A
alexey-milovidov 已提交
72 73
/// Avoid heavy operation on tables if we only queried columns that we can get without table object.
/// Otherwise it will require table initialization for Lazy database.
A
alexey-milovidov 已提交
74
static bool needLockStructure(const DatabasePtr & database, const Block & header)
V
fix  
Vasilyev Nikita 已提交
75
{
V
fix  
Vasilyev Nikita 已提交
76 77 78
    if (database->getEngineName() != "Lazy")
        return true;

A
Alexander Tokmakov 已提交
79
    static const std::set<std::string> columns_without_lock = { "database", "name", "uuid", "metadata_modification_time" };
A
alexey-milovidov 已提交
80
    for (const auto & column : header.getColumnsWithTypeAndName())
V
fix  
Vasilyev Nikita 已提交
81 82
    {
        if (columns_without_lock.find(column.name) == columns_without_lock.end())
V
fix  
Vasilyev Nikita 已提交
83 84 85 86
            return true;
    }
    return false;
}
87

88
class TablesBlockSource : public SourceWithProgress
89
{
90
public:
91
    TablesBlockSource(
K
kreuzerkrieg 已提交
92
        std::vector<UInt8> columns_mask_,
93
        Block header,
K
kreuzerkrieg 已提交
94 95 96
        UInt64 max_block_size_,
        ColumnPtr databases_,
        const Context & context_)
97 98
        : SourceWithProgress(std::move(header))
        , columns_mask(std::move(columns_mask_))
99 100 101
        , max_block_size(max_block_size_)
        , databases(std::move(databases_))
        , context(context_) {}
102 103 104 105

    String getName() const override { return "Tables"; }

protected:
106
    Chunk generate() override
107 108 109
    {
        if (done)
            return {};
110

111
        MutableColumns res_columns = getPort().getHeader().cloneEmptyColumns();
112

113 114
        const auto access = context.getAccess();
        const bool check_access_for_databases = !access->isGranted(AccessType::SHOW_TABLES);
115

116 117 118 119 120
        size_t rows_count = 0;
        while (rows_count < max_block_size)
        {
            if (tables_it && !tables_it->isValid())
                ++database_idx;
121

122 123 124
            while (database_idx < databases->size() && (!tables_it || !tables_it->isValid()))
            {
                database_name = databases->getDataAt(database_idx).toString();
125
                database = DatabaseCatalog::instance().tryGetDatabase(database_name);
126

127
                if (!database)
128 129 130 131 132
                {
                    /// Database was deleted just now or the user has no access.
                    ++database_idx;
                    continue;
                }
133

134 135
                break;
            }
136

A
Alexey Milovidov 已提交
137
            /// This is for temporary tables. They are output in single block regardless to max_block_size.
138 139 140 141 142
            if (database_idx >= databases->size())
            {
                if (context.hasSessionContext())
                {
                    Tables external_tables = context.getSessionContext().getExternalTables();
143

A
Alexey Milovidov 已提交
144
                    for (auto & table : external_tables)
145 146 147
                    {
                        size_t src_index = 0;
                        size_t res_index = 0;
148

149
                        // database
150 151
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insertDefault();
152

153
                        // name
154 155
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insert(table.first);
156

A
Alexander Tokmakov 已提交
157 158 159 160
                        // uuid
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insert(table.second->getStorageID().uuid);

161
                        // engine
162 163
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insert(table.second->getName());
164

165
                        // is_temporary
166
                        if (columns_mask[src_index++])
A
Amos Bird 已提交
167
                            res_columns[res_index++]->insert(1u);
168

169
                        // data_paths
170 171
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insertDefault();
172

173
                        // metadata_path
174 175
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insertDefault();
176

177
                        // metadata_modification_time
178 179
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insertDefault();
180

181
                        // dependencies_database
182 183
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insertDefault();
184

185
                        // dependencies_table
186 187
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insertDefault();
188

189
                        // create_table_query
190 191
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insertDefault();
192

193
                        // engine_full
194 195
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insert(table.second->getName());
196

197
                        // partition_key
198 199 200
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insertDefault();

201
                        // sorting_key
202 203 204
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insertDefault();

205
                        // primary_key
206 207
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insertDefault();
208

209
                        // sampling_key
210 211
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insertDefault();
212

213
                        // storage_policy
214 215
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insertDefault();
216 217 218 219

                        // total_rows
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insertDefault();
220 221 222 223

                        // total_bytes
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insertDefault();
224 225 226
                    }
                }

227
                UInt64 num_rows = res_columns.at(0)->size();
N
Nikolai Kochetov 已提交
228
                done = true;
229
                return Chunk(std::move(res_columns), num_rows);
230
            }
231

232
            const bool check_access_for_tables = check_access_for_databases && !access->isGranted(AccessType::SHOW_TABLES, database_name);
233

234
            if (!tables_it || !tables_it->isValid())
235
                tables_it = database->getTablesIterator();
V
fix  
Vasilyev Nikita 已提交
236

237
            const bool need_lock_structure = needLockStructure(database, getPort().getHeader());
V
fix  
Vasilyev Nikita 已提交
238

239
            for (; rows_count < max_block_size && tables_it->isValid(); tables_it->next())
240
            {
241
                auto table_name = tables_it->name();
242
                if (check_access_for_tables && !access->isGranted(AccessType::SHOW_TABLES, database_name, table_name))
243
                    continue;
A
Alexey Milovidov 已提交
244

245
                StoragePtr table = nullptr;
A
Alexey Milovidov 已提交
246 247
                TableStructureReadLockHolder lock;

A
Alexander Kazakov 已提交
248
                if (need_lock_structure)
A
Alexey Milovidov 已提交
249
                {
A
Alexander Kazakov 已提交
250 251 252 253 254 255 256
                    table = tables_it->table();
                    if (table == nullptr)
                    {
                        // Table might have just been removed or detached for Lazy engine (see DatabaseLazy::tryGetTable())
                        continue;
                    }
                    try
V
Vasilyev Nikita 已提交
257
                    {
258 259
                        lock = table->lockStructureForShare(
                                false, context.getCurrentQueryId(), context.getSettingsRef().lock_acquire_timeout);
V
Vasilyev Nikita 已提交
260
                    }
A
Alexander Kazakov 已提交
261 262 263 264 265 266
                    catch (const Exception & e)
                    {
                        if (e.code() == ErrorCodes::TABLE_IS_DROPPED)
                            continue;
                        throw;
                    }
A
Alexey Milovidov 已提交
267
                }
268 269

                ++rows_count;
270

271 272
                size_t src_index = 0;
                size_t res_index = 0;
273 274

                if (columns_mask[src_index++])
275
                    res_columns[res_index++]->insert(database_name);
276

277
                if (columns_mask[src_index++])
278
                    res_columns[res_index++]->insert(table_name);
279

A
Alexander Tokmakov 已提交
280 281 282
                if (columns_mask[src_index++])
                    res_columns[res_index++]->insert(tables_it->uuid());

283
                if (columns_mask[src_index++])
V
Vasilyev Nikita 已提交
284
                {
285
                    assert(table != nullptr);
286
                    res_columns[res_index++]->insert(table->getName());
V
Vasilyev Nikita 已提交
287
                }
288

289
                if (columns_mask[src_index++])
290
                    res_columns[res_index++]->insert(0u);  // is_temporary
291

292
                if (columns_mask[src_index++])
I
Fix.  
Igor Mineev 已提交
293
                {
294
                    assert(table != nullptr);
I
Igor Mineev 已提交
295
                    Array table_paths_array;
I
Fix.  
Igor Mineev 已提交
296
                    auto paths = table->getDataPaths();
I
Igor Mineev 已提交
297
                    table_paths_array.reserve(paths.size());
I
Igor Mineev 已提交
298
                    for (const String & path : paths)
I
Igor Mineev 已提交
299 300
                        table_paths_array.push_back(path);
                    res_columns[res_index++]->insert(table_paths_array);
I
Fix.  
Igor Mineev 已提交
301
                }
302 303

                if (columns_mask[src_index++])
A
alesapin 已提交
304
                    res_columns[res_index++]->insert(database->getObjectMetadataPath(table_name));
305

306
                if (columns_mask[src_index++])
307
                    res_columns[res_index++]->insert(static_cast<UInt64>(database->getObjectMetadataModificationTime(table_name)));
308 309 310 311 312

                {
                    Array dependencies_table_name_array;
                    Array dependencies_database_name_array;
                    if (columns_mask[src_index] || columns_mask[src_index + 1])
313
                    {
314
                        const auto dependencies = DatabaseCatalog::instance().getDependencies(StorageID(database_name, table_name));
315

316 317 318 319
                        dependencies_table_name_array.reserve(dependencies.size());
                        dependencies_database_name_array.reserve(dependencies.size());
                        for (const auto & dependency : dependencies)
                        {
A
Alexander Tokmakov 已提交
320 321
                            dependencies_table_name_array.push_back(dependency.table_name);
                            dependencies_database_name_array.push_back(dependency.database_name);
322 323 324
                        }
                    }

325 326
                    if (columns_mask[src_index++])
                        res_columns[res_index++]->insert(dependencies_database_name_array);
327

328 329 330
                    if (columns_mask[src_index++])
                        res_columns[res_index++]->insert(dependencies_table_name_array);
                }
Z
zhang2014 已提交
331

332 333
                if (columns_mask[src_index] || columns_mask[src_index + 1])
                {
334
                    ASTPtr ast = database->tryGetCreateTableQuery(table_name);
335

336 337
                    if (columns_mask[src_index++])
                        res_columns[res_index++]->insert(ast ? queryToString(ast) : "");
338

339 340 341
                    if (columns_mask[src_index++])
                    {
                        String engine_full;
342

343 344
                        if (ast)
                        {
I
Ivan Lezhankin 已提交
345 346
                            const auto & ast_create = ast->as<ASTCreateQuery &>();
                            if (ast_create.storage)
347
                            {
I
Ivan Lezhankin 已提交
348
                                engine_full = queryToString(*ast_create.storage);
349 350 351 352 353 354

                                static const char * const extra_head = " ENGINE = ";
                                if (startsWith(engine_full, extra_head))
                                    engine_full = engine_full.substr(strlen(extra_head));
                            }
                        }
355

356 357 358
                        res_columns[res_index++]->insert(engine_full);
                    }
                }
359
                else
360
                    src_index += 2;
361 362 363 364

                ASTPtr expression_ptr;
                if (columns_mask[src_index++])
                {
365
                    assert(table != nullptr);
366
                    if ((expression_ptr = table->getPartitionKeyAST()))
367 368 369 370 371
                        res_columns[res_index++]->insert(queryToString(expression_ptr));
                    else
                        res_columns[res_index++]->insertDefault();
                }

372 373
                if (columns_mask[src_index++])
                {
374
                    assert(table != nullptr);
A
alesapin 已提交
375
                    if ((expression_ptr = table->getSortingKey().expression_list_ast))
376 377 378 379 380
                        res_columns[res_index++]->insert(queryToString(expression_ptr));
                    else
                        res_columns[res_index++]->insertDefault();
                }

381 382
                if (columns_mask[src_index++])
                {
383
                    assert(table != nullptr);
A
alesapin 已提交
384
                    if ((expression_ptr = table->getPrimaryKey().expression_list_ast))
385 386 387 388 389 390 391
                        res_columns[res_index++]->insert(queryToString(expression_ptr));
                    else
                        res_columns[res_index++]->insertDefault();
                }

                if (columns_mask[src_index++])
                {
392
                    assert(table != nullptr);
393
                    if ((expression_ptr = table->getSamplingKeyAST()))
394 395 396 397
                        res_columns[res_index++]->insert(queryToString(expression_ptr));
                    else
                        res_columns[res_index++]->insertDefault();
                }
398 399 400

                if (columns_mask[src_index++])
                {
401
                    assert(table != nullptr);
402 403 404 405 406 407
                    auto policy = table->getStoragePolicy();
                    if (policy)
                        res_columns[res_index++]->insert(policy->getName());
                    else
                        res_columns[res_index++]->insertDefault();
                }
408 409 410 411 412 413 414 415 416 417

                if (columns_mask[src_index++])
                {
                    assert(table != nullptr);
                    auto total_rows = table->totalRows();
                    if (total_rows)
                        res_columns[res_index++]->insert(*total_rows);
                    else
                        res_columns[res_index++]->insertDefault();
                }
418 419 420 421 422 423 424 425 426 427

                if (columns_mask[src_index++])
                {
                    assert(table != nullptr);
                    auto total_bytes = table->totalBytes();
                    if (total_bytes)
                        res_columns[res_index++]->insert(*total_bytes);
                    else
                        res_columns[res_index++]->insertDefault();
                }
428 429
            }
        }
430

431 432
        UInt64 num_rows = res_columns.at(0)->size();
        return Chunk(std::move(res_columns), num_rows);
433 434 435
    }
private:
    std::vector<UInt8> columns_mask;
A
Alexey Milovidov 已提交
436
    UInt64 max_block_size;
437 438
    ColumnPtr databases;
    size_t database_idx = 0;
A
alesapin 已提交
439
    DatabaseTablesIteratorPtr tables_it;
440 441 442 443 444
    const Context context;
    bool done = false;
    DatabasePtr database;
    std::string database_name;
};
445 446


447
Pipes StorageSystemTables::read(
448 449 450
    const Names & column_names,
    const SelectQueryInfo & query_info,
    const Context & context,
451
    QueryProcessingStage::Enum /*processed_stage*/,
452
    const size_t max_block_size,
453 454 455
    const unsigned /*num_streams*/)
{
    check(column_names);
456

457
    /// Create a mask of what columns are needed in the result.
458

459
    NameSet names_set(column_names.begin(), column_names.end());
460

461 462
    Block sample_block = getSampleBlock();
    Block res_block;
463

464 465 466 467 468 469 470
    std::vector<UInt8> columns_mask(sample_block.columns());
    for (size_t i = 0, size = columns_mask.size(); i < size; ++i)
    {
        if (names_set.count(sample_block.getByPosition(i).name))
        {
            columns_mask[i] = 1;
            res_block.insert(sample_block.getByPosition(i));
471 472 473
        }
    }

474
    ColumnPtr filtered_databases_column = getFilteredDatabases(query_info.query, context);
475 476 477 478 479 480

    Pipes pipes;
    pipes.emplace_back(std::make_shared<TablesBlockSource>(
        std::move(columns_mask), std::move(res_block), max_block_size, std::move(filtered_databases_column), context));

    return pipes;
481 482
}

483
}