dbms: development.

This commit is contained in:
Alexey Milovidov 2009-07-23 18:03:21 +00:00
parent c8e544b0f6
commit 2dbd493503
18 changed files with 772 additions and 69 deletions

View File

@ -0,0 +1,35 @@
#ifndef DBMS_AGGREGATE_FUNCTION_H
#define DBMS_AGGREGATE_FUNCTION_H
namespace DB
{
/** Агрегатная функция
* Шаблонный параметр здесь только потому что непонятно, как сделать forward declaration Field из Field.h.
*/
template<typename Field>
class IAggregateFunction
{
public:
virtual void add(const Field & a) = 0;
virtual Field getValue() const = 0;
/** Бинарная сериализация и десериализация состояния для передачи по сети.
* При чём, deserializeMerge производит объединение текущего и считываемого состояний.
*/
virtual void serialize(std::ostream & ostr) const = 0;
virtual void deserializeMerge(std::istream & istr) = 0;
/** Объединение состояния агрегатной функции с состоянием другой агрегатной функции. */
virtual void merge(const IAggregateFunction & rhs) = 0;
virtual ~IAggregateFunction() {}
};
}
#endif

24
dbms/include/DB/Column.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef DBMS_COLUMN_H
#define DBMS_COLUMN_H
#include <string>
#include <Poco/SharedPtr.h>
#include <DB/ColumnType.h>
namespace DB
{
/** Столбец - часть ColumnGroup, которая, в свою очередь - часть таблицы
*/
struct Column
{
std::string name;
Poco::SharedPtr<IColumnType> type;
};
}
#endif

View File

@ -0,0 +1,32 @@
#ifndef DBMS_COLUMN_GROUP_H
#define DBMS_COLUMN_GROUP_H
#include <list>
#include <string>
#include <Poco/SharedPtr.h>
#include <DB/Column.h>
#include <DB/PrimaryKey.h>
namespace DB
{
/** ColumnGroup - часть таблицы, которая хранится отдельно.
* Может состоять из одного, нескольких или всех столбцов таблицы.
* Таблица состоит из column-групп.
*/
struct ColumnGroup
{
/// Номера столбцов
typedef std::vector<size_t> ColumnNumbers;
ColumnNumbers column_numbers;
/// Первичный ключ
Poco::SharedPtr<IPrimaryKey> primary_key;
};
}
#endif

View File

