dbms: development.

This commit is contained in:
Alexey Milovidov 2009-07-20 15:35:23 +00:00
parent ea150ca671
commit c8e544b0f6
4 changed files with 330 additions and 9 deletions

View File

@ -2,12 +2,18 @@
#define DBMS_COLUMN_TYPE_H
#include <ostream>
#include <sstream>
#include <boost/variant/apply_visitor.hpp>
#include <Poco/SharedPtr.h>
#include <Poco/BinaryWriter.h>
#include <Poco/BinaryReader.h>
#include <Poco/NumberParser.h>
#include <Poco/NumberFormatter.h>
#include <Poco/RegularExpression.h>
#include <strconvert/escape_manip.h>
#include <DB/Field.h>
#include <DB/Exception.h>
@ -32,7 +38,9 @@ public:
virtual void serializeBinary(const DB::Field & field, std::ostream & ostr) const = 0;
virtual void deserializeBinary(DB::Field & field, std::istream & ostr) 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;
@ -87,6 +95,7 @@ template <> struct SerializeImpl<TextSerializationTag>
};
/** Аналог BIGINT UNSIGNED, сериализуется в набор байт фиксированной длины */
class ColumnTypeUInt64 : public IColumnType
{
public:
@ -116,6 +125,7 @@ public:
};
/** Аналог INT UNSIGNED, сериализуется в набор байт фиксированной длины */
class ColumnTypeUInt32 : public IColumnType
{
public:
@ -149,6 +159,7 @@ public:
};
/** Аналог BIGINT, сериализуется в набор байт фиксированной длины */
class ColumnTypeInt64 : public IColumnType
{
public:
@ -178,6 +189,7 @@ public:
};
/** Аналог INT, сериализуется в набор байт фиксированной длины */
class ColumnTypeInt32 : public IColumnType
{
public:
@ -211,6 +223,7 @@ public:
};
/** Аналог BIGINT UNSIGNED, сериализуемый в набор байт переменной длины (до 9 байт) */
class ColumnTypeVarUInt : public IColumnType
{
public:
@ -238,6 +251,7 @@ public:
};
/** Аналог BIGINT, сериализуемый в набор байт переменной длины (до 9 байт) */
class ColumnTypeVarInt : public IColumnType
{
public:
@ -265,6 +279,260 @@ public:
};
/** Строки (без явного указания кодировки) произвольной длины */
class ColumnTypeText : public IColumnType
{
public:
std::string getName() const { return "Text"; }
void serializeBinary(const DB::Field & field, std::ostream & ostr) const
{
const std::string & str = boost::get<String>(field);
writeVarUInt(str.size(), ostr);
ostr << str;
}
void deserializeBinary(DB::Field & field, std::istream & istr) const
{
field = std::string("");
std::string & str = boost::get<String>(field);
UInt size;
readVarUInt(size, istr);
str.resize(size);
/// непереносимо, но (действительно) быстрее
istr.read(const_cast<char*>(str.data()), size);
}
void serializeText(const DB::Field & field, std::ostream & ostr) const
{
ostr << boost::get<String>(field);
}
void deserializeText(DB::Field & field, std::istream & istr) const
{
istr >> boost::get<String>(field);
}
};
/** Строки (без явного указания кодировки) фиксированной длины */
class ColumnTypeFixedText : public IColumnType
{
private:
UInt size;
public:
ColumnTypeFixedText(UInt size_)
: size(size_)
{
}
std::string getName() const
{
return "FixedText(" + Poco::NumberFormatter::format(size) + ")";
}
void serializeBinary(const DB::Field & field, std::ostream & ostr) const
{
const String & str = boost::get<String>(field);
if (str.size() != size)
throw Exception("Incorrect size of value of type " + getName()
+ ": " + Poco::NumberFormatter::format(str.size()), ErrorCodes::INCORRECT_SIZE_OF_VALUE);
ostr << str;
}
void deserializeBinary(DB::Field & field, std::istream & istr) const
{
field = std::string("");
std::string & str = boost::get<String>(field);
str.resize(size);
/// непереносимо, но (действительно) быстрее
istr.read(const_cast<char*>(str.data()), size);
}
void serializeText(const DB::Field & field, std::ostream & ostr) const
{
serializeBinary(field, ostr);
}
void deserializeText(DB::Field & field, std::istream & istr) const
{
istr >> boost::get<String>(field);
}
};
/** Массив заданного типа произвольной длины */
class ColumnTypeArray : public IColumnType
{
private:
Poco::SharedPtr<IColumnType> nested_type;
public:
ColumnTypeArray(Poco::SharedPtr<IColumnType> nested_type_)
: nested_type(nested_type_)
{
}
std::string getName() const
{
return "Array(" + nested_type->getName() + ")";
}
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)
nested_type->serializeBinary(vec[i], ostr);
}
void deserializeBinary(DB::Field & field, std::istream & istr) const
{
FieldVector & vec = boost::get<FieldVector>(field);
UInt size;
readVarUInt(size, istr);
vec.resize(size);
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)
{
std::stringstream stream;
nested_type->serializeText(vec[i], stream);
ostr << strconvert::quote_fast << stream.str();
if (i + 1 != vec.size())
ostr << ", ";
}
}
void deserializeText(DB::Field & field, std::istream & istr) const
{
// TODO
throw Exception("Method ColumnTypeArray::deserializeText not implemented", ErrorCodes::METHOD_NOT_IMPLEMENTED);
}
};
/** Массив заданного типа фиксированной длины */
class ColumnTypeFixedArray : public IColumnType
{
private:
Poco::SharedPtr<IColumnType> nested_type;
UInt size;
public:
ColumnTypeFixedArray(Poco::SharedPtr<IColumnType> nested_type_, UInt size_)
: nested_type(nested_type_), size(size_)
{
}
std::string getName() const
{
return "Array(" + nested_type->getName() + ", " + Poco::NumberFormatter::format(size) + ")";
}
void serializeBinary(const DB::Field & field, std::ostream & ostr) const
{
const FieldVector & vec = boost::get<FieldVector>(field);
if (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)
nested_type->serializeBinary(vec[i], ostr);
}
void deserializeBinary(DB::Field & field, std::istream & istr) const
{
FieldVector & vec = boost::get<FieldVector>(field);
vec.resize(size);
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)
{
std::stringstream stream;
nested_type->serializeText(vec[i], stream);
ostr << strconvert::quote_fast << stream.str();
if (i + 1 != size)
ostr << ", ";
}
}
void deserializeText(DB::Field & field, std::istream & istr) const
{
// TODO
throw Exception("Method ColumnTypeFixedArray::deserializeText not implemented", ErrorCodes::METHOD_NOT_IMPLEMENTED);
}
};
/** Типа с дополнительным значением NULL */
class ColumnTypeNullable : public IColumnType
{
private:
Poco::SharedPtr<IColumnType> nested_type;
public:
ColumnTypeNullable(Poco::SharedPtr<IColumnType> nested_type_)
: nested_type(nested_type_)
{
}
std::string getName() const
{
return "Nullable(" + nested_type->getName() + ")";
}
void serializeBinary(const DB::Field & field, std::ostream & ostr) const
{
if (boost::apply_visitor(FieldVisitorIsNull(), field))
ostr.put(1);
else
{
ostr.put(0);
nested_type->serializeBinary(field, ostr);
}
}
void deserializeBinary(DB::Field & field, std::istream & istr) const
{
bool is_null = istr.get();
if (is_null)
field = Null();
else
nested_type->deserializeBinary(field, istr);
}
void serializeText(const DB::Field & field, std::ostream & ostr) const
{
if (boost::apply_visitor(FieldVisitorIsNull(), field))
ostr << "NULL";
else
{
nested_type->serializeText(field, ostr); /// пока не взаимнооднозначно
}
}
void deserializeText(DB::Field & field, std::istream & istr) const
{
// TODO
throw Exception("Method ColumnTypeNullable::deserializeText not implemented", ErrorCodes::METHOD_NOT_IMPLEMENTED);
}
};
class ColumnTypeFactory
{
public:
@ -282,7 +550,56 @@ public:
return new ColumnTypeUInt32;
if (name == "Int64")
return new ColumnTypeUInt64;
if (name == "Text")
return new ColumnTypeText;
/// параметризованные типы
static Poco::RegularExpression one_parameter_regexp("^([^\\(]+)\\((.+)\\)$");
static Poco::RegularExpression two_parameters_regexp("^([^\\(]+)\\((.+),\\s*(.+)\\)$");
Poco::RegularExpression::MatchVec matches;
if (two_parameters_regexp.match(name, 0, matches))
{
/// FixedArray(T, N), где T - любой тип, а N - размер
if (name.substr(matches[0].offset, matches[0].length) == "FixedArray")
{
UInt size;
if (!Poco::NumberParser::tryParseUnsigned64(name.substr(matches[2].offset, matches[2].length), size))
throw Exception("Incorrect parameter '"
+ name.substr(matches[2].offset, matches[2].length)
+ "'for type FixedArray", ErrorCodes::INCORRECT_PARAMETER_FOR_TYPE);
return new ColumnTypeFixedArray(
get(name.substr(matches[1].offset, matches[1].length)),
size);
}
}
if (one_parameter_regexp.match(name, 0, matches))
{
/// FixedText(N), где N - размер
if (name.substr(matches[0].offset, matches[0].length) == "FixedText")
{
UInt size;
if (!Poco::NumberParser::tryParseUnsigned64(name.substr(matches[1].offset, matches[1].length), size))
throw Exception("Incorrect parameter '"
+ name.substr(matches[1].offset, matches[1].length)
+ "'for type FixedText", ErrorCodes::INCORRECT_PARAMETER_FOR_TYPE);
return new ColumnTypeFixedText(size);
}
/// Array(T), где T - любой тип
if (name.substr(matches[0].offset, matches[0].length) == "Array")
return new ColumnTypeArray(get(name.substr(matches[1].offset, matches[1].length)));
/// Nullable(T), где T - любой тип
if (name.substr(matches[0].offset, matches[0].length) == "Nullable")
return new ColumnTypeNullable(get(name.substr(matches[1].offset, matches[1].length)));
}
/// неизвестный тип
throw Exception("Unknown column type " + name, ErrorCodes::UNKNOWN_COLUMN_TYPE);
}
};

