StorageSystemTables.cpp 21.1 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
#include <Storages/System/StorageSystemTables.h>
7
#include <Storages/SelectQueryInfo.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>
K
kreuzerkrieg 已提交
18
#include <Disks/IStoragePolicy.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 34
StorageSystemTables::StorageSystemTables(const StorageID & table_id_)
    : IStorage(table_id_)
35
{
A
alesapin 已提交
36 37
    StorageInMemoryMetadata storage_metadata;
    storage_metadata.setColumns(ColumnsDescription(
A
Alexey Milovidov 已提交
38
    {
A
Alexey Milovidov 已提交
39 40
        {"database", std::make_shared<DataTypeString>()},
        {"name", std::make_shared<DataTypeString>()},
A
Alexander Tokmakov 已提交
41
        {"uuid", std::make_shared<DataTypeUUID>()},
A
Alexey Milovidov 已提交
42 43
        {"engine", std::make_shared<DataTypeString>()},
        {"is_temporary", std::make_shared<DataTypeUInt8>()},
I
Bugfix  
Igor Mineev 已提交
44
        {"data_paths", std::make_shared<DataTypeArray>(std::make_shared<DataTypeString>())},
45
        {"metadata_path", std::make_shared<DataTypeString>()},
46
        {"metadata_modification_time", std::make_shared<DataTypeDateTime>()},
47 48
        {"dependencies_database", std::make_shared<DataTypeArray>(std::make_shared<DataTypeString>())},
        {"dependencies_table", std::make_shared<DataTypeArray>(std::make_shared<DataTypeString>())},
49
        {"create_table_query", std::make_shared<DataTypeString>()},
50 51
        {"engine_full", std::make_shared<DataTypeString>()},
        {"partition_key", std::make_shared<DataTypeString>()},
52 53 54
        {"sorting_key", std::make_shared<DataTypeString>()},
        {"primary_key", std::make_shared<DataTypeString>()},
        {"sampling_key", std::make_shared<DataTypeString>()},
55
        {"storage_policy", std::make_shared<DataTypeString>()},
56
        {"total_rows", std::make_shared<DataTypeNullable>(std::make_shared<DataTypeUInt64>())},
57
        {"total_bytes", std::make_shared<DataTypeNullable>(std::make_shared<DataTypeUInt64>())},
58 59
        {"lifetime_rows", std::make_shared<DataTypeNullable>(std::make_shared<DataTypeUInt64>())},
        {"lifetime_bytes", std::make_shared<DataTypeNullable>(std::make_shared<DataTypeUInt64>())},
60
    }));
A
alesapin 已提交
61
    setInMemoryMetadata(storage_metadata);
62 63
}

64

65
static ColumnPtr getFilteredDatabases(const ASTPtr & query, const Context & context)
66
{
67
    MutableColumnPtr column = ColumnString::create();
68 69 70 71 72 73 74 75 76

    const auto databases = DatabaseCatalog::instance().getDatabases();
    for (const auto & database_name : databases | boost::adaptors::map_keys)
    {
        if (database_name == DatabaseCatalog::TEMPORARY_DATABASE)
            continue; /// We don't want to show the internal database for temporary tables in system.tables

        column->insert(database_name);
    }
77

78
    Block block { ColumnWithTypeAndName(std::move(column), std::make_shared<DataTypeString>(), "database") };
79
    VirtualColumnUtils::filterBlockWithQuery(query, block, context);
80
    return block.getByPosition(0).column;
81 82
}

A
alexey-milovidov 已提交
83 84
/// 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 已提交
85
static bool needLockStructure(const DatabasePtr & database, const Block & header)
V
fix  
Vasilyev Nikita 已提交
86
{
V
fix  
Vasilyev Nikita 已提交
87 88 89
    if (database->getEngineName() != "Lazy")
        return true;

A
Alexander Tokmakov 已提交
90
    static const std::set<std::string> columns_without_lock = { "database", "name", "uuid", "metadata_modification_time" };
A
alexey-milovidov 已提交
91
    for (const auto & column : header.getColumnsWithTypeAndName())
V
fix  
Vasilyev Nikita 已提交
92 93
    {
        if (columns_without_lock.find(column.name) == columns_without_lock.end())
V
fix  
Vasilyev Nikita 已提交
94 95 96 97
            return true;
    }
    return false;
}
98