@ -36,17 +36,19 @@ public:
/// Бинарная сериализация - для сохранения на диск / в сеть и т. п.
virtual void serializeBinary(const DB::Field & field, std::ostream & ostr) const = 0;
virtual void deserializeBinary(DB::Field & field, std::istream & ostr) const = 0;
virtual void deserializeBinary(DB::Field & field, std::istream & istr) const = 0;
/** Текстовая сериализация - для вывода на экран / сохранения в текстовый файл и т. п.
* Считается, что разделители, а также escape-инг обязан делать вызывающий.
*/
virtual void serializeText(const DB::Field & field, std::ostream & ostr) const = 0;
virtual void deserializeText(DB::Field & field, std::istream & ostr) const = 0;
virtual void deserializeText(DB::Field & field, std::istream & istr) const = 0;
/// Шаблонные методы для параметризуемого типа сериализации.
template <typename SerializationTag> void serialize(const DB::Field & field, std::ostream & ostr) const;
template <typename SerializationTag> void deserialize(DB::Field & field, std::istream & ostr) const;
template <typename SerializationTag> void deserialize(DB::Field & field, std::istream & istr) const;
virtual ~IColumnType() {}
};
@ -288,7 +290,7 @@ public:
void serializeBinary(const DB::Field & field, std::ostream & ostr) const
{
const std::string & str = boost::get<String>(field);
writeVarUInt(str.size(), ostr);
writeVarUInt(UInt(str.size()), ostr);
ostr << str;
}
@ -335,7 +337,7 @@ public:
void serializeBinary(const DB::Field & field, std::ostream & ostr) const
{
const String & str = boost::get<String>(field);
if (str.size() != size)
if (UInt(str.size()) != size)
throw Exception("Incorrect size of value of type " + getName()
+ ": " + Poco::NumberFormatter::format(str.size()), ErrorCodes::INCORRECT_SIZE_OF_VALUE);
@ -383,8 +385,8 @@ public:
void serializeBinary(const DB::Field & field, std::ostream & ostr) const
{
const FieldVector & vec = boost::get<FieldVector>(field);
writeVarUInt(vec.size(), ostr);
for (UInt i = 0; i < vec.size(); ++i)
writeVarUInt(UInt(vec.size()), ostr);
for (UInt i(0); i < vec.size(); ++i)
nested_type->serializeBinary(vec[i], ostr);
}
@ -394,14 +396,14 @@ public:
UInt size;
readVarUInt(size, istr);
vec.resize(size);
for (UInt i = 0; i < size; ++i)
for (UInt i(0); i < size; ++i)
nested_type->deserializeBinary(vec[i], istr);
}
void serializeText(const DB::Field & field, std::ostream & ostr) const
{
const FieldVector & vec = boost::get<FieldVector>(field);
for (UInt i = 0; i < vec.size(); ++i)
for (UInt i(0); i < vec.size(); ++i)
{
std::stringstream stream;
nested_type->serializeText(vec[i], stream);
@ -441,11 +443,11 @@ public:
{
const FieldVector & vec = boost::get<FieldVector>(field);
if (vec.size() != size)
if (UInt(vec.size()) != size)
throw Exception("Incorrect size of value of type " + getName()
+ ": " + Poco::NumberFormatter::format(vec.size()), ErrorCodes::INCORRECT_SIZE_OF_VALUE);
for (UInt i = 0; i < size; ++i)
for (UInt i(0); i < size; ++i)
nested_type->serializeBinary(vec[i], ostr);
}
@ -453,14 +455,14 @@ public:
{
FieldVector & vec = boost::get<FieldVector>(field);
vec.resize(size);
for (UInt i = 0; i < size; ++i)
for (UInt i(0); i < size; ++i)
nested_type->deserializeBinary(vec[i], istr);
}
void serializeText(const DB::Field & field, std::ostream & ostr) const
{
const FieldVector & vec = boost::get<FieldVector>(field);
for (UInt i = 0; i < size; ++i)
for (UInt i(0); i < size; ++i)
{
std::stringstream stream;
nested_type->serializeText(vec[i], stream);

View File

@ -14,6 +14,11 @@ namespace ErrorCodes
INCORRECT_PARAMETER_FOR_TYPE,
INCORRECT_SIZE_OF_VALUE,
METHOD_NOT_IMPLEMENTED,
CANT_READ_INDEX_FILE,
TOO_FEW_COLUMNS_FOR_KEY,
PRIMARY_KEY_WAS_NOT_ATTACHED,
CANT_READ_DATA_FILE,
TOO_MANY_COLUMNS_FOR_KEY
};
}

View File

@ -5,13 +5,17 @@
#include <vector>
#include <Poco/Types.h>
#include <Poco/Void.h>
#include <Poco/SharedPtr.h>
#include <boost/strong_typedef.hpp>
#include <boost/variant.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <boost/variant/static_visitor.hpp>
#include <DB/Exception.h>
#include <DB/ErrorCodes.h>
#include <DB/AggregateFunction.h>
namespace DB
@ -21,8 +25,7 @@ namespace DB
typedef Poco::Int64 Int;
typedef Poco::UInt64 UInt;
typedef std::string String;
struct Null {};
BOOST_STRONG_TYPEDEF(char, Null);
/** Используется для хранения значений в памяти
@ -36,56 +39,19 @@ typedef boost::make_recursive_variant<
UInt,
String,
Null,
Poco::SharedPtr<IAggregateFunction<boost::recursive_variant_> >,
std::vector<boost::recursive_variant_> /// FieldVector
>::type Field;
typedef std::vector<Field> FieldVector; /// Значение типа "массив"
typedef Poco::SharedPtr<IAggregateFunction<Field> > AggregateFunctionPtr;
/** Визитор по умолчанию, который ничего не делает
* - нужно для того, чтобы наследоваться от него и писать меньше кода
* для визиторов, которые делают что-то содержательное только для нескольких вариантов.
*/
class FieldVisitorDefaultNothing : public boost::static_visitor<>
{
public:
template <typename T> void operator() (const T & x) const {}
};
/** Визитор по умолчанию, который для всех вариантов кидает исключение
* - нужно для того, чтобы наследоваться от него и писать меньше кода
* для визиторов, которые делают что-то содержательное только для нескольких вариантов,
* но передача в него других вариантов должна вызывать runtime ошибку.
*/
class FieldVisitorDefaultThrow : public boost::static_visitor<>
{
public:
void operator() (const DB::Int & x) const
{
throw Exception("Unimplemented visitor for variant Int", ErrorCodes::UNIMPLEMENTED_VISITOR_FOR_VARIANT);
}
void operator() (const DB::UInt & x) const
{
throw Exception("Unimplemented visitor for variant UInt", ErrorCodes::UNIMPLEMENTED_VISITOR_FOR_VARIANT);
}
void operator() (const DB::String & x) const
{
throw Exception("Unimplemented visitor for variant String", ErrorCodes::UNIMPLEMENTED_VISITOR_FOR_VARIANT);
}
void operator() (const DB::Null & x) const
{
throw Exception("Unimplemented visitor for variant Null", ErrorCodes::UNIMPLEMENTED_VISITOR_FOR_VARIANT);
}
void operator() (const DB::FieldVector & x) const
{
throw Exception("Unimplemented visitor for variant FieldVector", ErrorCodes::UNIMPLEMENTED_VISITOR_FOR_VARIANT);
}
};
/// почему-то у boost::variant определены операторы < и ==, но не остальные операторы сравнения
inline bool operator!= (const Field & lhs, const Field & rhs) { return !(lhs == rhs); }
inline bool operator<= (const Field & lhs, const Field & rhs) { return lhs < rhs || lhs == rhs; }
inline bool operator>= (const Field & lhs, const Field & rhs) { return !(lhs < rhs); }
inline bool operator> (const Field & lhs, const Field & rhs) { return !(lhs < rhs) && !(lhs == rhs); }
/** Возвращает true, если вариант - Null */
@ -97,6 +63,32 @@ public:
};
/** Принимает два значения Field, обновляет первое вторым.
* Если только первое - не агрегатная функция, результат обновления - замена первого вторым.
* Иначе - добавление к агрегатной функции значения или объединение агрегатных функций.
*/
class FieldVisitorUpdate : public boost::static_visitor<>
{
public:
template <typename T, typename U>
void operator() (T & x, const U & y) const
{
x = y;
}
template <typename T>
void operator() (AggregateFunctionPtr & x, const T & y) const
{
x->add(y);
}
void operator() (AggregateFunctionPtr & x, const AggregateFunctionPtr & y) const
{
x->merge(*y);
}
};
}
#endif

