2017-04-01 09:19:00 +00:00
|
|
|
#include <Storages/IStorage.h>
|
2019-05-17 14:34:25 +00:00
|
|
|
|
2020-04-21 20:23:44 +00:00
|
|
|
#include <sparsehash/dense_hash_map>
|
|
|
|
#include <sparsehash/dense_hash_set>
|
|
|
|
|
2018-12-25 23:11:36 +00:00
|
|
|
#include <Storages/AlterCommands.h>
|
2019-08-07 15:21:45 +00:00
|
|
|
#include <Parsers/ASTCreateQuery.h>
|
|
|
|
#include <Parsers/ASTSetQuery.h>
|
2020-02-10 15:50:12 +00:00
|
|
|
#include <Interpreters/Context.h>
|
2019-11-19 12:46:07 +00:00
|
|
|
#include <Common/StringUtils/StringUtils.h>
|
2019-10-08 18:42:22 +00:00
|
|
|
#include <Common/quoteString.h>
|
2020-05-20 12:16:55 +00:00
|
|
|
#include <Interpreters/ExpressionActions.h>
|
2017-01-21 04:24:28 +00:00
|
|
|
|
2019-10-21 16:26:29 +00:00
|
|
|
#include <Processors/Executors/TreeExecutorBlockInputStream.h>
|
2019-09-13 12:59:48 +00:00
|
|
|
|
2017-01-21 04:24:28 +00:00
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
2019-05-17 14:34:25 +00:00
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
2020-02-25 18:02:41 +00:00
|
|
|
extern const int LOGICAL_ERROR;
|
2019-05-17 14:34:25 +00:00
|
|
|
extern const int COLUMN_QUERIED_MORE_THAN_ONCE;
|
|
|
|
extern const int DUPLICATE_COLUMN;
|
|
|
|
extern const int EMPTY_LIST_OF_COLUMNS_PASSED;
|
|
|
|
extern const int EMPTY_LIST_OF_COLUMNS_QUERIED;
|
|
|
|
extern const int NO_SUCH_COLUMN_IN_TABLE;
|
|
|
|
extern const int NOT_FOUND_COLUMN_IN_BLOCK;
|
|
|
|
extern const int TYPE_MISMATCH;
|
2019-08-27 23:47:30 +00:00
|
|
|
extern const int TABLE_IS_DROPPED;
|
2019-12-26 18:17:05 +00:00
|
|
|
extern const int NOT_IMPLEMENTED;
|
2020-04-06 23:45:51 +00:00
|
|
|
extern const int DEADLOCK_AVOIDED;
|
2019-05-17 14:34:25 +00:00
|
|
|
}
|
|
|
|
|
2020-06-13 08:51:07 +00:00
|
|
|
const ColumnsDescription & IStorage::getColumns() const
|
2019-05-17 14:34:25 +00:00
|
|
|
{
|
2020-06-05 17:29:40 +00:00
|
|
|
return metadata.columns;
|
2019-05-17 14:34:25 +00:00
|
|
|
}
|
|
|
|
|
2020-06-13 08:51:07 +00:00
|
|
|
const IndicesDescription & IStorage::getSecondaryIndices() const
|
2019-05-17 14:34:25 +00:00
|
|
|
{
|
2020-06-05 17:29:40 +00:00
|
|
|
return metadata.secondary_indices;
|
2019-05-17 14:34:25 +00:00
|
|
|
}
|
|
|
|
|
2020-06-01 11:29:11 +00:00
|
|
|
bool IStorage::hasSecondaryIndices() const
|
2020-05-27 18:38:34 +00:00
|
|
|
{
|
2020-06-05 17:29:40 +00:00
|
|
|
return !metadata.secondary_indices.empty();
|
2020-05-27 18:38:34 +00:00
|
|
|
}
|
|
|
|
|
2020-06-13 08:51:07 +00:00
|
|
|
const ConstraintsDescription & IStorage::getConstraints() const
|
2019-05-19 06:08:25 +00:00
|
|
|
{
|
2020-06-05 17:29:40 +00:00
|
|
|
return metadata.constraints;
|
2019-05-19 06:08:25 +00:00
|
|
|
}
|
|
|
|
|
2019-05-17 14:34:25 +00:00
|
|
|
Block IStorage::getSampleBlock() const
|
|
|
|
{
|
|
|
|
Block res;
|
|
|
|
|
|
|
|
for (const auto & column : getColumns().getAllPhysical())
|
|
|
|
res.insert({column.type->createColumn(), column.type, column.name});
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2019-06-18 16:32:37 +00:00
|
|
|
Block IStorage::getSampleBlockWithVirtuals() const
|
|
|
|
{
|
|
|
|
auto res = getSampleBlock();
|
|
|
|
|
2020-04-27 17:46:51 +00:00
|
|
|
/// Virtual columns must be appended after ordinary, because user can
|
|
|
|
/// override them.
|
2020-04-27 13:55:30 +00:00
|
|
|
for (const auto & column : getVirtuals())
|
2019-06-18 16:32:37 +00:00
|
|
|
res.insert({column.type->createColumn(), column.type, column.name});
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2019-05-17 14:34:25 +00:00
|
|
|
Block IStorage::getSampleBlockNonMaterialized() const
|
|
|
|
{
|
|
|
|
Block res;
|
|
|
|
|
|
|
|
for (const auto & column : getColumns().getOrdinary())
|
|
|
|
res.insert({column.type->createColumn(), column.type, column.name});
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
Block IStorage::getSampleBlockForColumns(const Names & column_names) const
|
|
|
|
{
|
|
|
|
Block res;
|
|
|
|
|
|
|
|
std::unordered_map<String, DataTypePtr> columns_map;
|
2020-04-27 14:44:32 +00:00
|
|
|
|
|
|
|
NamesAndTypesList all_columns = getColumns().getAll();
|
2019-05-17 14:34:25 +00:00
|
|
|
for (const auto & elem : all_columns)
|
|
|
|
columns_map.emplace(elem.name, elem.type);
|
|
|
|
|
2020-04-27 17:46:51 +00:00
|
|
|
/// Virtual columns must be appended after ordinary, because user can
|
|
|
|
/// override them.
|
|
|
|
for (const auto & column : getVirtuals())
|
|
|
|
columns_map.emplace(column.name, column.type);
|
|
|
|
|
2019-05-17 14:34:25 +00:00
|
|
|
for (const auto & name : column_names)
|
|
|
|
{
|
|
|
|
auto it = columns_map.find(name);
|
|
|
|
if (it != columns_map.end())
|
|
|
|
{
|
|
|
|
res.insert({it->second->createColumn(), it->second, it->first});
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-04-24 10:20:03 +00:00
|
|
|
throw Exception(
|
|
|
|
"Column " + backQuote(name) + " not found in table " + getStorageID().getNameForLogs(), ErrorCodes::NOT_FOUND_COLUMN_IN_BLOCK);
|
2019-05-17 14:34:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
2020-04-16 12:31:57 +00:00
|
|
|
#if !defined(ARCADIA_BUILD)
|
|
|
|
using NamesAndTypesMap = google::dense_hash_map<StringRef, const IDataType *, StringRefHash>;
|
|
|
|
using UniqueStrings = google::dense_hash_set<StringRef, StringRefHash>;
|
|
|
|
#else
|
|
|
|
using NamesAndTypesMap = google::sparsehash::dense_hash_map<StringRef, const IDataType *, StringRefHash>;
|
|
|
|
using UniqueStrings = google::sparsehash::dense_hash_set<StringRef, StringRefHash>;
|
|
|
|
#endif
|
2019-05-17 14:34:25 +00:00
|
|
|
|
|
|
|
String listOfColumns(const NamesAndTypesList & available_columns)
|
|
|
|
{
|
|
|
|
std::stringstream ss;
|
|
|
|
for (auto it = available_columns.begin(); it != available_columns.end(); ++it)
|
|
|
|
{
|
|
|
|
if (it != available_columns.begin())
|
|
|
|
ss << ", ";
|
|
|
|
ss << it->name;
|
|
|
|
}
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
NamesAndTypesMap getColumnsMap(const NamesAndTypesList & columns)
|
|
|
|
{
|
|
|
|
NamesAndTypesMap res;
|
|
|
|
res.set_empty_key(StringRef());
|
|
|
|
|
|
|
|
for (const auto & column : columns)
|
|
|
|
res.insert({column.name, column.type.get()});
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
UniqueStrings initUniqueStrings()
|
|
|
|
{
|
|
|
|
UniqueStrings strings;
|
|
|
|
strings.set_empty_key(StringRef());
|
|
|
|
return strings;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-07 16:10:14 +00:00
|
|
|
void IStorage::check(const Names & column_names, bool include_virtuals) const
|
2019-05-17 14:34:25 +00:00
|
|
|
{
|
2019-08-07 16:10:14 +00:00
|
|
|
NamesAndTypesList available_columns = getColumns().getAllPhysical();
|
|
|
|
if (include_virtuals)
|
2020-04-28 10:38:57 +00:00
|
|
|
{
|
|
|
|
auto virtuals = getVirtuals();
|
|
|
|
available_columns.insert(available_columns.end(), virtuals.begin(), virtuals.end());
|
|
|
|
}
|
2019-08-07 16:10:14 +00:00
|
|
|
|
2019-05-17 14:34:25 +00:00
|
|
|
const String list_of_columns = listOfColumns(available_columns);
|
|
|
|
|
|
|
|
if (column_names.empty())
|
|
|
|
throw Exception("Empty list of columns queried. There are columns: " + list_of_columns, ErrorCodes::EMPTY_LIST_OF_COLUMNS_QUERIED);
|
|
|
|
|
|
|
|
const auto columns_map = getColumnsMap(available_columns);
|
|
|
|
|
|
|
|
auto unique_names = initUniqueStrings();
|
|
|
|
for (const auto & name : column_names)
|
|
|
|
{
|
|
|
|
if (columns_map.end() == columns_map.find(name))
|
|
|
|
throw Exception(
|
2019-12-10 20:47:05 +00:00
|
|
|
"There is no column with name " + backQuote(name) + " in table " + getStorageID().getNameForLogs() + ". There are columns: " + list_of_columns,
|
2019-05-17 14:34:25 +00:00
|
|
|
ErrorCodes::NO_SUCH_COLUMN_IN_TABLE);
|
|
|
|
|
|
|
|
if (unique_names.end() != unique_names.find(name))
|
|
|
|
throw Exception("Column " + name + " queried more than once", ErrorCodes::COLUMN_QUERIED_MORE_THAN_ONCE);
|
|
|
|
unique_names.insert(name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void IStorage::check(const NamesAndTypesList & provided_columns) const
|
|
|
|
{
|
|
|
|
const NamesAndTypesList & available_columns = getColumns().getAllPhysical();
|
|
|
|
const auto columns_map = getColumnsMap(available_columns);
|
|
|
|
|
|
|
|
auto unique_names = initUniqueStrings();
|
|
|
|
for (const NameAndTypePair & column : provided_columns)
|
|
|
|
{
|
|
|
|
auto it = columns_map.find(column.name);
|
|
|
|
if (columns_map.end() == it)
|
|
|
|
throw Exception(
|
|
|
|
"There is no column with name " + column.name + ". There are columns: " + listOfColumns(available_columns),
|
|
|
|
ErrorCodes::NO_SUCH_COLUMN_IN_TABLE);
|
|
|
|
|
|
|
|
if (!column.type->equals(*it->second))
|
|
|
|
throw Exception(
|
|
|
|
"Type mismatch for column " + column.name + ". Column has type " + it->second->getName() + ", got type "
|
|
|
|
+ column.type->getName(),
|
|
|
|
ErrorCodes::TYPE_MISMATCH);
|
|
|
|
|
|
|
|
if (unique_names.end() != unique_names.find(column.name))
|
|
|
|
throw Exception("Column " + column.name + " queried more than once", ErrorCodes::COLUMN_QUERIED_MORE_THAN_ONCE);
|
|
|
|
unique_names.insert(column.name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void IStorage::check(const NamesAndTypesList & provided_columns, const Names & column_names) const
|
|
|
|
{
|
|
|
|
const NamesAndTypesList & available_columns = getColumns().getAllPhysical();
|
|
|
|
const auto available_columns_map = getColumnsMap(available_columns);
|
|
|
|
const auto & provided_columns_map = getColumnsMap(provided_columns);
|
|
|
|
|
|
|
|
if (column_names.empty())
|
|
|
|
throw Exception(
|
|
|
|
"Empty list of columns queried. There are columns: " + listOfColumns(available_columns),
|
|
|
|
ErrorCodes::EMPTY_LIST_OF_COLUMNS_QUERIED);
|
|
|
|
|
|
|
|
auto unique_names = initUniqueStrings();
|
|
|
|
for (const String & name : column_names)
|
|
|
|
{
|
|
|
|
auto it = provided_columns_map.find(name);
|
|
|
|
if (provided_columns_map.end() == it)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
auto jt = available_columns_map.find(name);
|
|
|
|
if (available_columns_map.end() == jt)
|
|
|
|
throw Exception(
|
|
|
|
"There is no column with name " + name + ". There are columns: " + listOfColumns(available_columns),
|
|
|
|
ErrorCodes::NO_SUCH_COLUMN_IN_TABLE);
|
|
|
|
|
|
|
|
if (!it->second->equals(*jt->second))
|
|
|
|
throw Exception(
|
|
|
|
"Type mismatch for column " + name + ". Column has type " + jt->second->getName() + ", got type " + it->second->getName(),
|
|
|
|
ErrorCodes::TYPE_MISMATCH);
|
|
|
|
|
|
|
|
if (unique_names.end() != unique_names.find(name))
|
|
|
|
throw Exception("Column " + name + " queried more than once", ErrorCodes::COLUMN_QUERIED_MORE_THAN_ONCE);
|
|
|
|
unique_names.insert(name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void IStorage::check(const Block & block, bool need_all) const
|
|
|
|
{
|
|
|
|
const NamesAndTypesList & available_columns = getColumns().getAllPhysical();
|
|
|
|
const auto columns_map = getColumnsMap(available_columns);
|
|
|
|
|
|
|
|
NameSet names_in_block;
|
|
|
|
|
|
|
|
block.checkNumberOfRows();
|
|
|
|
|
|
|
|
for (const auto & column : block)
|
|
|
|
{
|
|
|
|
if (names_in_block.count(column.name))
|
|
|
|
throw Exception("Duplicate column " + column.name + " in block", ErrorCodes::DUPLICATE_COLUMN);
|
|
|
|
|
|
|
|
names_in_block.insert(column.name);
|
|
|
|
|
|
|
|
auto it = columns_map.find(column.name);
|
|
|
|
if (columns_map.end() == it)
|
|
|
|
throw Exception(
|
|
|
|
"There is no column with name " + column.name + ". There are columns: " + listOfColumns(available_columns),
|
|
|
|
ErrorCodes::NO_SUCH_COLUMN_IN_TABLE);
|
|
|
|
|
|
|
|
if (!column.type->equals(*it->second))
|
|
|
|
throw Exception(
|
|
|
|
"Type mismatch for column " + column.name + ". Column has type " + it->second->getName() + ", got type "
|
|
|
|
+ column.type->getName(),
|
|
|
|
ErrorCodes::TYPE_MISMATCH);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (need_all && names_in_block.size() < columns_map.size())
|
|
|
|
{
|
2020-03-09 01:03:43 +00:00
|
|
|
for (const auto & available_column : available_columns)
|
2019-05-17 14:34:25 +00:00
|
|
|
{
|
2020-03-09 01:03:43 +00:00
|
|
|
if (!names_in_block.count(available_column.name))
|
|
|
|
throw Exception("Expected column " + available_column.name, ErrorCodes::NOT_FOUND_COLUMN_IN_BLOCK);
|
2019-05-17 14:34:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-21 11:24:32 +00:00
|
|
|
void IStorage::setColumns(ColumnsDescription columns_)
|
|
|
|
{
|
|
|
|
if (columns_.getOrdinary().empty())
|
|
|
|
throw Exception("Empty list of columns passed", ErrorCodes::EMPTY_LIST_OF_COLUMNS_PASSED);
|
2020-06-05 17:29:40 +00:00
|
|
|
metadata.columns = std::move(columns_);
|
2019-05-21 11:24:32 +00:00
|
|
|
}
|
|
|
|
|
2020-06-01 12:11:23 +00:00
|
|
|
void IStorage::setSecondaryIndices(IndicesDescription secondary_indices_)
|
2019-05-21 11:24:32 +00:00
|
|
|
{
|
2020-06-05 17:29:40 +00:00
|
|
|
metadata.secondary_indices = std::move(secondary_indices_);
|
2019-05-21 11:24:32 +00:00
|
|
|
}
|
|
|
|
|
2019-07-04 19:40:00 +00:00
|
|
|
void IStorage::setConstraints(ConstraintsDescription constraints_)
|
|
|
|
{
|
2020-06-05 17:29:40 +00:00
|
|
|
metadata.constraints = std::move(constraints_);
|
2019-07-04 19:40:00 +00:00
|
|
|
}
|
|
|
|
|
2019-05-21 11:24:32 +00:00
|
|
|
bool IStorage::isVirtualColumn(const String & column_name) const
|
|
|
|
{
|
2020-04-27 13:55:30 +00:00
|
|
|
/// Virtual column maybe overriden by real column
|
|
|
|
return !getColumns().has(column_name) && getVirtuals().contains(column_name);
|
2019-05-21 11:24:32 +00:00
|
|
|
}
|
|
|
|
|
2020-04-09 18:10:27 +00:00
|
|
|
RWLockImpl::LockHolder IStorage::tryLockTimed(
|
2020-04-22 06:22:14 +00:00
|
|
|
const RWLock & rwlock, RWLockImpl::Type type, const String & query_id, const SettingSeconds & acquire_timeout) const
|
2020-04-06 23:45:51 +00:00
|
|
|
{
|
2020-04-09 18:10:27 +00:00
|
|
|
auto lock_holder = rwlock->getLock(type, query_id, std::chrono::milliseconds(acquire_timeout.totalMilliseconds()));
|
2020-04-06 23:45:51 +00:00
|
|
|
if (!lock_holder)
|
2020-04-07 11:34:35 +00:00
|
|
|
{
|
|
|
|
const String type_str = type == RWLockImpl::Type::Read ? "READ" : "WRITE";
|
2020-04-06 23:45:51 +00:00
|
|
|
throw Exception(
|
2020-04-07 11:34:35 +00:00
|
|
|
type_str + " locking attempt on \"" + getStorageID().getFullTableName() +
|
2020-04-09 20:11:20 +00:00
|
|
|
"\" has timed out! (" + toString(acquire_timeout.totalMilliseconds()) + "ms) "
|
2020-04-07 11:34:35 +00:00
|
|
|
"Possible deadlock avoided. Client should retry.",
|
2020-04-06 23:45:51 +00:00
|
|
|
ErrorCodes::DEADLOCK_AVOIDED);
|
2020-04-07 11:34:35 +00:00
|
|
|
}
|
2020-04-07 07:15:59 +00:00
|
|
|
return lock_holder;
|
2020-04-06 23:45:51 +00:00
|
|
|
}
|
|
|
|
|
2020-04-09 18:10:27 +00:00
|
|
|
TableStructureReadLockHolder IStorage::lockStructureForShare(bool will_add_new_data, const String & query_id, const SettingSeconds & acquire_timeout)
|
2019-05-17 14:48:03 +00:00
|
|
|
{
|
|
|
|
TableStructureReadLockHolder result;
|
2020-04-01 12:43:09 +00:00
|
|
|
if (will_add_new_data)
|
2020-04-09 18:10:27 +00:00
|
|
|
result.new_data_structure_lock = tryLockTimed(new_data_structure_lock, RWLockImpl::Read, query_id, acquire_timeout);
|
|
|
|
result.structure_lock = tryLockTimed(structure_lock, RWLockImpl::Read, query_id, acquire_timeout);
|
2019-05-17 14:48:03 +00:00
|
|
|
|
|
|
|
if (is_dropped)
|
|
|
|
throw Exception("Table is dropped", ErrorCodes::TABLE_IS_DROPPED);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2020-04-09 18:10:27 +00:00
|
|
|
TableStructureWriteLockHolder IStorage::lockAlterIntention(const String & query_id, const SettingSeconds & acquire_timeout)
|
2019-05-17 14:48:03 +00:00
|
|
|
{
|
|
|
|
TableStructureWriteLockHolder result;
|
2020-04-09 18:10:27 +00:00
|
|
|
result.alter_intention_lock = tryLockTimed(alter_intention_lock, RWLockImpl::Write, query_id, acquire_timeout);
|
2019-05-17 14:48:03 +00:00
|
|
|
|
|
|
|
if (is_dropped)
|
|
|
|
throw Exception("Table is dropped", ErrorCodes::TABLE_IS_DROPPED);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2020-04-09 18:10:27 +00:00
|
|
|
void IStorage::lockStructureExclusively(TableStructureWriteLockHolder & lock_holder, const String & query_id, const SettingSeconds & acquire_timeout)
|
2019-05-17 14:48:03 +00:00
|
|
|
{
|
2020-04-01 12:43:09 +00:00
|
|
|
if (!lock_holder.alter_intention_lock)
|
2019-12-10 20:47:05 +00:00
|
|
|
throw Exception("Alter intention lock for table " + getStorageID().getNameForLogs() + " was not taken. This is a bug.", ErrorCodes::LOGICAL_ERROR);
|
2019-05-17 14:48:03 +00:00
|
|
|
|
2020-04-01 12:43:09 +00:00
|
|
|
if (!lock_holder.new_data_structure_lock)
|
2020-04-09 18:10:27 +00:00
|
|
|
lock_holder.new_data_structure_lock = tryLockTimed(new_data_structure_lock, RWLockImpl::Write, query_id, acquire_timeout);
|
|
|
|
lock_holder.structure_lock = tryLockTimed(structure_lock, RWLockImpl::Write, query_id, acquire_timeout);
|
2019-05-17 14:48:03 +00:00
|
|
|
}
|
|
|
|
|
2020-04-09 18:10:27 +00:00
|
|
|
TableStructureWriteLockHolder IStorage::lockExclusively(const String & query_id, const SettingSeconds & acquire_timeout)
|
2019-05-17 14:48:03 +00:00
|
|
|
{
|
|
|
|
TableStructureWriteLockHolder result;
|
2020-04-09 18:10:27 +00:00
|
|
|
result.alter_intention_lock = tryLockTimed(alter_intention_lock, RWLockImpl::Write, query_id, acquire_timeout);
|
2019-05-17 14:48:03 +00:00
|
|
|
|
|
|
|
if (is_dropped)
|
|
|
|
throw Exception("Table is dropped", ErrorCodes::TABLE_IS_DROPPED);
|
|
|
|
|
2020-04-09 18:10:27 +00:00
|
|
|
result.new_data_structure_lock = tryLockTimed(new_data_structure_lock, RWLockImpl::Write, query_id, acquire_timeout);
|
|
|
|
result.structure_lock = tryLockTimed(structure_lock, RWLockImpl::Write, query_id, acquire_timeout);
|
2019-05-17 14:48:03 +00:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-05-17 14:34:25 +00:00
|
|
|
void IStorage::alter(
|
|
|
|
const AlterCommands & params,
|
|
|
|
const Context & context,
|
2019-12-29 16:34:32 +00:00
|
|
|
TableStructureWriteLockHolder & table_lock_holder)
|
2018-12-25 23:11:36 +00:00
|
|
|
{
|
2020-04-09 18:10:27 +00:00
|
|
|
lockStructureExclusively(table_lock_holder, context.getCurrentQueryId(), context.getSettingsRef().lock_acquire_timeout);
|
2019-12-10 20:47:05 +00:00
|
|
|
auto table_id = getStorageID();
|
2020-06-10 09:09:51 +00:00
|
|
|
StorageInMemoryMetadata new_metadata = getInMemoryMetadata();
|
|
|
|
params.apply(new_metadata, context);
|
|
|
|
DatabaseCatalog::instance().getDatabase(table_id.database_name)->alterTable(context, table_id, new_metadata);
|
|
|
|
setColumns(std::move(new_metadata.columns));
|
2019-12-26 18:17:05 +00:00
|
|
|
}
|
2019-08-27 09:34:53 +00:00
|
|
|
|
2019-12-26 18:17:05 +00:00
|
|
|
|
2020-06-10 11:16:31 +00:00
|
|
|
void IStorage::checkAlterIsPossible(const AlterCommands & commands, const Settings & /* settings */) const
|
2019-12-26 18:17:05 +00:00
|
|
|
{
|
|
|
|
for (const auto & command : commands)
|
2019-08-27 09:34:53 +00:00
|
|
|
{
|
2019-12-27 14:36:59 +00:00
|
|
|
if (!command.isCommentAlter())
|
2019-12-26 18:17:05 +00:00
|
|
|
throw Exception(
|
|
|
|
"Alter of type '" + alterTypeToString(command.type) + "' is not supported by storage " + getName(),
|
|
|
|
ErrorCodes::NOT_IMPLEMENTED);
|
2018-12-25 23:11:36 +00:00
|
|
|
}
|
|
|
|
}
|
2019-05-17 14:48:03 +00:00
|
|
|
|
2019-09-13 12:59:48 +00:00
|
|
|
|
2019-12-27 19:30:22 +00:00
|
|
|
StorageID IStorage::getStorageID() const
|
2019-12-03 16:25:32 +00:00
|
|
|
{
|
2020-01-15 16:17:04 +00:00
|
|
|
std::lock_guard lock(id_mutex);
|
2019-12-12 12:30:31 +00:00
|
|
|
return storage_id;
|
2019-12-03 16:25:32 +00:00
|
|
|
}
|
|
|
|
|
2020-04-07 14:05:51 +00:00
|
|
|
void IStorage::renameInMemory(const StorageID & new_table_id)
|
2019-12-03 16:25:32 +00:00
|
|
|
{
|
2020-01-15 16:17:04 +00:00
|
|
|
std::lock_guard lock(id_mutex);
|
2020-04-07 14:05:51 +00:00
|
|
|
storage_id = new_table_id;
|
2019-12-03 16:25:32 +00:00
|
|
|
}
|
|
|
|
|
2020-04-28 10:38:57 +00:00
|
|
|
NamesAndTypesList IStorage::getVirtuals() const
|
2020-04-27 13:55:30 +00:00
|
|
|
{
|
2020-04-28 10:38:57 +00:00
|
|
|
return {};
|
2020-04-27 13:55:30 +00:00
|
|
|
}
|
|
|
|
|
2020-06-13 09:12:45 +00:00
|
|
|
const KeyDescription & IStorage::getPartitionKey() const
|
2020-05-20 12:16:55 +00:00
|
|
|
{
|
2020-06-05 17:29:40 +00:00
|
|
|
return metadata.partition_key;
|
2020-05-20 12:16:55 +00:00
|
|
|
}
|
|
|
|
|
2020-06-05 11:54:54 +00:00
|
|
|
void IStorage::setPartitionKey(const KeyDescription & partition_key_)
|
2020-05-20 12:16:55 +00:00
|
|
|
{
|
2020-06-05 17:29:40 +00:00
|
|
|
metadata.partition_key = partition_key_;
|
2020-05-20 12:16:55 +00:00
|
|
|
}
|
|
|
|
|
2020-05-26 14:14:08 +00:00
|
|
|
bool IStorage::isPartitionKeyDefined() const
|
|
|
|
{
|
2020-06-05 17:29:40 +00:00
|
|
|
return metadata.partition_key.definition_ast != nullptr;
|
2020-05-26 14:14:08 +00:00
|
|
|
}
|
|
|
|
|
2020-05-21 19:46:03 +00:00
|
|
|
bool IStorage::hasPartitionKey() const
|
|
|
|
{
|
2020-06-05 17:29:40 +00:00
|
|
|
return !metadata.partition_key.column_names.empty();
|
2020-05-21 19:46:03 +00:00
|
|
|
}
|
|
|
|
|
2020-05-20 12:16:55 +00:00
|
|
|
Names IStorage::getColumnsRequiredForPartitionKey() const
|
|
|
|
{
|
2020-06-13 09:12:45 +00:00
|
|
|
if (hasPartitionKey())
|
2020-06-05 17:29:40 +00:00
|
|
|
return metadata.partition_key.expression->getRequiredColumns();
|
2020-05-20 12:16:55 +00:00
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2020-06-13 09:12:45 +00:00
|
|
|
const KeyDescription & IStorage::getSortingKey() const
|
2020-05-20 15:16:39 +00:00
|
|
|
{
|
2020-06-05 17:29:40 +00:00
|
|
|
return metadata.sorting_key;
|
2020-05-20 15:16:39 +00:00
|
|
|
}
|
|
|
|
|
2020-06-05 11:54:54 +00:00
|
|
|
void IStorage::setSortingKey(const KeyDescription & sorting_key_)
|
2020-05-20 12:16:55 +00:00
|
|
|
{
|
2020-06-05 17:29:40 +00:00
|
|
|
metadata.sorting_key = sorting_key_;
|
2020-05-20 12:16:55 +00:00
|
|
|
}
|
|
|
|
|
2020-05-26 14:14:08 +00:00
|
|
|
bool IStorage::isSortingKeyDefined() const
|
|
|
|
{
|
2020-06-05 17:29:40 +00:00
|
|
|
return metadata.sorting_key.definition_ast != nullptr;
|
2020-05-26 14:14:08 +00:00
|
|
|
}
|
|
|
|
|
2020-05-21 19:46:03 +00:00
|
|
|
bool IStorage::hasSortingKey() const
|
2020-05-20 15:16:39 +00:00
|
|
|
{
|
2020-06-05 17:29:40 +00:00
|
|
|
return !metadata.sorting_key.column_names.empty();
|
2020-05-20 15:16:39 +00:00
|
|
|
}
|
|
|
|
|
2020-05-20 18:11:38 +00:00
|
|
|
Names IStorage::getColumnsRequiredForSortingKey() const
|
|
|
|
{
|
2020-06-13 09:12:45 +00:00
|
|
|
if (hasSortingKey())
|
2020-06-05 17:29:40 +00:00
|
|
|
return metadata.sorting_key.expression->getRequiredColumns();
|
2020-05-20 18:11:38 +00:00
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
Names IStorage::getSortingKeyColumns() const
|
|
|
|
{
|
2020-06-13 09:12:45 +00:00
|
|
|
if (hasSortingKey())
|
2020-06-05 17:29:40 +00:00
|
|
|
return metadata.sorting_key.column_names;
|
2020-05-20 18:11:38 +00:00
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2020-06-13 09:12:45 +00:00
|
|
|
const KeyDescription & IStorage::getPrimaryKey() const
|
2020-05-20 15:16:39 +00:00
|
|
|
{
|
2020-06-05 17:29:40 +00:00
|
|
|
return metadata.primary_key;
|
2020-05-20 15:16:39 +00:00
|
|
|
}
|
|
|
|
|
2020-06-05 11:54:54 +00:00
|
|
|
void IStorage::setPrimaryKey(const KeyDescription & primary_key_)
|
2020-05-20 15:16:39 +00:00
|
|
|
{
|
2020-06-05 17:29:40 +00:00
|
|
|
metadata.primary_key = primary_key_;
|
2020-05-20 18:11:38 +00:00
|
|
|
}
|
|
|
|
|
2020-05-21 19:46:03 +00:00
|
|
|
bool IStorage::isPrimaryKeyDefined() const
|
2020-05-20 18:11:38 +00:00
|
|
|
{
|
2020-06-05 17:29:40 +00:00
|
|
|
return metadata.primary_key.definition_ast != nullptr;
|
2020-05-20 18:11:38 +00:00
|
|
|
}
|
|
|
|
|
2020-05-21 19:46:03 +00:00
|
|
|
bool IStorage::hasPrimaryKey() const
|
2020-05-20 18:11:38 +00:00
|
|
|
{
|
2020-06-05 17:29:40 +00:00
|
|
|
return !metadata.primary_key.column_names.empty();
|
2020-05-20 15:16:39 +00:00
|
|
|
}
|
|
|
|
|
2020-05-21 19:46:03 +00:00
|
|
|
Names IStorage::getColumnsRequiredForPrimaryKey() const
|
2020-05-20 18:11:38 +00:00
|
|
|
{
|
2020-06-13 09:12:45 +00:00
|
|
|
if (hasPrimaryKey())
|
2020-06-05 17:29:40 +00:00
|
|
|
return metadata.primary_key.expression->getRequiredColumns();
|
2020-05-21 19:46:03 +00:00
|
|
|
return {};
|
2020-05-20 18:11:38 +00:00
|
|
|
}
|
|
|
|
|
2020-05-21 19:46:03 +00:00
|
|
|
Names IStorage::getPrimaryKeyColumns() const
|
2020-05-20 18:11:38 +00:00
|
|
|
{
|
2020-06-12 14:32:47 +00:00
|
|
|
if (!metadata.primary_key.column_names.empty())
|
2020-06-05 17:29:40 +00:00
|
|
|
return metadata.primary_key.column_names;
|
2020-05-21 19:46:03 +00:00
|
|
|
return {};
|
2020-05-20 18:11:38 +00:00
|
|
|
}
|
|
|
|
|
2020-06-13 09:12:45 +00:00
|
|
|
const KeyDescription & IStorage::getSamplingKey() const
|
2020-05-20 18:11:38 +00:00
|
|
|
{
|
2020-06-05 17:29:40 +00:00
|
|
|
return metadata.sampling_key;
|
2020-05-20 18:11:38 +00:00
|
|
|
}
|
|
|
|
|
2020-06-05 11:54:54 +00:00
|
|
|
void IStorage::setSamplingKey(const KeyDescription & sampling_key_)
|
2020-05-20 18:11:38 +00:00
|
|
|
{
|
2020-06-05 17:29:40 +00:00
|
|
|
metadata.sampling_key = sampling_key_;
|
2020-05-20 18:11:38 +00:00
|
|
|
}
|
|
|
|
|
2020-05-26 14:14:08 +00:00
|
|
|
|
|
|
|
bool IStorage::isSamplingKeyDefined() const
|
|
|
|
{
|
2020-06-05 17:29:40 +00:00
|
|
|
return metadata.sampling_key.definition_ast != nullptr;
|
2020-05-26 14:14:08 +00:00
|
|
|
}
|
|
|
|
|
2020-05-21 19:46:03 +00:00
|
|
|
bool IStorage::hasSamplingKey() const
|
2020-05-20 18:11:38 +00:00
|
|
|
{
|
2020-06-05 17:29:40 +00:00
|
|
|
return !metadata.sampling_key.column_names.empty();
|
2020-05-20 18:11:38 +00:00
|
|
|
}
|
2020-05-21 19:07:18 +00:00
|
|
|
|
2020-05-21 19:46:03 +00:00
|
|
|
Names IStorage::getColumnsRequiredForSampling() const
|
2020-05-21 19:07:18 +00:00
|
|
|
{
|
2020-06-13 09:12:45 +00:00
|
|
|
if (hasSamplingKey())
|
2020-06-05 17:29:40 +00:00
|
|
|
return metadata.sampling_key.expression->getRequiredColumns();
|
2020-05-21 19:46:03 +00:00
|
|
|
return {};
|
2020-05-21 19:07:18 +00:00
|
|
|
}
|
|
|
|
|
2020-06-12 14:32:47 +00:00
|
|
|
TTLTableDescription IStorage::getTableTTLs() const
|
2020-05-25 17:57:08 +00:00
|
|
|
{
|
2020-06-13 09:12:45 +00:00
|
|
|
std::lock_guard lock(ttl_mutex);
|
2020-06-05 17:29:40 +00:00
|
|
|
return metadata.table_ttl;
|
2020-05-25 17:57:08 +00:00
|
|
|
}
|
2020-05-25 17:07:14 +00:00
|
|
|
|
2020-05-28 15:33:44 +00:00
|
|
|
void IStorage::setTableTTLs(const TTLTableDescription & table_ttl_)
|
2020-05-25 17:07:14 +00:00
|
|
|
{
|
2020-06-13 09:12:45 +00:00
|
|
|
std::lock_guard lock(ttl_mutex);
|
2020-06-05 17:29:40 +00:00
|
|
|
metadata.table_ttl = table_ttl_;
|
2020-05-25 17:07:14 +00:00
|
|
|
}
|
|
|
|
|
2020-05-25 17:57:08 +00:00
|
|
|
bool IStorage::hasAnyTableTTL() const
|
2020-05-25 17:07:14 +00:00
|
|
|
{
|
2020-05-25 17:57:08 +00:00
|
|
|
return hasAnyMoveTTL() || hasRowsTTL();
|
2020-05-25 17:07:14 +00:00
|
|
|
}
|
|
|
|
|
2020-06-12 14:32:47 +00:00
|
|
|
TTLColumnsDescription IStorage::getColumnTTLs() const
|
2020-05-25 17:07:14 +00:00
|
|
|
{
|
2020-06-13 09:12:45 +00:00
|
|
|
std::lock_guard lock(ttl_mutex);
|
2020-06-05 17:29:40 +00:00
|
|
|
return metadata.column_ttls_by_name;
|
2020-05-25 17:07:14 +00:00
|
|
|
}
|
|
|
|
|
2020-05-28 15:33:44 +00:00
|
|
|
void IStorage::setColumnTTLs(const TTLColumnsDescription & column_ttls_by_name_)
|
2020-05-25 17:07:14 +00:00
|
|
|
{
|
2020-06-13 09:12:45 +00:00
|
|
|
std::lock_guard lock(ttl_mutex);
|
2020-06-05 17:29:40 +00:00
|
|
|
metadata.column_ttls_by_name = column_ttls_by_name_;
|
2020-05-25 17:07:14 +00:00
|
|
|
}
|
|
|
|
|
2020-05-25 17:57:08 +00:00
|
|
|
bool IStorage::hasAnyColumnTTL() const
|
2020-05-25 17:07:14 +00:00
|
|
|
{
|
2020-06-13 09:12:45 +00:00
|
|
|
std::lock_guard lock(ttl_mutex);
|
2020-06-05 17:29:40 +00:00
|
|
|
return !metadata.column_ttls_by_name.empty();
|
2020-05-25 17:07:14 +00:00
|
|
|
}
|
|
|
|
|
2020-06-12 14:32:47 +00:00
|
|
|
TTLDescription IStorage::getRowsTTL() const
|
2020-05-25 17:07:14 +00:00
|
|
|
{
|
2020-06-13 09:12:45 +00:00
|
|
|
std::lock_guard lock(ttl_mutex);
|
2020-06-05 17:29:40 +00:00
|
|
|
return metadata.table_ttl.rows_ttl;
|
2020-05-25 17:07:14 +00:00
|
|
|
}
|
|
|
|
|
2020-05-25 17:57:08 +00:00
|
|
|
bool IStorage::hasRowsTTL() const
|
2020-05-25 17:07:14 +00:00
|
|
|
{
|
2020-06-13 09:12:45 +00:00
|
|
|
std::lock_guard lock(ttl_mutex);
|
2020-06-05 17:29:40 +00:00
|
|
|
return metadata.table_ttl.rows_ttl.expression != nullptr;
|
2020-05-25 17:07:14 +00:00
|
|
|
}
|
|
|
|
|
2020-06-12 14:32:47 +00:00
|
|
|
TTLDescriptions IStorage::getMoveTTLs() const
|
2020-05-25 17:07:14 +00:00
|
|
|
{
|
2020-06-13 09:12:45 +00:00
|
|
|
std::lock_guard lock(ttl_mutex);
|
2020-06-05 17:29:40 +00:00
|
|
|
return metadata.table_ttl.move_ttl;
|
2020-05-25 17:07:14 +00:00
|
|
|
}
|
|
|
|
|
2020-05-25 17:57:08 +00:00
|
|
|
bool IStorage::hasAnyMoveTTL() const
|
2020-05-25 17:07:14 +00:00
|
|
|
{
|
2020-06-13 09:12:45 +00:00
|
|
|
std::lock_guard lock(ttl_mutex);
|
2020-06-05 17:29:40 +00:00
|
|
|
return !metadata.table_ttl.move_ttl.empty();
|
2020-05-25 17:07:14 +00:00
|
|
|
}
|
|
|
|
|
2020-06-01 11:17:18 +00:00
|
|
|
|
|
|
|
ColumnDependencies IStorage::getColumnDependencies(const NameSet & updated_columns) const
|
|
|
|
{
|
|
|
|
if (updated_columns.empty())
|
|
|
|
return {};
|
|
|
|
|
|
|
|
ColumnDependencies res;
|
|
|
|
|
|
|
|
NameSet indices_columns;
|
|
|
|
NameSet required_ttl_columns;
|
|
|
|
NameSet updated_ttl_columns;
|
|
|
|
|
|
|
|
auto add_dependent_columns = [&updated_columns](const auto & expression, auto & to_set)
|
|
|
|
{
|
|
|
|
auto requiered_columns = expression->getRequiredColumns();
|
|
|
|
for (const auto & dependency : requiered_columns)
|
|
|
|
{
|
|
|
|
if (updated_columns.count(dependency))
|
|
|
|
{
|
|
|
|
to_set.insert(requiered_columns.begin(), requiered_columns.end());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
2020-06-01 11:29:11 +00:00
|
|
|
for (const auto & index : getSecondaryIndices())
|
2020-06-01 11:17:18 +00:00
|
|
|
add_dependent_columns(index.expression, indices_columns);
|
|
|
|
|
|
|
|
if (hasRowsTTL())
|
|
|
|
{
|
2020-06-13 10:39:25 +00:00
|
|
|
auto rows_expression = getRowsTTL().expression;
|
|
|
|
if (add_dependent_columns(rows_expression, required_ttl_columns))
|
2020-06-01 11:17:18 +00:00
|
|
|
{
|
|
|
|
/// Filter all columns, if rows TTL expression have to be recalculated.
|
|
|
|
for (const auto & column : getColumns().getAllPhysical())
|
|
|
|
updated_ttl_columns.insert(column.name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto & [name, entry] : getColumnTTLs())
|
|
|
|
{
|
|
|
|
if (add_dependent_columns(entry.expression, required_ttl_columns))
|
|
|
|
updated_ttl_columns.insert(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto & entry : getMoveTTLs())
|
|
|
|
add_dependent_columns(entry.expression, required_ttl_columns);
|
|
|
|
|
|
|
|
for (const auto & column : indices_columns)
|
|
|
|
res.emplace(column, ColumnDependency::SKIP_INDEX);
|
|
|
|
for (const auto & column : required_ttl_columns)
|
|
|
|
res.emplace(column, ColumnDependency::TTL_EXPRESSION);
|
|
|
|
for (const auto & column : updated_ttl_columns)
|
|
|
|
res.emplace(column, ColumnDependency::TTL_TARGET);
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-06-12 14:32:47 +00:00
|
|
|
ASTPtr IStorage::getSettingsChanges() const
|
2020-06-05 11:54:54 +00:00
|
|
|
{
|
2020-06-12 14:32:47 +00:00
|
|
|
if (metadata.settings_changes)
|
|
|
|
return metadata.settings_changes->clone();
|
|
|
|
return nullptr;
|
2020-06-05 11:54:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void IStorage::setSettingsChanges(const ASTPtr & settings_changes_)
|
|
|
|
{
|
2020-06-05 12:13:24 +00:00
|
|
|
if (settings_changes_)
|
2020-06-05 17:29:40 +00:00
|
|
|
metadata.settings_changes = settings_changes_->clone();
|
2020-06-05 12:13:24 +00:00
|
|
|
else
|
2020-06-05 17:29:40 +00:00
|
|
|
metadata.settings_changes = nullptr;
|
2020-06-05 11:54:54 +00:00
|
|
|
}
|
|
|
|
|
2020-06-13 09:12:45 +00:00
|
|
|
const SelectQueryDescription & IStorage::getSelectQuery() const
|
2020-06-05 11:54:54 +00:00
|
|
|
{
|
2020-06-05 17:29:40 +00:00
|
|
|
return metadata.select;
|
2020-06-05 11:54:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void IStorage::setSelectQuery(const SelectQueryDescription & select_)
|
|
|
|
{
|
2020-06-05 17:29:40 +00:00
|
|
|
metadata.select = select_;
|
2020-06-05 11:54:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool IStorage::hasSelectQuery() const
|
|
|
|
{
|
2020-06-05 17:29:40 +00:00
|
|
|
return metadata.select.select_query != nullptr;
|
2020-06-05 11:54:54 +00:00
|
|
|
}
|
|
|
|
|
2017-01-21 04:24:28 +00:00
|
|
|
}
|