ClickHouse/dbms/src/Storages/ITableDeclaration.cpp

288 lines
9.1 KiB
C++
Raw Normal View History

#include <unordered_set>
2012-11-30 05:24:24 +00:00
#include <sparsehash/dense_hash_map>
2014-03-09 17:36:01 +00:00
#include <sparsehash/dense_hash_set>
#include <DB/Storages/ITableDeclaration.h>
2013-09-23 12:01:19 +00:00
#include <DB/Parsers/ASTIdentifier.h>
#include <DB/Parsers/ASTNameTypePair.h>
#include <DB/Interpreters/Context.h>
namespace DB
{
NamesAndTypesList ITableDeclaration::getColumnsList() const
{
auto columns = getColumnsListImpl();
columns.insert(std::end(columns), std::begin(materialized_columns), std::end(materialized_columns));
return columns;
}
ITableDeclaration::ColumnsListRange ITableDeclaration::getColumnsListIterator() const
{
const auto & columns = getColumnsListImpl();
return boost::join(
boost::iterator_range<NamesAndTypesList::const_iterator>(columns.begin(), columns.end()),
boost::iterator_range<NamesAndTypesList::const_iterator>(std::begin(materialized_columns), std::end(materialized_columns)));
}
bool ITableDeclaration::hasRealColumn(const String & column_name) const
2014-01-16 14:52:13 +00:00
{
for (auto & it : getColumnsListIterator())
if (it.name == column_name)
2014-01-16 14:52:13 +00:00
return true;
return false;
}
Names ITableDeclaration::getColumnNamesList() const
{
Names res;
for (auto & it : getColumnsListIterator())
res.push_back(it.name);
return res;
}
NameAndTypePair ITableDeclaration::getRealColumn(const String & column_name) const
2014-01-16 14:52:13 +00:00
{
for (auto & it : getColumnsListIterator())
if (it.name == column_name)
2014-01-16 14:52:13 +00:00
return it;
2014-05-26 11:40:22 +00:00
throw Exception("There is no column " + column_name + " in table.", ErrorCodes::NO_SUCH_COLUMN_IN_TABLE);
2014-01-16 14:52:13 +00:00
}
NameAndTypePair ITableDeclaration::getMaterializedColumn(const String & column_name) const
{
for (auto & column : materialized_columns)
if (column.name == column_name)
return column;
2014-01-16 14:52:13 +00:00
throw Exception("There is no column " + column_name + " in table.", ErrorCodes::NO_SUCH_COLUMN_IN_TABLE);
}
bool ITableDeclaration::hasMaterializedColumn(const String & column_name) const
2014-01-16 14:52:13 +00:00
{
for (auto & column : materialized_columns)
if (column.name == column_name)
return true;
return false;
2014-01-16 14:52:13 +00:00
}
bool ITableDeclaration::hasColumn(const String & column_name) const
2014-01-16 14:52:13 +00:00
{
return hasRealColumn(column_name); /// По умолчанию считаем, что виртуальных столбцов в сторадже нет.
}
NameAndTypePair ITableDeclaration::getColumn(const String & column_name) const
2014-01-16 14:52:13 +00:00
{
return getRealColumn(column_name); /// По умолчанию считаем, что виртуальных столбцов в сторадже нет.
}
2011-11-01 17:12:11 +00:00
const DataTypePtr ITableDeclaration::getDataTypeByName(const String & column_name) const
2011-11-01 17:12:11 +00:00
{
for (const auto & column : getColumnsListIterator())
if (column.name == column_name)
return column.type;
2014-03-09 17:36:01 +00:00
2014-05-26 11:40:22 +00:00
throw Exception("There is no column " + column_name + " in table.", ErrorCodes::NO_SUCH_COLUMN_IN_TABLE);
2011-11-01 17:12:11 +00:00
}
Block ITableDeclaration::getSampleBlock() const
2011-10-31 06:37:12 +00:00
{
Block res;
for (const auto & col : getColumnsListIterator())
res.insert({ col.type->createColumn(), col.type, col.name });
return res;
}
Block ITableDeclaration::getSampleBlockNonMaterialized() const
{
Block res;
for (const auto & col : getColumnsListNonMaterialized())
res.insert({ col.type->createColumn(), col.type, col.name });
2014-03-09 17:36:01 +00:00
2011-10-31 06:37:12 +00:00
return res;
}
2012-11-30 05:24:24 +00:00
static std::string listOfColumns(const NamesAndTypesList & available_columns)
{
std::stringstream s;
for (NamesAndTypesList::const_iterator it = available_columns.begin(); it != available_columns.end(); ++it)
{
if (it != available_columns.begin())
s << ", ";
s << it->name;
2012-11-30 05:24:24 +00:00
}
return s.str();
}
typedef google::dense_hash_map<StringRef, const IDataType *, StringRefHash> NamesAndTypesMap;
2012-11-30 05:24:24 +00:00
static NamesAndTypesMap & getColumnsMapImpl(NamesAndTypesMap & res) { return res; }
2012-11-30 05:24:24 +00:00
template <typename Arg, typename... Args>
static NamesAndTypesMap & getColumnsMapImpl(NamesAndTypesMap & res, const Arg & arg, const Args &... args)
{
static_assert(std::is_same<Arg, NamesAndTypesList>::value, "getColumnsMap requires arguments of type NamesAndTypesList");
for (const auto & column : arg)
res.insert({column.name, column.type.get()});
return getColumnsMapImpl(res, args...);
}
2012-11-30 05:24:24 +00:00
template <typename... Args>
static NamesAndTypesMap getColumnsMap(const Args &... args)
2012-11-30 05:24:24 +00:00
{
NamesAndTypesMap res;
res.set_empty_key(StringRef());
2012-11-30 05:24:24 +00:00
return getColumnsMapImpl(res, args...);
2012-11-30 05:24:24 +00:00
}
void ITableDeclaration::check(const Names & column_names) const
{
2012-11-30 05:24:24 +00:00
const NamesAndTypesList & available_columns = getColumnsList();
2014-03-09 17:36:01 +00:00
if (column_names.empty())
2014-05-26 11:40:22 +00:00
throw Exception("Empty list of columns queried. There are columns: " + listOfColumns(available_columns),
ErrorCodes::EMPTY_LIST_OF_COLUMNS_QUERIED);
const auto columns_map = getColumnsMap(available_columns);
2012-11-30 05:24:24 +00:00
typedef google::dense_hash_set<StringRef, StringRefHash> UniqueStrings;
UniqueStrings unique_names;
unique_names.set_empty_key(StringRef());
for (Names::const_iterator it = column_names.begin(); it != column_names.end(); ++it)
{
2012-11-30 05:24:24 +00:00
if (columns_map.end() == columns_map.find(*it))
2014-05-26 11:40:22 +00:00
throw Exception("There is no column with name " + *it + " in table. There are columns: " + listOfColumns(available_columns),
ErrorCodes::NO_SUCH_COLUMN_IN_TABLE);
if (unique_names.end() != unique_names.find(*it))
2014-05-26 11:40:22 +00:00
throw Exception("Column " + *it + " queried more than once",
ErrorCodes::COLUMN_QUERIED_MORE_THAN_ONCE);
unique_names.insert(*it);
}
}
2014-07-14 14:07:47 +00:00
void ITableDeclaration::check(const NamesAndTypesList & columns) const
{
const NamesAndTypesList & available_columns = getColumnsList();
const auto columns_map = getColumnsMap(available_columns);
2014-07-14 14:07:47 +00:00
typedef google::dense_hash_set<StringRef, StringRefHash> UniqueStrings;
UniqueStrings unique_names;
unique_names.set_empty_key(StringRef());
for (const NameAndTypePair & column : columns)
{
NamesAndTypesMap::const_iterator 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->getName() != it->second->getName())
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 ITableDeclaration::check(const NamesAndTypesList & columns, const Names & column_names) const
{
const NamesAndTypesList & available_columns = getColumnsList();
const auto available_columns_map = getColumnsMap(available_columns);
2014-07-14 14:07:47 +00:00
const NamesAndTypesMap & provided_columns_map = getColumnsMap(columns);
if (column_names.empty())
throw Exception("Empty list of columns queried. There are columns: " + listOfColumns(available_columns),
ErrorCodes::EMPTY_LIST_OF_COLUMNS_QUERIED);
2014-07-14 14:07:47 +00:00
typedef google::dense_hash_set<StringRef, StringRefHash> UniqueStrings;
UniqueStrings unique_names;
unique_names.set_empty_key(StringRef());
for (const String & name : column_names)
{
NamesAndTypesMap::const_iterator it = provided_columns_map.find(name);
if (provided_columns_map.end() == it)
continue;
NamesAndTypesMap::const_iterator 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->getName() != jt->second->getName())
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 ITableDeclaration::check(const Block & block, bool need_all) const
{
2012-11-30 05:24:24 +00:00
const NamesAndTypesList & available_columns = getColumnsList();
const auto columns_map = getColumnsMap(available_columns);
2014-03-09 17:36:01 +00:00
2014-01-08 16:33:28 +00:00
typedef std::unordered_set<String> NameSet;
2013-02-25 10:23:31 +00:00
NameSet names_in_block;
2014-03-09 17:36:01 +00:00
for (size_t i = 0; i < block.columns(); ++i)
{
const ColumnWithNameAndType & column = block.getByPosition(i);
2013-02-25 10:23:31 +00:00
if (names_in_block.count(column.name))
throw Exception("Duplicate column " + column.name + " in block",
ErrorCodes::DUPLICATE_COLUMN);
names_in_block.insert(column.name);
2012-11-30 05:24:24 +00:00
NamesAndTypesMap::const_iterator it = columns_map.find(column.name);
if (columns_map.end() == it)
2014-05-26 11:40:22 +00:00
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->getName() != it->second->getName())
2014-05-26 11:40:22 +00:00
throw Exception("Type mismatch for column " + column.name + ". Column has type "
+ it->second->getName() + ", got type " + column.type->getName(), ErrorCodes::TYPE_MISMATCH);
}
2014-03-09 17:36:01 +00:00
2013-02-25 10:23:31 +00:00
if (need_all && names_in_block.size() < columns_map.size())
{
2013-02-25 10:51:52 +00:00
for (NamesAndTypesList::const_iterator it = available_columns.begin(); it != available_columns.end(); ++it)
2013-02-25 10:23:31 +00:00
{
if (!names_in_block.count(it->name))
throw Exception("Expected column " + it->name, ErrorCodes::NOT_FOUND_COLUMN_IN_BLOCK);
2013-02-25 10:23:31 +00:00
}
}
}
}