View File

@ -0,0 +1,82 @@
#ifndef DBMS_PRIMARY_KEY_H
#define DBMS_PRIMARY_KEY_H
#include <Poco/SharedPtr.h>
#include <DB/RowSet.h>
#include <DB/TablePartReader.h>
namespace DB
{
class ColumnGroup;
class Table;
/** Первичный ключ - самая важная часть БД.
* Отвечает за:
* - определение, в каком файле (или не файле) хранятся данные;
* - поиск данных и обновление данных;
* - структура хранения данных (сжатие, etc.)
* - конкуррентный доступ к данным (блокировки, etc.)
*
* Присутствуют следующие особенности первичного ключа:
* - может состоять из нескольких частей. Например, значения первых нескольких столбцов индексируются
* с помощью файловой системы для удобства бэкапа и устаревания данных; а значения остальных столбцов
* индексируются с помощью B-дерева.
* - может не полностью индексировать столбцы, однозначно идентифицирующие строку в таблице -
* для работы с пачками строк.
*/
class IPrimaryKey
{
friend class Table;
private:
/** Установить указатель на таблицу и кол-группу.
* - часть инициализации, которая выполняется при инициализации таблицы.
* (инициализация первичного ключа выполняется в два шага:
* 1 - конструктор,
* 2 - добавление к таблице (выполняется в конструкторе Table))
*/
virtual void addToTable(Table * table_, ColumnGroup * column_group_) = 0;
public:
/** Прочитать данные, соответствующие точному значению ключа или префиксу.
* Возвращает объект, с помощью которого можно последовательно читать данные.
*/
virtual Poco::SharedPtr<ITablePartReader> read(const Row & key) = 0;
/** Записать пачку данных в таблицу, обновляя существующие данные, если они есть.
* @param data - набор данных вида ключ (набор столбцов) -> значение (набор столбцов)
* @param mask - битовая маска - какие столбцы входят в кол-группу,
* которую индексирует этот первичный ключ
*/
virtual void merge(const AggregatedRowSet & data, const ColumnMask & mask) = 0;
virtual ~IPrimaryKey() {}
};
/** Реализует метод addToTable(),
* а также содержит члены table, column_group.
*/
class PrimaryKeyBase : public IPrimaryKey
{
protected:
/// Слабые указатели на таблицу и column_group, которые владеют этим первичным ключём.
Table * table;
ColumnGroup * column_group;
PrimaryKeyBase() : table(0), column_group(0) {}
void addToTable(Table * table_, ColumnGroup * column_group_)
{
table = table_;
column_group = column_group_;
}
};
}
#endif

