2021-03-09 14:10:28 +00:00
|
|
|
#include <DataTypes/EnumValues.h>
|
2021-09-28 12:59:22 +00:00
|
|
|
#include <boost/algorithm/string.hpp>
|
2022-01-30 19:49:48 +00:00
|
|
|
#include <base/sort.h>
|
|
|
|
|
2021-03-09 14:10:28 +00:00
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
|
|
|
extern const int SYNTAX_ERROR;
|
|
|
|
extern const int EMPTY_DATA_PASSED;
|
2023-03-28 22:31:53 +00:00
|
|
|
extern const int UNKNOWN_ELEMENT_OF_ENUM;
|
2021-03-09 14:10:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
EnumValues<T>::EnumValues(const Values & values_)
|
|
|
|
: values(values_)
|
|
|
|
{
|
|
|
|
if (values.empty())
|
2023-01-23 21:13:58 +00:00
|
|
|
throw Exception(ErrorCodes::EMPTY_DATA_PASSED, "DataTypeEnum enumeration cannot be empty");
|
2021-03-09 14:10:28 +00:00
|
|
|
|
2022-01-30 19:49:48 +00:00
|
|
|
::sort(std::begin(values), std::end(values), [] (auto & left, auto & right)
|
2021-03-09 14:10:28 +00:00
|
|
|
{
|
|
|
|
return left.second < right.second;
|
|
|
|
});
|
|
|
|
|
|
|
|
fillMaps();
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void EnumValues<T>::fillMaps()
|
|
|
|
{
|
|
|
|
for (const auto & name_and_value : values)
|
|
|
|
{
|
|
|
|
const auto inserted_value = name_to_value_map.insert(
|
|
|
|
{ StringRef{name_and_value.first}, name_and_value.second });
|
|
|
|
|
|
|
|
if (!inserted_value.second)
|
2023-01-23 21:13:58 +00:00
|
|
|
throw Exception(ErrorCodes::SYNTAX_ERROR, "Duplicate names in enum: '{}' = {} and {}",
|
|
|
|
name_and_value.first, toString(name_and_value.second), toString(inserted_value.first->getMapped()));
|
2021-03-09 14:10:28 +00:00
|
|
|
|
|
|
|
const auto inserted_name = value_to_name_map.insert(
|
|
|
|
{ name_and_value.second, StringRef{name_and_value.first} });
|
|
|
|
|
|
|
|
if (!inserted_name.second)
|
2023-01-23 21:13:58 +00:00
|
|
|
throw Exception(ErrorCodes::SYNTAX_ERROR, "Duplicate values in enum: '{}' = {} and '{}'",
|
|
|
|
name_and_value.first, toString(name_and_value.second), toString((*inserted_name.first).first));
|
2021-03-09 14:10:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
T EnumValues<T>::getValue(StringRef field_name, bool try_treat_as_id) const
|
|
|
|
{
|
|
|
|
const auto it = name_to_value_map.find(field_name);
|
|
|
|
if (!it)
|
|
|
|
{
|
|
|
|
/// It is used in CSV and TSV input formats. If we fail to find given string in
|
|
|
|
/// enum names, we will try to treat it as enum id.
|
|
|
|
if (try_treat_as_id)
|
|
|
|
{
|
|
|
|
T x;
|
|
|
|
ReadBufferFromMemory tmp_buf(field_name.data, field_name.size);
|
|
|
|
readText(x, tmp_buf);
|
|
|
|
/// Check if we reached end of the tmp_buf (otherwise field_name is not a number)
|
|
|
|
/// and try to find it in enum ids
|
|
|
|
if (tmp_buf.eof() && value_to_name_map.find(x) != value_to_name_map.end())
|
|
|
|
return x;
|
|
|
|
}
|
2021-05-06 13:07:36 +00:00
|
|
|
auto hints = this->getHints(field_name.toString());
|
2021-05-19 22:26:44 +00:00
|
|
|
auto hints_string = !hints.empty() ? ", maybe you meant: " + toString(hints) : "";
|
2023-03-28 22:31:53 +00:00
|
|
|
throw Exception(ErrorCodes::UNKNOWN_ELEMENT_OF_ENUM, "Unknown element '{}' for enum{}", field_name.toString(), hints_string);
|
2021-03-09 14:10:28 +00:00
|
|
|
}
|
|
|
|
return it->getMapped();
|
|
|
|
}
|
|
|
|
|
2021-05-06 13:07:36 +00:00
|
|
|
template <typename T>
|
|
|
|
Names EnumValues<T>::getAllRegisteredNames() const
|
|
|
|
{
|
|
|
|
Names result;
|
|
|
|
for (const auto & value : values)
|
|
|
|
result.emplace_back(value.first);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-09-28 12:59:22 +00:00
|
|
|
template <typename T>
|
|
|
|
std::unordered_set<String> EnumValues<T>::getSetOfAllNames(bool to_lower) const
|
|
|
|
{
|
|
|
|
std::unordered_set<String> result;
|
|
|
|
for (const auto & value : values)
|
|
|
|
result.insert(to_lower ? boost::algorithm::to_lower_copy(value.first) : value.first);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
std::unordered_set<T> EnumValues<T>::getSetOfAllValues() const
|
|
|
|
{
|
|
|
|
std::unordered_set<T> result;
|
|
|
|
for (const auto & value : values)
|
|
|
|
result.insert(value.second);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-03-09 14:10:28 +00:00
|
|
|
template class EnumValues<Int8>;
|
|
|
|
template class EnumValues<Int16>;
|
|
|
|
|
|
|
|
}
|