View File

@ -11,6 +11,9 @@ namespace ErrorCodes
{
UNIMPLEMENTED_VISITOR_FOR_VARIANT = 1,
UNKNOWN_COLUMN_TYPE,
INCORRECT_PARAMETER_FOR_TYPE,
INCORRECT_SIZE_OF_VALUE,
METHOD_NOT_IMPLEMENTED,
};
}

View File

@ -8,6 +8,7 @@
#include <boost/variant.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <boost/variant/static_visitor.hpp>
#include <DB/Exception.h>
#include <DB/ErrorCodes.h>

View File

@ -11,15 +11,15 @@
int main(int argc, char ** argv)
{
DB::FieldVector vec;
vec.reserve(10000000);
vec.reserve(1000000);
Poco::Stopwatch stopwatch;
Poco::SharedPtr<DB::IColumnType> column_type = DB::ColumnTypeFactory::get("VarUInt");
Poco::SharedPtr<DB::IColumnType> column_type = DB::ColumnTypeFactory::get("Text");
{
stopwatch.restart();
for (int i = 0; i < 10000000; ++i)
for (int i = 0; i < 1000000; ++i)
{
vec.push_back(DB::UInt(i));
vec.push_back("http://www.boost.org/doc/libs/1_39_0/doc/html/variant/tutorial.html#variant.tutorial.recursive.recursive-variant");
}
stopwatch.stop();
std::cout << "Filling array: " << static_cast<double>(stopwatch.elapsed()) / 1000000 << std::endl;
@ -28,7 +28,7 @@ int main(int argc, char ** argv)
{
std::ofstream ostr("test");
stopwatch.restart();
for (int i = 0; i < 10000000; ++i)
for (int i = 0; i < 1000000; ++i)
{
column_type->serializeBinary(vec[i], ostr);
}
@ -39,7 +39,7 @@ int main(int argc, char ** argv)
{
std::ifstream istr("test");
stopwatch.restart();
for (int i = 0; i < 10000000; ++i)
for (int i = 0; i < 1000000; ++i)
{
column_type->deserializeBinary(vec[i], istr);
}
@ -50,7 +50,7 @@ int main(int argc, char ** argv)
{
std::ofstream ostr("test2");
stopwatch.restart();
for (int i = 0; i < 10000000; ++i)
for (int i = 0; i < 1000000; ++i)
{
column_type->serializeText(vec[i], ostr);
ostr.put('\t');
@ -62,7 +62,7 @@ int main(int argc, char ** argv)
{
std::ifstream istr("test2");
stopwatch.restart();
for (int i = 0; i < 10000000; ++i)
for (int i = 0; i < 1000000; ++i)
{
column_type->deserializeText(vec[i], istr);
}