View File

@ -0,0 +1,58 @@
#ifndef DBMS_PRIMARY_KEY_NONE_H
#define DBMS_PRIMARY_KEY_NONE_H
#include <Poco/SharedPtr.h>
#include <Poco/File.h>
#include <Poco/FileStream.h>
#include <DB/PrimaryKey.h>
#include <DB/TablePartReader.h>
namespace DB
{
/** Самый простой первичный ключ - ничего не индексирует;
* для чтения или обновления приходится читать файл целиком.
* - удобно для логов.
*/
class PrimaryKeyNone : public PrimaryKeyBase
{
friend class PrimaryKeyNoneTablePartReader;
private:
std::string path;
std::string name;
std::string data_file_name;
Poco::File data_file;
public:
/** Путь со слешем на конце. */
PrimaryKeyNone(const std::string & path_, const std::string & name_);
/** Просто дописывает данные в конец. */
void merge(const AggregatedRowSet & data, const ColumnMask & mask);
/** Прочитать данные, префикс ключа которых совпадает с key */
Poco::SharedPtr<ITablePartReader> read(const Row & key);
};
class PrimaryKeyNoneTablePartReader : public ITablePartReader
{
friend class PrimaryKeyNone;
private:
const Row key;
/// слабый указатель на первичный ключ
PrimaryKeyNone * pk;
Poco::FileInputStream istr;
PrimaryKeyNoneTablePartReader(const Row & key_, PrimaryKeyNone * pk_);
public:
bool fetch(Row & row);
};
}
#endif

View File

@ -0,0 +1,64 @@
#ifndef DBMS_PRIMARY_KEY_PLAIN_H
#define DBMS_PRIMARY_KEY_PLAIN_H
#include <set>
#include <map>
#include <Poco/SharedPtr.h>
#include <Poco/BinaryReader.h>
#include <DB/Table.h>
#include <DB/PrimaryKey.h>
namespace DB
{
/** Простой, "плоский" первичный ключ.
* Хранит список смещений в бинарном файле, список свободных блоков - в другом бинарном файле.
* Поиск в этом файле линейный.
* При обновлении данных, индексный файл полностью перезаписывается.
* Файл с данными не сжатый.
* Индекс полностью загружается в память во время работы.
*/
class PrimaryKeyPlain : public PrimaryKeyBase
{
private:
std::string path;
std::string name;
std::string data_file_name;
std::string offsets_file_name;
std::string free_blocks_file_name;
Poco::File data_file;
Poco::File offsets_file;
Poco::File free_blocks_file;
struct Offset
{
size_t offset; /// смещение от начала файла
size_t size; /// размер данных
bool operator< (const Offset & rhs) const
{
return size < rhs.size;
}
};
std::map<Row, Offset> offsets;
std::set<Offset> free_blocks;
public:
/** Путь со слешем на конце. */
PrimaryKeyPlain(const std::string & path_, const std::string & name_);
void addToTable(Table * table_, ColumnGroup * column_group_);
void merge(const AggregatedRowSet & data, const ColumnMask & mask);
};
}
#endif

View File

@ -1,17 +1,21 @@
#ifndef DBMS_ROW_H
#define DBMS_ROW_H
#include <map>
#include <vector>
#include <DB/Field.h>
namespace DB
{
/** Используется для хранения строк в памяти
* - при обработке запроса, для временных таблиц, для результата.
*/
/** Строка или часть строки.
* Используется для хранения строк в памяти
* - при обработке запроса, для временных таблиц, для результата.
*/
typedef std::vector<Field> Row;
}
#endif

