ClickHouse/dbms/include/DB/Interpreters/Set.h

261 lines
7.9 KiB
C
Raw Normal View History

2012-08-22 20:29:01 +00:00
#pragma once
#include <set>
2014-03-26 10:56:21 +00:00
#include <boost/concept_check.hpp>
2012-08-22 20:29:01 +00:00
2012-08-23 23:49:28 +00:00
#include <statdaemons/Stopwatch.h>
#include <Yandex/logger_useful.h>
2012-08-23 23:49:28 +00:00
#include <DB/Core/ColumnNumbers.h>
#include <DB/Common/Arena.h>
2012-08-23 23:49:28 +00:00
#include <DB/DataStreams/IBlockInputStream.h>
2012-08-22 20:29:01 +00:00
#include <DB/Parsers/IAST.h>
#include <DB/Interpreters/HashSet.h>
2012-08-23 23:49:28 +00:00
#include <DB/Interpreters/AggregationCommon.h>
#include <DB/Interpreters/Limits.h>
#include <DB/Columns/ColumnConst.h>
#include <DB/Columns/ColumnArray.h>
2012-08-22 20:29:01 +00:00
2014-03-26 18:19:25 +00:00
#include <DB/Storages/MergeTree/BoolMask.h>
#include <DB/Storages/MergeTree/PKCondition.h>
2012-08-22 20:29:01 +00:00
namespace DB
{
/** Структура данных для реализации выражения IN.
*/
2012-08-23 22:40:51 +00:00
class Set
2012-08-22 20:29:01 +00:00
{
2012-08-23 22:40:51 +00:00
public:
Set(const Limits & limits)
: type(EMPTY), log(&Logger::get("Set")),
max_rows(limits.max_rows_in_set),
max_bytes(limits.max_bytes_in_set),
overflow_mode(limits.set_overflow_mode)
{
}
2012-08-23 20:22:44 +00:00
bool empty() { return type == EMPTY; }
2012-08-24 19:42:03 +00:00
/** Создать множество по выражению (для перечисления в самом запросе).
* types - типы того, что стоит слева от IN.
* node - это список значений: 1, 2, 3 или список tuple-ов: (1, 2), (3, 4), (5, 6).
*/
void createFromAST(DataTypes & types, ASTPtr node);
/** Запомнить поток блоков (для подзапросов), чтобы потом его можно было прочитать и создать множество.
*/
void setSource(BlockInputStreamPtr stream) { source = stream; }
BlockInputStreamPtr getSource() { return source; }
// Возвращает false, если превышено какое-нибудь ограничение, и больше не нужно вставлять.
bool insertFromBlock(Block & block);
size_t size() const { return getTotalRowCount(); }
2012-08-23 20:22:44 +00:00
/** Для указанных столбцов блока проверить принадлежность их значений множеству.
* Записать результат в столбец в позиции result.
*/
void execute(Block & block, const ColumnNumbers & arguments, size_t result, bool negative) const;
2014-03-26 10:56:21 +00:00
2014-03-26 18:19:25 +00:00
std::string descibe()
2014-03-26 10:56:21 +00:00
{
if (type == KEY_64)
return setToString(key64);
else if (type == KEY_STRING)
return setToString(key_string);
else if (type == HASHED)
2014-03-26 18:19:25 +00:00
return "{hashed values}";
2014-03-26 10:56:21 +00:00
else if (type == EMPTY)
return "{}";
2014-03-26 18:19:25 +00:00
else
throw DB::Exception("Unknown type");
2014-03-26 10:56:21 +00:00
}
2014-03-26 10:56:21 +00:00
void createOrderedSet()
{
for (auto & key : key64)
ordered_key64.push_back(key);
std::sort(ordered_key64.begin(), ordered_key64.end());
for (auto & key : key_string)
ordered_string.push_back(key);
std::sort(ordered_string.begin(), ordered_string.end());
}
2014-03-26 18:19:25 +00:00
BoolMask mayBeTrueInRange(const Field & left, const Field & right)
2014-03-26 10:56:21 +00:00
{
if (type == KEY_64)
2014-03-26 18:19:25 +00:00
return mayBeTrueInRangeImpl(left, right, ordered_key64);
2014-03-26 10:56:21 +00:00
else if (type == KEY_STRING)
2014-03-26 18:19:25 +00:00
return mayBeTrueInRangeImpl(left, right, ordered_string);
else{
std::stringstream ss;
ss << "Unsupported set of type " << type;
throw DB::Exception(ss.str());
}
2014-03-26 10:56:21 +00:00
}
2012-08-23 20:22:44 +00:00
private:
2012-08-22 20:29:01 +00:00
/** Разные структуры данных, которые могут использоваться для проверки принадлежности
* одного или нескольких столбцов значений множеству.
*/
typedef HashSet<UInt64> SetUInt64;
typedef HashSet<StringRef, StringRefHash, StringRefZeroTraits> SetString;
typedef HashSet<UInt128, UInt128Hash, UInt128ZeroTraits> SetHashed;
2012-08-23 20:22:44 +00:00
BlockInputStreamPtr source;
/// Специализация для случая, когда есть один числовой ключ.
2012-08-22 20:29:01 +00:00
SetUInt64 key64;
/// Специализация для случая, когда есть один строковый ключ.
SetString key_string;
Arena string_pool;
2012-08-22 20:29:01 +00:00
/** Сравнивает 128 битные хэши.
* Если все ключи фиксированной длины, влезающие целиком в 128 бит, то укладывает их без изменений в 128 бит.
* Иначе - вычисляет SipHash от набора из всех ключей.
2012-08-22 20:29:01 +00:00
* (При этом, строки, содержащие нули посередине, могут склеиться.)
2012-08-23 20:22:44 +00:00
*/
2012-08-22 20:29:01 +00:00
SetHashed hashed;
enum Type
{
EMPTY = 0,
KEY_64 = 1,
KEY_STRING = 2,
HASHED = 3,
2012-08-22 20:29:01 +00:00
};
Type type;
bool keys_fit_128_bits;
Sizes key_sizes;
2012-08-23 22:40:51 +00:00
/** Типы данных, из которых было создано множество.
* При проверке на принадлежность множеству, типы проверяемых столбцов должны с ними совпадать.
*/
DataTypes data_types;
2012-08-23 20:22:44 +00:00
Logger * log;
/// Ограничения на максимальный размер множества
size_t max_rows;
size_t max_bytes;
OverflowMode overflow_mode;
2013-07-19 19:53:51 +00:00
static Type chooseMethod(const ConstColumnPlainPtrs & key_columns, bool & keys_fit_128_bits, Sizes & key_sizes);
2012-08-23 23:49:28 +00:00
/// Если в левой части IN стоит массив. Проверяем, что хоть один элемент массива лежит в множестве.
void executeConstArray(const ColumnConstArray * key_column, ColumnUInt8::Container_t & vec_res, bool negative) const;
void executeArray(const ColumnArray * key_column, ColumnUInt8::Container_t & vec_res, bool negative) const;
/// Если в левой части набор столбцов тех же типов, что элементы множества.
void executeOrdinary(const ConstColumnPlainPtrs & key_columns, ColumnUInt8::Container_t & vec_res, bool negative) const;
/// Проверить не превышены ли допустимые размеры множества ключей
bool checkSetSizeLimits() const;
/// Считает суммарное число ключей во всех Set'ах
size_t getTotalRowCount() const;
/// Считает суммарный размер в байтах буфферов всех Set'ов + размер string_pool'а
size_t getTotalByteCount() const;
2014-03-26 10:56:21 +00:00
template <typename T>
std::string setToString(const T & set)
{
std::stringstream ss;
bool first = false;
2014-03-26 18:19:25 +00:00
for (auto it = set.begin(); it != set.end(); ++it)
2014-03-26 10:56:21 +00:00
{
if (first)
{
2014-03-26 18:19:25 +00:00
ss << *it;
2014-03-26 10:56:21 +00:00
first = false;
}
else
{
2014-03-26 18:19:25 +00:00
ss << ", " << *it;
2014-03-26 10:56:21 +00:00
}
}
ss << "}";
return ss.str();
}
/// несколько столбцов пока не поддерживаем
std::vector<UInt64> ordered_key64;
std::vector<StringRef> ordered_string;
2014-03-26 18:19:25 +00:00
template <class T>
BoolMask mayBeTrueInRangeImpl(const Field & field_left, const Field & field_right, const std::vector<T> & v)
2014-03-26 10:56:21 +00:00
{
2014-03-26 18:19:25 +00:00
T left = field_left.get<T>();
T right = field_right.get<T>();
2014-03-26 10:56:21 +00:00
bool can_be_true;
bool can_be_false = true;
/// Если во всем диапазоне одинаковый ключ и он есть в Set, то выбираем блок для in и не выбираем для notIn
2014-03-26 18:19:25 +00:00
if (left == right)
2014-03-26 10:56:21 +00:00
{
2014-03-26 18:19:25 +00:00
if (std::find(v.begin(), v.end(), left) != v.end())
2014-03-26 10:56:21 +00:00
{
can_be_false = false;
can_be_true = true;
}
2014-03-26 18:19:25 +00:00
else
{
can_be_true = false;
can_be_false = true;
}
2014-03-26 10:56:21 +00:00
}
else
{
2014-03-26 18:19:25 +00:00
auto left_it = std::lower_bound(v.begin(), v.end(), left);
2014-03-26 10:56:21 +00:00
/// если весь диапазон, правее in
2014-03-26 18:19:25 +00:00
if (left_it == v.end())
2014-03-26 10:56:21 +00:00
{
can_be_true = false;
}
else
{
2014-03-26 18:19:25 +00:00
auto right_it = std::upper_bound(v.begin(), v.end(), right);
2014-03-26 10:56:21 +00:00
/// весь диапазон, левее in
2014-03-26 18:19:25 +00:00
if (right_it == v.begin())
2014-03-26 10:56:21 +00:00
{
can_be_true = false;
}
else
{
--right_it;
/// в диапазон не попадает ни одного ключа из in
if (*right_it < *left_it)
{
can_be_true = false;
}
else
{
can_be_true = true;
}
}
}
}
return BoolMask(can_be_true, can_be_false);
}
2012-08-22 20:29:01 +00:00
};
2014-03-26 18:19:25 +00:00
typedef Poco::SharedPtr<Set> SetPtr;
typedef std::vector<SetPtr> Sets;
2012-08-22 20:29:01 +00:00
}