2018-08-25 16:07:48 +00:00
|
|
|
#include <optional>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Storages/System/StorageSystemColumns.h>
|
|
|
|
#include <Storages/MergeTree/MergeTreeData.h>
|
|
|
|
#include <Columns/ColumnsNumber.h>
|
|
|
|
#include <Columns/ColumnString.h>
|
|
|
|
#include <DataTypes/DataTypeString.h>
|
|
|
|
#include <DataTypes/DataTypesNumber.h>
|
2018-08-25 16:07:48 +00:00
|
|
|
#include <DataStreams/NullBlockInputStream.h>
|
2017-11-20 05:22:54 +00:00
|
|
|
#include <Storages/VirtualColumnUtils.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Parsers/queryToString.h>
|
2018-08-25 16:07:48 +00:00
|
|
|
#include <Parsers/ASTSelectQuery.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Databases/IDatabase.h>
|
2016-03-19 01:18:49 +00:00
|
|
|
|
2015-04-24 12:26:23 +00:00
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
2018-08-25 16:07:48 +00:00
|
|
|
namespace ErrorCodes
|
2018-07-24 18:46:23 +00:00
|
|
|
{
|
2018-08-25 16:07:48 +00:00
|
|
|
extern const int LOGICAL_ERROR;
|
2019-08-27 23:47:30 +00:00
|
|
|
extern const int TABLE_IS_DROPPED;
|
2018-08-25 16:07:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
StorageSystemColumns::StorageSystemColumns(const std::string & name_)
|
|
|
|
: name(name_)
|
|
|
|
{
|
|
|
|
setColumns(ColumnsDescription(
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
{ "database", std::make_shared<DataTypeString>() },
|
|
|
|
{ "table", std::make_shared<DataTypeString>() },
|
|
|
|
{ "name", std::make_shared<DataTypeString>() },
|
|
|
|
{ "type", std::make_shared<DataTypeString>() },
|
2017-05-24 19:54:25 +00:00
|
|
|
{ "default_kind", std::make_shared<DataTypeString>() },
|
2017-04-01 07:20:54 +00:00
|
|
|
{ "default_expression", std::make_shared<DataTypeString>() },
|
2017-05-24 19:54:25 +00:00
|
|
|
{ "data_compressed_bytes", std::make_shared<DataTypeUInt64>() },
|
2017-04-01 07:20:54 +00:00
|
|
|
{ "data_uncompressed_bytes", std::make_shared<DataTypeUInt64>() },
|
|
|
|
{ "marks_bytes", std::make_shared<DataTypeUInt64>() },
|
2018-10-14 15:30:06 +00:00
|
|
|
{ "comment", std::make_shared<DataTypeString>() },
|
2018-11-19 17:21:34 +00:00
|
|
|
{ "is_in_partition_key", std::make_shared<DataTypeUInt8>() },
|
2019-05-03 18:07:59 +00:00
|
|
|
{ "is_in_sorting_key", std::make_shared<DataTypeUInt8>() },
|
|
|
|
{ "is_in_primary_key", std::make_shared<DataTypeUInt8>() },
|
|
|
|
{ "is_in_sampling_key", std::make_shared<DataTypeUInt8>() },
|
|
|
|
{ "compression_codec", std::make_shared<DataTypeString>() },
|
2018-08-25 16:07:48 +00:00
|
|
|
}));
|
2015-04-24 12:26:23 +00:00
|
|
|
}
|
|
|
|
|
2018-08-25 16:07:48 +00:00
|
|
|
|
|
|
|
namespace
|
2015-04-24 12:26:23 +00:00
|
|
|
{
|
2018-08-25 16:07:48 +00:00
|
|
|
using Storages = std::map<std::pair<std::string, std::string>, StoragePtr>;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-01-23 14:48:50 +00:00
|
|
|
class ColumnsBlockInputStream : public IBlockInputStream
|
2018-08-25 16:07:48 +00:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
ColumnsBlockInputStream(
|
2019-08-03 11:02:40 +00:00
|
|
|
const std::vector<UInt8> & columns_mask_,
|
|
|
|
const Block & header_,
|
|
|
|
UInt64 max_block_size_,
|
|
|
|
ColumnPtr databases_,
|
|
|
|
ColumnPtr tables_,
|
|
|
|
Storages storages_,
|
2019-02-27 18:26:24 +00:00
|
|
|
String query_id_)
|
2019-08-03 11:02:40 +00:00
|
|
|
: columns_mask(columns_mask_), header(header_), max_block_size(max_block_size_)
|
|
|
|
, databases(databases_), tables(tables_), storages(std::move(storages_))
|
2019-03-01 01:08:12 +00:00
|
|
|
, query_id(std::move(query_id_)), total_tables(tables->size())
|
2019-02-27 18:26:24 +00:00
|
|
|
{
|
|
|
|
}
|
2018-08-25 16:07:48 +00:00
|
|
|
|
|
|
|
String getName() const override { return "Columns"; }
|
|
|
|
Block getHeader() const override { return header; }
|
|
|
|
|
|
|
|
protected:
|
|
|
|
Block readImpl() override
|
|
|
|
{
|
|
|
|
if (db_table_num >= total_tables)
|
|
|
|
return {};
|
|
|
|
|
|
|
|
Block res = header;
|
|
|
|
MutableColumns res_columns = header.cloneEmptyColumns();
|
|
|
|
size_t rows_count = 0;
|
|
|
|
|
|
|
|
while (rows_count < max_block_size && db_table_num < total_tables)
|
|
|
|
{
|
|
|
|
const std::string database_name = (*databases)[db_table_num].get<std::string>();
|
|
|
|
const std::string table_name = (*tables)[db_table_num].get<std::string>();
|
|
|
|
++db_table_num;
|
|
|
|
|
2019-03-14 15:20:51 +00:00
|
|
|
ColumnsDescription columns;
|
2018-11-27 17:07:10 +00:00
|
|
|
Names cols_required_for_partition_key;
|
|
|
|
Names cols_required_for_sorting_key;
|
|
|
|
Names cols_required_for_primary_key;
|
|
|
|
Names cols_required_for_sampling;
|
2018-08-25 16:07:48 +00:00
|
|
|
MergeTreeData::ColumnSizeByName column_sizes;
|
|
|
|
|
|
|
|
{
|
|
|
|
StoragePtr storage = storages.at(std::make_pair(database_name, table_name));
|
2019-03-07 18:04:47 +00:00
|
|
|
TableStructureReadLockHolder table_lock;
|
2018-08-25 16:07:48 +00:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
2019-03-07 18:04:47 +00:00
|
|
|
table_lock = storage->lockStructureForShare(false, query_id);
|
2018-08-25 16:07:48 +00:00
|
|
|
}
|
|
|
|
catch (const Exception & e)
|
|
|
|
{
|
|
|
|
/** There are case when IStorage::drop was called,
|
|
|
|
* but we still own the object.
|
|
|
|
* Then table will throw exception at attempt to lock it.
|
|
|
|
* Just skip the table.
|
|
|
|
*/
|
|
|
|
if (e.code() == ErrorCodes::TABLE_IS_DROPPED)
|
|
|
|
continue;
|
|
|
|
else
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
|
2019-03-14 15:20:51 +00:00
|
|
|
columns = storage->getColumns();
|
2018-08-25 16:07:48 +00:00
|
|
|
|
2018-11-27 17:07:10 +00:00
|
|
|
cols_required_for_partition_key = storage->getColumnsRequiredForPartitionKey();
|
|
|
|
cols_required_for_sorting_key = storage->getColumnsRequiredForSortingKey();
|
|
|
|
cols_required_for_primary_key = storage->getColumnsRequiredForPrimaryKey();
|
|
|
|
cols_required_for_sampling = storage->getColumnsRequiredForSampling();
|
2018-08-25 16:07:48 +00:00
|
|
|
|
2019-07-16 17:13:12 +00:00
|
|
|
column_sizes = storage->getColumnSizes();
|
2018-08-25 16:07:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto & column : columns)
|
|
|
|
{
|
2019-08-08 15:48:32 +00:00
|
|
|
if (column.is_virtual)
|
|
|
|
continue;
|
|
|
|
|
2018-08-25 16:07:48 +00:00
|
|
|
size_t src_index = 0;
|
|
|
|
size_t res_index = 0;
|
|
|
|
|
|
|
|
if (columns_mask[src_index++])
|
|
|
|
res_columns[res_index++]->insert(database_name);
|
|
|
|
if (columns_mask[src_index++])
|
|
|
|
res_columns[res_index++]->insert(table_name);
|
|
|
|
if (columns_mask[src_index++])
|
|
|
|
res_columns[res_index++]->insert(column.name);
|
|
|
|
if (columns_mask[src_index++])
|
|
|
|
res_columns[res_index++]->insert(column.type->getName());
|
|
|
|
|
2019-03-14 15:20:51 +00:00
|
|
|
if (column.default_desc.expression)
|
2018-08-25 16:07:48 +00:00
|
|
|
{
|
2019-03-14 15:20:51 +00:00
|
|
|
if (columns_mask[src_index++])
|
|
|
|
res_columns[res_index++]->insert(toString(column.default_desc.kind));
|
|
|
|
if (columns_mask[src_index++])
|
|
|
|
res_columns[res_index++]->insert(queryToString(column.default_desc.expression));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (columns_mask[src_index++])
|
|
|
|
res_columns[res_index++]->insertDefault();
|
|
|
|
if (columns_mask[src_index++])
|
|
|
|
res_columns[res_index++]->insertDefault();
|
2018-08-25 16:07:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
const auto it = column_sizes.find(column.name);
|
|
|
|
if (it == std::end(column_sizes))
|
|
|
|
{
|
|
|
|
if (columns_mask[src_index++])
|
|
|
|
res_columns[res_index++]->insertDefault();
|
|
|
|
if (columns_mask[src_index++])
|
|
|
|
res_columns[res_index++]->insertDefault();
|
|
|
|
if (columns_mask[src_index++])
|
|
|
|
res_columns[res_index++]->insertDefault();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (columns_mask[src_index++])
|
2018-10-22 08:54:54 +00:00
|
|
|
res_columns[res_index++]->insert(it->second.data_compressed);
|
2018-08-25 16:07:48 +00:00
|
|
|
if (columns_mask[src_index++])
|
2018-10-22 08:54:54 +00:00
|
|
|
res_columns[res_index++]->insert(it->second.data_uncompressed);
|
2018-08-25 16:07:48 +00:00
|
|
|
if (columns_mask[src_index++])
|
2018-10-22 08:54:54 +00:00
|
|
|
res_columns[res_index++]->insert(it->second.marks);
|
2018-08-25 16:07:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-14 15:20:51 +00:00
|
|
|
if (columns_mask[src_index++])
|
|
|
|
res_columns[res_index++]->insert(column.comment);
|
2018-10-14 15:30:06 +00:00
|
|
|
|
2018-11-09 12:02:08 +00:00
|
|
|
{
|
2018-11-19 17:21:34 +00:00
|
|
|
auto find_in_vector = [&key = column.name](const Names& names)
|
|
|
|
{
|
2018-11-19 14:31:16 +00:00
|
|
|
return std::find(names.cbegin(), names.cend(), key) != names.end();
|
|
|
|
};
|
|
|
|
|
|
|
|
if (columns_mask[src_index++])
|
2018-11-27 17:07:10 +00:00
|
|
|
res_columns[res_index++]->insert(find_in_vector(cols_required_for_partition_key));
|
2018-11-19 14:31:16 +00:00
|
|
|
if (columns_mask[src_index++])
|
2018-11-27 17:07:10 +00:00
|
|
|
res_columns[res_index++]->insert(find_in_vector(cols_required_for_sorting_key));
|
2018-11-19 14:31:16 +00:00
|
|
|
if (columns_mask[src_index++])
|
2018-11-27 17:07:10 +00:00
|
|
|
res_columns[res_index++]->insert(find_in_vector(cols_required_for_primary_key));
|
2018-11-19 14:31:16 +00:00
|
|
|
if (columns_mask[src_index++])
|
2018-11-27 17:07:10 +00:00
|
|
|
res_columns[res_index++]->insert(find_in_vector(cols_required_for_sampling));
|
2018-11-09 12:02:08 +00:00
|
|
|
}
|
|
|
|
|
2019-03-14 15:20:51 +00:00
|
|
|
if (columns_mask[src_index++])
|
2018-12-21 14:40:20 +00:00
|
|
|
{
|
2019-03-14 15:20:51 +00:00
|
|
|
if (column.codec)
|
|
|
|
res_columns[res_index++]->insert("CODEC(" + column.codec->getCodecDesc() + ")");
|
2018-12-21 14:40:20 +00:00
|
|
|
else
|
2019-03-14 15:20:51 +00:00
|
|
|
res_columns[res_index++]->insertDefault();
|
2018-12-21 14:40:20 +00:00
|
|
|
}
|
|
|
|
|
2018-08-25 16:07:48 +00:00
|
|
|
++rows_count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
res.setColumns(std::move(res_columns));
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::vector<UInt8> columns_mask;
|
|
|
|
Block header;
|
2019-02-10 16:55:12 +00:00
|
|
|
UInt64 max_block_size;
|
2018-08-25 16:07:48 +00:00
|
|
|
ColumnPtr databases;
|
|
|
|
ColumnPtr tables;
|
|
|
|
Storages storages;
|
2019-02-27 18:26:24 +00:00
|
|
|
String query_id;
|
2018-08-25 16:07:48 +00:00
|
|
|
size_t db_table_num = 0;
|
|
|
|
size_t total_tables;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
BlockInputStreams StorageSystemColumns::read(
|
|
|
|
const Names & column_names,
|
|
|
|
const SelectQueryInfo & query_info,
|
|
|
|
const Context & context,
|
2018-09-08 11:29:23 +00:00
|
|
|
QueryProcessingStage::Enum /*processed_stage*/,
|
2019-02-18 23:38:44 +00:00
|
|
|
const size_t max_block_size,
|
2018-08-25 16:07:48 +00:00
|
|
|
const unsigned /*num_streams*/)
|
|
|
|
{
|
|
|
|
check(column_names);
|
|
|
|
|
|
|
|
/// Create a mask of what columns are needed in the result.
|
|
|
|
|
|
|
|
NameSet names_set(column_names.begin(), column_names.end());
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2018-08-25 16:07:48 +00:00
|
|
|
Block sample_block = getSampleBlock();
|
|
|
|
Block res_block;
|
|
|
|
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Block block_to_filter;
|
|
|
|
Storages storages;
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
Databases databases = context.getDatabases();
|
|
|
|
|
|
|
|
/// Add `database` column.
|
2017-12-16 00:49:03 +00:00
|
|
|
MutableColumnPtr database_column_mut = ColumnString::create();
|
2017-04-01 07:20:54 +00:00
|
|
|
for (const auto & database : databases)
|
2018-08-13 09:11:58 +00:00
|
|
|
{
|
2019-10-08 00:27:57 +00:00
|
|
|
/// We are skipping "Lazy" database because we cannot afford initialization of all its tables.
|
|
|
|
/// This should be documented.
|
|
|
|
|
|
|
|
if (context.hasDatabaseAccessRights(database.first)
|
|
|
|
&& database.second->getEngineName() != "Lazy")
|
2018-08-13 09:11:58 +00:00
|
|
|
database_column_mut->insert(database.first);
|
|
|
|
}
|
|
|
|
|
2017-12-16 00:49:03 +00:00
|
|
|
block_to_filter.insert(ColumnWithTypeAndName(std::move(database_column_mut), std::make_shared<DataTypeString>(), "database"));
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
/// Filter block with `database` column.
|
2017-12-16 00:49:03 +00:00
|
|
|
VirtualColumnUtils::filterBlockWithQuery(query_info.query, block_to_filter, context);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2017-12-16 00:49:03 +00:00
|
|
|
if (!block_to_filter.rows())
|
2018-08-25 16:07:48 +00:00
|
|
|
return {std::make_shared<NullBlockInputStream>(res_block)};
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2018-08-25 16:07:48 +00:00
|
|
|
ColumnPtr & database_column = block_to_filter.getByName("database").column;
|
2017-04-01 07:20:54 +00:00
|
|
|
size_t rows = database_column->size();
|
|
|
|
|
|
|
|
/// Add `table` column.
|
2017-12-16 00:49:03 +00:00
|
|
|
MutableColumnPtr table_column_mut = ColumnString::create();
|
2017-12-15 21:32:25 +00:00
|
|
|
IColumn::Offsets offsets(rows);
|
2017-04-01 07:20:54 +00:00
|
|
|
for (size_t i = 0; i < rows; ++i)
|
|
|
|
{
|
|
|
|
const std::string database_name = (*database_column)[i].get<std::string>();
|
|
|
|
const DatabasePtr database = databases.at(database_name);
|
|
|
|
offsets[i] = i ? offsets[i - 1] : 0;
|
|
|
|
|
2019-10-10 20:47:47 +00:00
|
|
|
for (auto iterator = database->getTablesIterator(context); iterator->isValid(); iterator->next())
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
const String & table_name = iterator->name();
|
|
|
|
storages.emplace(std::piecewise_construct,
|
|
|
|
std::forward_as_tuple(database_name, table_name),
|
|
|
|
std::forward_as_tuple(iterator->table()));
|
2017-12-16 00:49:03 +00:00
|
|
|
table_column_mut->insert(table_name);
|
2018-08-25 16:07:48 +00:00
|
|
|
++offsets[i];
|
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
|
2018-08-25 16:07:48 +00:00
|
|
|
database_column = database_column->replicate(offsets);
|
2017-12-16 00:49:03 +00:00
|
|
|
block_to_filter.insert(ColumnWithTypeAndName(std::move(table_column_mut), std::make_shared<DataTypeString>(), "table"));
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Filter block with `database` and `table` columns.
|
2017-12-16 00:49:03 +00:00
|
|
|
VirtualColumnUtils::filterBlockWithQuery(query_info.query, block_to_filter, context);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2017-12-16 00:49:03 +00:00
|
|
|
if (!block_to_filter.rows())
|
2018-08-25 16:07:48 +00:00
|
|
|
return {std::make_shared<NullBlockInputStream>(res_block)};
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2017-12-16 00:49:03 +00:00
|
|
|
ColumnPtr filtered_database_column = block_to_filter.getByName("database").column;
|
|
|
|
ColumnPtr filtered_table_column = block_to_filter.getByName("table").column;
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2018-08-25 16:07:48 +00:00
|
|
|
return {std::make_shared<ColumnsBlockInputStream>(
|
|
|
|
std::move(columns_mask), std::move(res_block), max_block_size,
|
2019-02-27 18:26:24 +00:00
|
|
|
std::move(filtered_database_column), std::move(filtered_table_column), std::move(storages),
|
|
|
|
context.getCurrentQueryId())};
|
2015-04-24 12:26:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|