26
dbms/include/DB/RowSet.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef DBMS_ROW_SET_H
#define DBMS_ROW_SET_H
#include <map>
#include <vector>
#include <DB/Row.h>
namespace DB
{
/** Набор строк. */
typedef std::vector<Row> RowSet;
/** Набор строк, использующийся в качестве результата запроса с агрегатными функциями,
* а также как массив для загрузки данных в таблицу.
*/
typedef std::map<Row, Row> AggregatedRowSet;
/** Битовая маска столбцов. */
typedef std::vector<bool> ColumnMask;
}
#endif

57
dbms/include/DB/Table.h Normal file
View File

@ -0,0 +1,57 @@
#ifndef DBMS_TABLE_H
#define DBMS_TABLE_H
#include <set>
#include <Poco/SharedPtr.h>
#include <DB/Column.h>
#include <DB/ColumnGroup.h>
namespace DB
{
class Table
{
friend class PrimaryKeyNone;
friend class PrimaryKeyNoneTablePartReader;
friend class PrimaryKeyPlain;
public:
typedef std::vector<Column> Columns;
typedef std::vector<size_t> ColumnNumbers;
typedef std::vector<ColumnGroup> ColumnGroups;
private:
/// Имя таблицы
std::string name;
/// Столбцы
Poco::SharedPtr<Columns> columns;
/// Столбцы, которые относятся к первичному ключу
Poco::SharedPtr<ColumnNumbers> primary_key_column_numbers;
/// Группы столбцов
Poco::SharedPtr<ColumnGroups> column_groups;
public:
Table(const std::string & name_,
const Poco::SharedPtr<Columns> columns_,
const Poco::SharedPtr<ColumnNumbers> primary_key_column_numbers_,
const Poco::SharedPtr<ColumnGroups> column_groups_)
: name(name_),
columns(columns_),
primary_key_column_numbers(primary_key_column_numbers_),
column_groups(column_groups_)
{
/// Пропишем в первичных ключах в кол-группах указатель на таблицу и кол-группу
for (ColumnGroups::iterator it = column_groups->begin(); it != column_groups->end(); ++it)
it->primary_key->addToTable(this, &*it);
}
};
}
#endif

View File

@ -0,0 +1,21 @@
#ifndef DBMS_TABLE_PART_READER_H
#define DBMS_TABLE_PART_READER_H
#include <DB/Row.h>
namespace DB
{
class ITablePartReader
{
public:
/// прочитать следующую строку, вернуть false, если строк больше нет
virtual bool fetch(Row & row) = 0;
virtual ~ITablePartReader() {}
};
}
#endif

View File

@ -0,0 +1,87 @@
#include <DB/Exception.h>
#include <DB/ErrorCodes.h>
#include <DB/Table.h>
#include <DB/ColumnGroup.h>
#include <DB/PrimaryKeyNone.h>
namespace DB
{
PrimaryKeyNone::PrimaryKeyNone(const std::string & path_, const std::string & name_)
: path(path_),
name(name_),
data_file_name(path + name + ".dat"),
data_file(data_file_name)
{
/// создаём файлы, если их ещё нет
data_file.createFile();
}
void PrimaryKeyNone::merge(const AggregatedRowSet & data, const ColumnMask & mask)
{
if (!table || !column_group)
throw Exception("Primary key was not attached to table and column group",
ErrorCodes::PRIMARY_KEY_WAS_NOT_ATTACHED);
/// просто дописываем данные в конец файла
Poco::FileOutputStream ostr(data_file_name, std::ios::out | std::ios::binary | std::ios::app);
for (AggregatedRowSet::const_iterator it = data.begin(); it != data.end(); ++it)
{
for (size_t j = 0; j != it->first.size(); ++j)
if (mask[j])
table->columns->at(column_group->column_numbers[j]).type->serializeBinary(it->first[j], ostr);
for (size_t j = 0; j != it->second.size(); ++j)
if (mask[j + it->first.size()])
table->columns->at(
column_group->column_numbers[j + it->first.size()]
).type->serializeBinary(it->second[j], ostr);
}
}
Poco::SharedPtr<ITablePartReader> PrimaryKeyNone::read(const Row & key)
{
return new PrimaryKeyNoneTablePartReader(key, this);
}
PrimaryKeyNoneTablePartReader::PrimaryKeyNoneTablePartReader(
const Row & key_, PrimaryKeyNone * pk_)
: key(key_), pk(pk_), istr(pk->data_file_name)
{
}
bool PrimaryKeyNoneTablePartReader::fetch(Row & row)
{
if (key.size() > pk->column_group->column_numbers.size())
throw Exception("Too many columns specified for key", ErrorCodes::TOO_MANY_COLUMNS_FOR_KEY);
while (1)
{
for (size_t i = 0; i < pk->column_group->column_numbers.size(); ++i)
pk->table->columns->at(pk->column_group->column_numbers[i]).type->deserializeBinary(row[i], istr);
/// проверим, что ключи совпадают (замечание: столбцы ключа всегда идут первыми)
for (size_t i = 0; i < key.size(); ++i)
if (key[i] != row[i])
continue;
if (istr.eof())
return false;
if (istr.fail())
throw Exception("Cannot read data file " + pk->data_file_name
, ErrorCodes::CANT_READ_DATA_FILE);
return true;
}
}
}