99
class TablesBlockSource : public SourceWithProgress
100
{
101
public:
102
    TablesBlockSource(
K
kreuzerkrieg 已提交
103
        std::vector<UInt8> columns_mask_,
104
        Block header,
K
kreuzerkrieg 已提交
105 106 107
        UInt64 max_block_size_,
        ColumnPtr databases_,
        const Context & context_)
108 109
        : SourceWithProgress(std::move(header))
        , columns_mask(std::move(columns_mask_))
110 111 112
        , max_block_size(max_block_size_)
        , databases(std::move(databases_))
        , context(context_) {}
113 114 115 116

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

protected:
117
    Chunk generate() override
118 119 120
    {
        if (done)
            return {};
121

122
        MutableColumns res_columns = getPort().getHeader().cloneEmptyColumns();
123

124 125
        const auto access = context.getAccess();
        const bool check_access_for_databases = !access->isGranted(AccessType::SHOW_TABLES);
126

127 128 129 130 131
        size_t rows_count = 0;
        while (rows_count < max_block_size)
        {
            if (tables_it && !tables_it->isValid())
                ++database_idx;
132

133 134 135
            while (database_idx < databases->size() && (!tables_it || !tables_it->isValid()))
            {
                database_name = databases->getDataAt(database_idx).toString();
136
                database = DatabaseCatalog::instance().tryGetDatabase(database_name);
137

138
                if (!database)
139 140 141 142 143
                {
                    /// Database was deleted just now or the user has no access.
                    ++database_idx;
                    continue;
                }
144

145 146
                break;
            }
147

A
Alexey Milovidov 已提交
148
            /// This is for temporary tables. They are output in single block regardless to max_block_size.
149 150 151 152 153
            if (database_idx >= databases->size())
            {
                if (context.hasSessionContext())
                {
                    Tables external_tables = context.getSessionContext().getExternalTables();
154

A
Alexey Milovidov 已提交
155
                    for (auto & table : external_tables)
156 157 158
                    {
                        size_t src_index = 0;
                        size_t res_index = 0;
159

160
                        // database
161 162
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insertDefault();
163

164
                        // name
165 166
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insert(table.first);
167

A
Alexander Tokmakov 已提交
168 169 170 171
                        // uuid
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insert(table.second->getStorageID().uuid);

172
                        // engine
173 174
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insert(table.second->getName());
175

176
                        // is_temporary
177
                        if (columns_mask[src_index++])
A
Amos Bird 已提交
178
                            res_columns[res_index++]->insert(1u);
179

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

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

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

192
                        // dependencies_database
193 194
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insertDefault();
195

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

200
                        // create_table_query
201
                        if (columns_mask[src_index++])
202 203 204 205 206
                        {
                            auto temp_db = DatabaseCatalog::instance().getDatabaseForTemporaryTables();
                            ASTPtr ast = temp_db ? temp_db->tryGetCreateTableQuery(table.second->getStorageID().getTableName(), context) : nullptr;
                            res_columns[res_index++]->insert(ast ? queryToString(ast) : "");
                        }
207

208
                        // engine_full
209 210
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insert(table.second->getName());
211

212
                        // partition_key
213 214 215
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insertDefault();

216
                        // sorting_key
217 218 219
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insertDefault();

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

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

228
                        // storage_policy
229 230
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insertDefault();
231 232 233 234

                        // total_rows
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insertDefault();
235 236 237 238

                        // total_bytes
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insertDefault();
239 240 241 242 243 244 245 246

                        // lifetime_rows
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insertDefault();

                        // lifetime_bytes
                        if (columns_mask[src_index++])
                            res_columns[res_index++]->insertDefault();
247 248 249
                    }
                }

250
                UInt64 num_rows = res_columns.at(0)->size();
N
Nikolai Kochetov 已提交
251
                done = true;
252
                return Chunk(std::move(res_columns), num_rows);
253
            }
254

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

257
            if (!tables_it || !tables_it->isValid())
258
                tables_it = database->getTablesIterator(context);
V
fix  
Vasilyev Nikita 已提交
259

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

262
            for (; rows_count < max_block_size && tables_it->isValid(); tables_it->next())
263
            {
264
                auto table_name = tables_it->name();
265
                if (check_access_for_tables && !access->isGranted(AccessType::SHOW_TABLES, database_name, table_name))
266
                    continue;
A
Alexey Milovidov 已提交
267

268
                StoragePtr table = nullptr;
A
alesapin 已提交
269
                TableLockHolder lock;
A
Alexey Milovidov 已提交
270

A
Alexander Kazakov 已提交
271
                if (need_lock_structure)
A
Alexey Milovidov 已提交
272
                {
A
Alexander Kazakov 已提交
273 274 275 276 277 278 279
                    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 已提交
280
                    {
A
alesapin 已提交
281
                        lock = table->lockForShare(context.getCurrentQueryId(), context.getSettingsRef().lock_acquire_timeout);
V
Vasilyev Nikita 已提交
282
                    }
A
Alexander Kazakov 已提交
283 284 285 286 287 288
                    catch (const Exception & e)
                    {
                        if (e.code() == ErrorCodes::TABLE_IS_DROPPED)
                            continue;
                        throw;
                    }
A
Alexey Milovidov 已提交
289
                }
290 291

                ++rows_count;
292

293 294
                size_t src_index = 0;
                size_t res_index = 0;
295 296

                if (columns_mask[src_index++])
297
                    res_columns[res_index++]->insert(database_name);
298

299
                if (columns_mask[src_index++])
300
                    res_columns[res_index++]->insert(table_name);
301

A
Alexander Tokmakov 已提交
302 303 304
                if (columns_mask[src_index++])
                    res_columns[res_index++]->insert(tables_it->uuid());

305
                if (columns_mask[src_index++])
V
Vasilyev Nikita 已提交
306
                {
307
                    assert(table != nullptr);
308
                    res_columns[res_index++]->insert(table->getName());
V
Vasilyev Nikita 已提交
309
                }
310

311
                if (columns_mask[src_index++])
312
                    res_columns[res_index++]->insert(0u);  // is_temporary
313

314
                if (columns_mask[src_index++])
I
Fix.  
Igor Mineev 已提交
315
                {
316
                    assert(table != nullptr);
I
Igor Mineev 已提交
317
                    Array table_paths_array;
I
Fix.  
Igor Mineev 已提交
318
                    auto paths = table->getDataPaths();
I
Igor Mineev 已提交
319
                    table_paths_array.reserve(paths.size());
I
Igor Mineev 已提交
320
                    for (const String & path : paths)
I
Igor Mineev 已提交
321 322
                        table_paths_array.push_back(path);
                    res_columns[res_index++]->insert(table_paths_array);
I
Fix.  
Igor Mineev 已提交
323
                }
324 325

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

328
                if (columns_mask[src_index++])
329
                    res_columns[res_index++]->insert(static_cast<UInt64>(database->getObjectMetadataModificationTime(table_name)));
330 331 332 333 334

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

338 339 340 341
                        dependencies_table_name_array.reserve(dependencies.size());
                        dependencies_database_name_array.reserve(dependencies.size());
                        for (const auto & dependency : dependencies)
                        {
A
Alexander Tokmakov 已提交
342 343
                            dependencies_table_name_array.push_back(dependency.table_name);
                            dependencies_database_name_array.push_back(dependency.database_name);
344 345 346
                        }
                    }

347 348
                    if (columns_mask[src_index++])
                        res_columns[res_index++]->insert(dependencies_database_name_array);
349

350 351 352
                    if (columns_mask[src_index++])
                        res_columns[res_index++]->insert(dependencies_table_name_array);
                }
Z
zhang2014 已提交
353

354 355
                if (columns_mask[src_index] || columns_mask[src_index + 1])
                {
356
                    ASTPtr ast = database->tryGetCreateTableQuery(table_name, context);
357

358 359 360 361
                    if (ast && !context.getSettingsRef().show_table_uuid_in_table_create_query_if_not_nil)
                    {
                        auto & create = ast->as<ASTCreateQuery &>();
                        create.uuid = UUIDHelpers::Nil;
362
                        create.to_inner_uuid = UUIDHelpers::Nil;
363 364
                    }

365 366
                    if (columns_mask[src_index++])
                        res_columns[res_index++]->insert(ast ? queryToString(ast) : "");
367

368 369 370
                    if (columns_mask[src_index++])
                    {
                        String engine_full;
371

372 373
                        if (ast)
                        {
I
Ivan Lezhankin 已提交
374 375
                            const auto & ast_create = ast->as<ASTCreateQuery &>();
                            if (ast_create.storage)
376
                            {
I
Ivan Lezhankin 已提交
377
                                engine_full = queryToString(*ast_create.storage);
378 379 380 381 382 383

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

385 386 387
                        res_columns[res_index++]->insert(engine_full);
                    }
                }
388
                else
389
                    src_index += 2;
390

A
alesapin 已提交
391 392 393 394
                StorageMetadataPtr metadata_snapshot;
                if (table != nullptr)
                    metadata_snapshot = table->getInMemoryMetadataPtr();

395 396 397
                ASTPtr expression_ptr;
                if (columns_mask[src_index++])
                {
A
alesapin 已提交
398
                    assert(metadata_snapshot != nullptr);
399
                    if ((expression_ptr = metadata_snapshot->getPartitionKeyAST()))
400 401 402 403 404
                        res_columns[res_index++]->insert(queryToString(expression_ptr));
                    else
                        res_columns[res_index++]->insertDefault();
                }

405 406
                if (columns_mask[src_index++])
                {
A
alesapin 已提交
407
                    assert(metadata_snapshot != nullptr);
A
alesapin 已提交
408
                    if ((expression_ptr = metadata_snapshot->getSortingKey().expression_list_ast))
409 410 411 412 413
                        res_columns[res_index++]->insert(queryToString(expression_ptr));
                    else
                        res_columns[res_index++]->insertDefault();
                }

414 415
                if (columns_mask[src_index++])
                {
A
alesapin 已提交
416
                    assert(metadata_snapshot != nullptr);
A
alesapin 已提交
417
                    if ((expression_ptr = metadata_snapshot->getPrimaryKey().expression_list_ast))
418 419 420 421 422 423 424
                        res_columns[res_index++]->insert(queryToString(expression_ptr));
                    else
                        res_columns[res_index++]->insertDefault();
                }

                if (columns_mask[src_index++])
                {
A
alesapin 已提交
425
                    assert(metadata_snapshot != nullptr);
426
                    if ((expression_ptr = metadata_snapshot->getSamplingKeyAST()))
427 428 429 430
                        res_columns[res_index++]->insert(queryToString(expression_ptr));
                    else
                        res_columns[res_index++]->insertDefault();
                }
431 432 433

                if (columns_mask[src_index++])
                {
434
                    assert(table != nullptr);
435 436 437 438 439 440
                    auto policy = table->getStoragePolicy();
                    if (policy)
                        res_columns[res_index++]->insert(policy->getName());
                    else
                        res_columns[res_index++]->insertDefault();
                }
441 442 443 444

                if (columns_mask[src_index++])
                {
                    assert(table != nullptr);
N
nikitamikhaylov 已提交
445
                    auto total_rows = table->totalRows(context.getSettingsRef());
446 447 448 449 450
                    if (total_rows)
                        res_columns[res_index++]->insert(*total_rows);
                    else
                        res_columns[res_index++]->insertDefault();
                }
451 452 453 454

                if (columns_mask[src_index++])
                {
                    assert(table != nullptr);
N
nikitamikhaylov 已提交
455
                    auto total_bytes = table->totalBytes(context.getSettingsRef());
456 457 458 459 460
                    if (total_bytes)
                        res_columns[res_index++]->insert(*total_bytes);
                    else
                        res_columns[res_index++]->insertDefault();
                }
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480

                if (columns_mask[src_index++])
                {
                    assert(table != nullptr);
                    auto lifetime_rows = table->lifetimeRows();
                    if (lifetime_rows)
                        res_columns[res_index++]->insert(*lifetime_rows);
                    else
                        res_columns[res_index++]->insertDefault();
                }

                if (columns_mask[src_index++])
                {
                    assert(table != nullptr);
                    auto lifetime_bytes = table->lifetimeBytes();
                    if (lifetime_bytes)
                        res_columns[res_index++]->insert(*lifetime_bytes);
                    else
                        res_columns[res_index++]->insertDefault();
                }
481 482
            }
        }
483

484 485
        UInt64 num_rows = res_columns.at(0)->size();
        return Chunk(std::move(res_columns), num_rows);
486 487 488
    }
private:
    std::vector<UInt8> columns_mask;
A
Alexey Milovidov 已提交
489
    UInt64 max_block_size;
490 491
    ColumnPtr databases;
    size_t database_idx = 0;
A
alesapin 已提交
492
    DatabaseTablesIteratorPtr tables_it;
493 494 495 496 497
    const Context context;
    bool done = false;
    DatabasePtr database;
    std::string database_name;
};
498 499


N
Nikolai Kochetov 已提交
500
Pipe StorageSystemTables::read(
501
    const Names & column_names,
502
    const StorageMetadataPtr & metadata_snapshot,
503
    SelectQueryInfo & query_info,
504
    const Context & context,
505
    QueryProcessingStage::Enum /*processed_stage*/,
506
    const size_t max_block_size,
507 508
    const unsigned /*num_streams*/)
{
A
alesapin 已提交
509
    metadata_snapshot->check(column_names, getVirtuals(), getStorageID());
510

511
    /// Create a mask of what columns are needed in the result.
512

513
    NameSet names_set(column_names.begin(), column_names.end());
514

515
    Block sample_block = metadata_snapshot->getSampleBlock();
516
    Block res_block;
517

518 519 520 521 522 523 524
    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));
525 526 527
        }
    }

528
    ColumnPtr filtered_databases_column = getFilteredDatabases(query_info.query, context);
529

N
Nikolai Kochetov 已提交
530
    return Pipe(std::make_shared<TablesBlockSource>(
531
        std::move(columns_mask), std::move(res_block), max_block_size, std::move(filtered_databases_column), context));
532 533
}

534
}