2018-03-06 20:18:34 +00:00
|
|
|
#include <Storages/ITableDeclaration.h>
|
|
|
|
#include <Common/Exception.h>
|
|
|
|
|
|
|
|
#include <boost/range/join.hpp>
|
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>
|
2018-03-06 20:18:34 +00:00
|
|
|
|
|
|
|
#include <unordered_set>
|
|
|
|
#include <sstream>
|
2011-08-15 21:50:08 +00:00
|
|
|
|
2015-02-22 15:31:39 +00:00
|
|
|
|
2011-08-15 21:50:08 +00:00
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
2016-01-11 21:46:36 +00:00
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
extern const int NO_SUCH_COLUMN_IN_TABLE;
|
|
|
|
extern const int EMPTY_LIST_OF_COLUMNS_QUERIED;
|
|
|
|
extern const int COLUMN_QUERIED_MORE_THAN_ONCE;
|
|
|
|
extern const int TYPE_MISMATCH;
|
|
|
|
extern const int DUPLICATE_COLUMN;
|
|
|
|
extern const int NOT_FOUND_COLUMN_IN_BLOCK;
|
2018-01-25 14:42:39 +00:00
|
|
|
extern const int EMPTY_LIST_OF_COLUMNS_PASSED;
|
2016-01-11 21:46:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-13 14:18:11 +00:00
|
|
|
void ITableDeclaration::setColumns(ColumnsDescription columns_)
|
|
|
|
{
|
|
|
|
if (columns_.ordinary.empty())
|
|
|
|
throw Exception("Empty list of columns passed", ErrorCodes::EMPTY_LIST_OF_COLUMNS_PASSED);
|
|
|
|
columns = std::move(columns_);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-04-29 00:28:18 +00:00
|
|
|
bool ITableDeclaration::hasColumn(const String & column_name) const
|
2014-01-16 14:52:13 +00:00
|
|
|
{
|
2018-03-13 15:00:28 +00:00
|
|
|
return getColumns().hasPhysical(column_name); /// By default, we assume that there are no virtual columns in the storage.
|
2014-01-16 14:52:13 +00:00
|
|
|
}
|
|
|
|
|
2017-12-25 21:57:29 +00:00
|
|
|
NameAndTypePair ITableDeclaration::getColumn(const String & column_name) const
|
2014-01-16 14:52:13 +00:00
|
|
|
{
|
2018-03-13 15:00:28 +00:00
|
|
|
return getColumns().getPhysical(column_name); /// By default, we assume that there are no virtual columns in the storage.
|
2011-11-01 17:12:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-19 10:45:13 +00:00
|
|
|
Block ITableDeclaration::getSampleBlock() const
|
2011-10-31 06:37:12 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
Block res;
|
2011-10-31 06:37:12 +00:00
|
|
|
|
2018-09-20 11:16:15 +00:00
|
|
|
for (const auto & col : getColumns().getAllPhysical())
|
2017-04-01 07:20:54 +00:00
|
|
|
res.insert({ col.type->createColumn(), col.type, col.name });
|
2014-10-13 14:35:40 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
return res;
|
2014-10-13 14:35:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Block ITableDeclaration::getSampleBlockNonMaterialized() const
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
Block res;
|
2014-10-13 14:35:40 +00:00
|
|
|
|
2018-03-13 14:18:11 +00:00
|
|
|
for (const auto & col : getColumns().ordinary)
|
2017-04-01 07:20:54 +00:00
|
|
|
res.insert({ col.type->createColumn(), col.type, col.name });
|
2014-03-09 17:36:01 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
return res;
|
2011-10-31 06:37:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-01-09 01:51:08 +00:00
|
|
|
Block ITableDeclaration::getSampleBlockForColumns(const Names & column_names) const
|
|
|
|
{
|
|
|
|
Block res;
|
|
|
|
|
2018-07-19 13:36:21 +00:00
|
|
|
NamesAndTypesList all_columns = getColumns().getAll();
|
|
|
|
std::unordered_map<String, DataTypePtr> columns_map;
|
|
|
|
for (const auto & elem : all_columns)
|
|
|
|
columns_map.emplace(elem.name, elem.type);
|
|
|
|
|
2018-01-09 01:51:08 +00:00
|
|
|
for (const auto & name : column_names)
|
|
|
|
{
|
2018-07-19 13:36:21 +00:00
|
|
|
auto it = columns_map.find(name);
|
|
|
|
if (it != columns_map.end())
|
|
|
|
{
|
|
|
|
res.insert({ it->second->createColumn(), it->second, it->first });
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/// Virtual columns.
|
|
|
|
NameAndTypePair elem = getColumn(name);
|
|
|
|
res.insert({ elem.type->createColumn(), elem.type, elem.name });
|
|
|
|
}
|
2018-01-09 01:51:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-12-25 21:57:29 +00:00
|
|
|
static std::string listOfColumns(const NamesAndTypesList & available_columns)
|
2012-11-30 05:24:24 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
std::stringstream s;
|
2018-03-06 20:18:34 +00:00
|
|
|
for (auto it = available_columns.begin(); it != available_columns.end(); ++it)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
if (it != available_columns.begin())
|
|
|
|
s << ", ";
|
|
|
|
s << it->name;
|
|
|
|
}
|
|
|
|
return s.str();
|
2012-11-30 05:24:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-06-19 18:09:09 +00:00
|
|
|
using NamesAndTypesMap = GOOGLE_NAMESPACE::dense_hash_map<StringRef, const IDataType *, StringRefHash>;
|
2012-11-30 05:24:24 +00:00
|
|
|
|
2014-10-03 15:30:10 +00:00
|
|
|
static NamesAndTypesMap & getColumnsMapImpl(NamesAndTypesMap & res) { return res; }
|
2012-11-30 05:24:24 +00:00
|
|
|
|
2014-10-03 15:30:10 +00:00
|
|
|
template <typename Arg, typename... Args>
|
|
|
|
static NamesAndTypesMap & getColumnsMapImpl(NamesAndTypesMap & res, const Arg & arg, const Args &... args)
|
|
|
|
{
|
2017-12-25 21:57:29 +00:00
|
|
|
static_assert(std::is_same_v<Arg, NamesAndTypesList>, "getColumnsMap requires arguments of type NamesAndTypesList");
|
2014-10-03 15:30:10 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
for (const auto & column : arg)
|
|
|
|
res.insert({column.name, column.type.get()});
|
2014-10-03 15:30:10 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
return getColumnsMapImpl(res, args...);
|
2014-10-03 15:30:10 +00:00
|
|
|
}
|
2012-11-30 05:24:24 +00:00
|
|
|
|
2014-10-03 15:30:10 +00:00
|
|
|
template <typename... Args>
|
|
|
|
static NamesAndTypesMap getColumnsMap(const Args &... args)
|
2012-11-30 05:24:24 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
NamesAndTypesMap res;
|
|
|
|
res.set_empty_key(StringRef());
|
2012-11-30 05:24:24 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
return getColumnsMapImpl(res, args...);
|
2012-11-30 05:24:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-19 10:45:13 +00:00
|
|
|
void ITableDeclaration::check(const Names & column_names) const
|
2011-08-15 21:50:08 +00:00
|
|
|
{
|
2018-03-13 15:00:28 +00:00
|
|
|
const NamesAndTypesList & available_columns = getColumns().getAllPhysical();
|
2014-03-09 17:36:01 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
if (column_names.empty())
|
|
|
|
throw Exception("Empty list of columns queried. There are columns: " + listOfColumns(available_columns),
|
|
|
|
ErrorCodes::EMPTY_LIST_OF_COLUMNS_QUERIED);
|
2011-08-15 21:50:08 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
const auto columns_map = getColumnsMap(available_columns);
|
2012-11-30 05:24:24 +00:00
|
|
|
|
2018-06-19 18:09:09 +00:00
|
|
|
using UniqueStrings = GOOGLE_NAMESPACE::dense_hash_set<StringRef, StringRefHash>;
|
2017-04-01 07:20:54 +00:00
|
|
|
UniqueStrings unique_names;
|
|
|
|
unique_names.set_empty_key(StringRef());
|
2011-08-15 21:50:08 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
for (const auto & name : column_names)
|
|
|
|
{
|
|
|
|
if (columns_map.end() == columns_map.find(name))
|
|
|
|
throw Exception("There is no column with name " + name + " in table. There are columns: " + listOfColumns(available_columns),
|
|
|
|
ErrorCodes::NO_SUCH_COLUMN_IN_TABLE);
|
2011-08-15 21:50:08 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
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);
|
|
|
|
}
|
2011-08-15 21:50:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-06 20:18:34 +00:00
|
|
|
void ITableDeclaration::check(const NamesAndTypesList & provided_columns) const
|
2014-07-14 14:07:47 +00:00
|
|
|
{
|
2018-03-13 15:00:28 +00:00
|
|
|
const NamesAndTypesList & available_columns = getColumns().getAllPhysical();
|
2017-04-01 07:20:54 +00:00
|
|
|
const auto columns_map = getColumnsMap(available_columns);
|
|
|
|
|
2018-06-19 18:09:09 +00:00
|
|
|
using UniqueStrings = GOOGLE_NAMESPACE::dense_hash_set<StringRef, StringRefHash>;
|
2017-04-01 07:20:54 +00:00
|
|
|
UniqueStrings unique_names;
|
|
|
|
unique_names.set_empty_key(StringRef());
|
|
|
|
|
2018-03-06 20:18:34 +00:00
|
|
|
for (const NameAndTypePair & column : provided_columns)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
2017-12-23 01:55:46 +00:00
|
|
|
if (!column.type->equals(*it->second))
|
2017-04-01 07:20:54 +00:00
|
|
|
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);
|
|
|
|
}
|
2014-07-14 14:07:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-06 20:18:34 +00:00
|
|
|
void ITableDeclaration::check(const NamesAndTypesList & provided_columns, const Names & column_names) const
|
2014-07-14 14:07:47 +00:00
|
|
|
{
|
2018-03-13 15:00:28 +00:00
|
|
|
const NamesAndTypesList & available_columns = getColumns().getAllPhysical();
|
2017-04-01 07:20:54 +00:00
|
|
|
const auto available_columns_map = getColumnsMap(available_columns);
|
2018-03-06 20:18:34 +00:00
|
|
|
const NamesAndTypesMap & provided_columns_map = getColumnsMap(provided_columns);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
if (column_names.empty())
|
|
|
|
throw Exception("Empty list of columns queried. There are columns: " + listOfColumns(available_columns),
|
|
|
|
ErrorCodes::EMPTY_LIST_OF_COLUMNS_QUERIED);
|
|
|
|
|
2018-06-19 18:09:09 +00:00
|
|
|
using UniqueStrings = GOOGLE_NAMESPACE::dense_hash_set<StringRef, StringRefHash>;
|
2017-04-01 07:20:54 +00:00
|
|
|
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);
|
|
|
|
|
2018-05-22 11:23:07 +00:00
|
|
|
if (!it->second->equals(*jt->second))
|
2017-04-01 07:20:54 +00:00
|
|
|
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);
|
|
|
|
}
|
2014-07-14 14:07:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-19 10:45:13 +00:00
|
|
|
void ITableDeclaration::check(const Block & block, bool need_all) const
|
2011-08-15 21:50:08 +00:00
|
|
|
{
|
2018-03-13 15:00:28 +00:00
|
|
|
const NamesAndTypesList & available_columns = getColumns().getAllPhysical();
|
2017-04-01 07:20:54 +00:00
|
|
|
const auto columns_map = getColumnsMap(available_columns);
|
|
|
|
|
|
|
|
NameSet names_in_block;
|
|
|
|
|
2018-01-23 18:49:15 +00:00
|
|
|
block.checkNumberOfRows();
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2018-01-23 18:49:15 +00:00
|
|
|
for (const auto & column : block)
|
|
|
|
{
|
2017-04-01 07:20:54 +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);
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2017-12-23 01:55:46 +00:00
|
|
|
if (!column.type->equals(*it->second))
|
2017-04-01 07:20:54 +00:00
|
|
|
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())
|
|
|
|
{
|
2017-12-25 21:57:29 +00:00
|
|
|
for (NamesAndTypesList::const_iterator it = available_columns.begin(); it != available_columns.end(); ++it)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
if (!names_in_block.count(it->name))
|
|
|
|
throw Exception("Expected column " + it->name, ErrorCodes::NOT_FOUND_COLUMN_IN_BLOCK);
|
|
|
|
}
|
|
|
|
}
|
2011-08-15 21:50:08 +00:00
|
|
|
}
|
|
|
|
|
2018-03-06 20:18:34 +00:00
|
|
|
|
|
|
|
ITableDeclaration::ITableDeclaration(ColumnsDescription columns_)
|
2018-01-25 14:42:39 +00:00
|
|
|
{
|
2018-03-13 14:18:11 +00:00
|
|
|
setColumns(std::move(columns_));
|
2018-01-25 14:42:39 +00:00
|
|
|
}
|
|
|
|
|
2011-08-15 21:50:08 +00:00
|
|
|
}
|