View File

@ -0,0 +1,99 @@
#include <Poco/File.h>
#include <Poco/FileStream.h>
#include <Poco/BinaryWriter.h>
#include <DB/PrimaryKeyPlain.h>
namespace DB
{
PrimaryKeyPlain::PrimaryKeyPlain(const std::string & path_, const std::string & name_)
: path(path_),
name(name_),
data_file_name(path + name + ".dat"),
offsets_file_name(path + name + ".idx"),
free_blocks_file_name(path + name + ".blk"),
data_file(data_file_name),
offsets_file(offsets_file_name),
free_blocks_file(free_blocks_file_name)
{
/// создаём файлы, если их ещё нет
data_file.createFile();
offsets_file.createFile();
free_blocks_file.createFile();
/// прочитаем список свободных блоков
Poco::FileInputStream free_blocks_istr(free_blocks_file_name);
Poco::BinaryReader free_blocks_reader(free_blocks_istr);
while (1)
{
Offset offset;
free_blocks_reader >> offset.offset >> offset.size;
if (free_blocks_istr.eof())
break;
if (free_blocks_istr.fail())
throw Exception("Cannot read index file " + free_blocks_file_name
, ErrorCodes::CANT_READ_INDEX_FILE);
free_blocks.insert(offset);
}
}
void PrimaryKeyPlain::addToTable(Table * table_, ColumnGroup * column_group_)
{
PrimaryKeyBase::addToTable(table_, column_group_);
/// прочитаем список смещений
Poco::FileInputStream offsets_istr(offsets_file_name);
Poco::BinaryReader offsets_reader(offsets_istr);
while (1)
{
Row key;
for (Table::ColumnNumbers::const_iterator it = table->primary_key_column_numbers->begin();
it != table->primary_key_column_numbers->end();
++it)
{
key.push_back(Field());
table->columns->at(*it).type->deserializeBinary(key.back(), offsets_istr);
}
Offset offset;
offsets_reader >> offset.offset >> offset.size;
if (offsets_istr.eof())
break;
if (offsets_istr.fail())
throw Exception("Cannot read index file " + offsets_file_name
, ErrorCodes::CANT_READ_INDEX_FILE);
offsets[key] = offset;
}
}
void PrimaryKeyPlain::merge(const AggregatedRowSet & data, const ColumnMask & mask)
{
/* std::set<Row> keys;
for (Result::const_iterator it = data.begin(); it != data.end(); ++it)
{
if (data->first.size() < columns.size())
throw Exception("Too few columns for key", ErrorCodes::TOO_FEW_COLUMNS_FOR_KEY);
Row key;
for (size_t j = 0; j < columns.size(); ++j)
key.push_back(it->first[j]);
keys.insert(key);
}*/
}
}

View File

@ -0,0 +1,85 @@
#include <iostream>
#include <Poco/Stopwatch.h>
#include <DB/Table.h>
#include <DB/Column.h>
#include <DB/ColumnType.h>
#include <DB/PrimaryKeyNone.h>
#include <DB/RowSet.h>
int main(int argc, char ** argv)
{
Poco::Stopwatch stopwatch;
/// создаём таблицу
DB::Column column0;
column0.name = "ID";
column0.type = new DB::ColumnTypeVarUInt;
DB::Column column1;
column1.name = "PageViews";
column1.type = new DB::ColumnTypeVarUInt;
DB::Column column2;
column2.name = "URL";
column2.type = new DB::ColumnTypeText;
Poco::SharedPtr<DB::Table::Columns> columns = new DB::Table::Columns;
columns->push_back(column0);
columns->push_back(column1);
columns->push_back(column2);
Poco::SharedPtr<DB::Table::ColumnNumbers> primary_key_column_numbers = new DB::Table::ColumnNumbers;
primary_key_column_numbers->push_back(0);
DB::ColumnGroup column_group0;
column_group0.column_numbers.push_back(0);
column_group0.column_numbers.push_back(1);
column_group0.column_numbers.push_back(2);
column_group0.primary_key = new DB::PrimaryKeyNone("./", "TestPrimaryKeyNone");
Poco::SharedPtr<DB::Table::ColumnGroups> column_groups = new DB::Table::ColumnGroups;
column_groups->push_back(column_group0);
DB::Table table("TestTable", columns, primary_key_column_numbers, column_groups);
/// создаём набор данных
DB::AggregatedRowSet data;
{
DB::Row key;
key.push_back(DB::Field(DB::UInt(0)));
key.push_back(DB::Field(DB::UInt(0)));
key.push_back(DB::Field(DB::String("")));
DB::Row value;
stopwatch.restart();
for (int i = 0; i < 1000000; ++i)
{
key[0] = DB::UInt(i);
key[1] = DB::UInt(i * 123456789 % 1000000);
key[2] = "http://www.google.com/custom?cof=LW%3A277%3BL%3Ahttp%3A%2F%2Fwww.boost.org%2Fboost.png%3BLH%3A86%3BAH%3Acenter%3BGL%3A0%3BS%3Ahttp%3A%2F%2Fwww.boost.org%3BAWFID%3A9b83d16ce652ed5a%3B&sa=Google+Search&domains=www.boost.org%3Blists.boost.org&hq=site%3Awww.boost.org+OR+site%3Alists.boost.org&q=boost%3A%3Ablank";
data[key] = value;
}
stopwatch.stop();
std::cout << "Filling data: " << static_cast<double>(stopwatch.elapsed()) / 1000000 << std::endl;
}
/// заполняем таблицу
{
DB::ColumnMask mask(3, true);
stopwatch.restart();
column_group0.primary_key->merge(data, mask);
stopwatch.stop();
std::cout << "Saving data: " << static_cast<double>(stopwatch.elapsed()) / 1000000 << std::endl;
}
return 0;
}

View File

@ -0,0 +1,17 @@
#include <iostream>
#include <boost/variant.hpp>
#include <DB/Field.h>
int main(int argc, char ** argv)
{
DB::Field f1(DB::UInt(10));
DB::Field f2(DB::String("test"));
std::cout << (f1 < f1) << std::endl;
std::cout << (f1 < f2) << std::endl;
std::cout << (f1 == f1) << std::endl;
std::cout << (f1 == f2) << std::endl;
return 0;
}

View File

@ -66,6 +66,10 @@ public:
ostr << '}' << "," << std::endl;
}
void operator() (const DB::AggregateFunctionPtr & x) const
{
}
private:
std::ostream & ostr;
unsigned indent;
@ -75,14 +79,23 @@ private:
class TimesTwoVisitor : public boost::static_visitor<>
{
public:
template <typename T> void operator() (T & x) const { x *= 2; }
void operator() (DB::Int & x) const { x *= 2; }
void operator() (DB::UInt & x) const { x *= 2; }
void operator() (DB::Null & x) const {}
void operator() (DB::String & x) const { x = ""; }
void operator() (DB::FieldVector & x) const
void operator() (const DB::String & x) const
{
}
void operator() (const DB::Null & x) const
{
}
void operator() (const DB::FieldVector & x) const
{
}
void operator() (const DB::AggregateFunctionPtr & x) const
{
TimesTwoVisitor visitor;
std::for_each(x.begin(), x.end(), boost::apply_visitor(visitor));
}
};