2011-08-28 00:31:30 +00:00
|
|
|
|
#pragma once
|
2010-03-01 16:59:51 +00:00
|
|
|
|
|
|
|
|
|
#include <vector>
|
2016-05-28 14:14:18 +00:00
|
|
|
|
#include <algorithm>
|
2014-01-08 16:33:28 +00:00
|
|
|
|
#include <type_traits>
|
|
|
|
|
#include <functional>
|
2010-03-01 16:59:51 +00:00
|
|
|
|
|
2015-10-05 01:35:28 +00:00
|
|
|
|
#include <DB/Common/Exception.h>
|
2015-10-12 07:05:54 +00:00
|
|
|
|
#include <DB/Core/Types.h>
|
2015-12-24 14:31:41 +00:00
|
|
|
|
#include <common/strong_typedef.h>
|
2014-12-09 12:07:27 +00:00
|
|
|
|
|
2010-03-01 16:59:51 +00:00
|
|
|
|
|
2013-10-11 11:43:50 +00:00
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
|
2016-01-11 21:46:36 +00:00
|
|
|
|
namespace ErrorCodes
|
|
|
|
|
{
|
|
|
|
|
extern const int BAD_TYPE_OF_FIELD;
|
|
|
|
|
extern const int BAD_GET;
|
|
|
|
|
extern const int NOT_IMPLEMENTED;
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-02 22:20:58 +00:00
|
|
|
|
class Field;
|
2017-01-06 17:41:19 +00:00
|
|
|
|
using Array = std::vector<Field>;
|
2015-12-24 14:31:41 +00:00
|
|
|
|
using TupleBackend = std::vector<Field>;
|
2017-01-06 17:41:19 +00:00
|
|
|
|
STRONG_TYPEDEF(TupleBackend, Tuple); /// Array and Tuple are different types with equal representation inside Field.
|
2013-10-11 11:43:50 +00:00
|
|
|
|
|
2010-03-01 16:59:51 +00:00
|
|
|
|
|
2017-01-06 17:41:19 +00:00
|
|
|
|
/** 32 is enough. Round number is used for alignment and for better arithmetic inside std::vector.
|
2013-01-08 21:32:16 +00:00
|
|
|
|
*/
|
2016-01-14 01:43:14 +00:00
|
|
|
|
#define DBMS_MIN_FIELD_SIZE 32
|
2013-01-08 21:32:16 +00:00
|
|
|
|
|
2013-01-05 20:03:19 +00:00
|
|
|
|
|
|
|
|
|
/** Discriminated union из нескольких типов.
|
|
|
|
|
* Сделан для замены boost::variant:
|
|
|
|
|
* является не обобщённым,
|
|
|
|
|
* зато несколько более эффективным, и более простым.
|
|
|
|
|
*
|
|
|
|
|
* Используется для представления единичного значения одного из нескольких типов в оперативке.
|
2010-03-01 16:59:51 +00:00
|
|
|
|
* Внимание! Предпочтительно вместо единичных значений хранить кусочки столбцов. См. Column.h
|
|
|
|
|
*/
|
2016-01-14 01:43:14 +00:00
|
|
|
|
class Field
|
2013-01-05 20:03:19 +00:00
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
struct Types
|
|
|
|
|
{
|
2017-01-20 04:06:05 +00:00
|
|
|
|
/// Type tag.
|
2013-01-05 20:03:19 +00:00
|
|
|
|
enum Which
|
|
|
|
|
{
|
|
|
|
|
Null = 0,
|
|
|
|
|
UInt64 = 1,
|
|
|
|
|
Int64 = 2,
|
|
|
|
|
Float64 = 3,
|
2013-01-07 06:47:15 +00:00
|
|
|
|
|
2017-01-20 04:06:05 +00:00
|
|
|
|
/// Non-POD types.
|
2013-01-07 06:47:15 +00:00
|
|
|
|
|
2013-01-05 20:03:19 +00:00
|
|
|
|
String = 16,
|
2013-02-03 23:11:21 +00:00
|
|
|
|
Array = 17,
|
2015-12-24 14:31:41 +00:00
|
|
|
|
Tuple = 18,
|
2013-01-05 20:03:19 +00:00
|
|
|
|
};
|
|
|
|
|
|
2013-01-07 06:53:24 +00:00
|
|
|
|
static const int MIN_NON_POD = 16;
|
|
|
|
|
|
2013-01-05 20:03:19 +00:00
|
|
|
|
static const char * toString(Which which)
|
|
|
|
|
{
|
|
|
|
|
switch (which)
|
|
|
|
|
{
|
|
|
|
|
case Null: return "Null";
|
|
|
|
|
case UInt64: return "UInt64";
|
|
|
|
|
case Int64: return "Int64";
|
|
|
|
|
case Float64: return "Float64";
|
|
|
|
|
case String: return "String";
|
|
|
|
|
case Array: return "Array";
|
2015-12-24 14:31:41 +00:00
|
|
|
|
case Tuple: return "Tuple";
|
2013-01-05 20:03:19 +00:00
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
2010-03-01 16:59:51 +00:00
|
|
|
|
|
2017-01-20 03:33:56 +00:00
|
|
|
|
|
2013-01-05 20:03:19 +00:00
|
|
|
|
/// Позволяет получить идентификатор для типа или наоборот.
|
|
|
|
|
template <typename T> struct TypeToEnum;
|
|
|
|
|
template <Types::Which which> struct EnumToType;
|
2010-03-01 16:59:51 +00:00
|
|
|
|
|
2012-08-26 06:48:39 +00:00
|
|
|
|
|
2013-01-05 20:03:19 +00:00
|
|
|
|
Field()
|
|
|
|
|
: which(Types::Null)
|
|
|
|
|
{
|
|
|
|
|
}
|
2010-03-01 16:59:51 +00:00
|
|
|
|
|
2013-01-05 20:03:19 +00:00
|
|
|
|
/** Не смотря на наличие шаблонного конструктора, этот конструктор всё-равно нужен,
|
2013-01-08 20:31:24 +00:00
|
|
|
|
* так как при его отсутствии, компилятор всё-равно сгенерирует конструктор по-умолчанию.
|
2013-01-05 20:03:19 +00:00
|
|
|
|
*/
|
|
|
|
|
Field(const Field & rhs)
|
|
|
|
|
{
|
|
|
|
|
create(rhs);
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-20 12:04:22 +00:00
|
|
|
|
Field(Field && rhs)
|
2013-01-05 20:03:19 +00:00
|
|
|
|
{
|
2017-01-20 03:33:56 +00:00
|
|
|
|
create(std::move(rhs));
|
2013-01-05 20:03:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
2017-01-20 04:06:05 +00:00
|
|
|
|
Field(T && rhs,
|
|
|
|
|
typename std::enable_if<!std::is_same<typename std::decay<T>::type, Field>::value, void>::type * unused = nullptr)
|
2013-01-05 20:03:19 +00:00
|
|
|
|
{
|
2017-01-20 04:06:05 +00:00
|
|
|
|
createConcrete(std::forward<T>(rhs));
|
2017-01-20 03:33:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-07 05:33:36 +00:00
|
|
|
|
/// Создать строку inplace.
|
|
|
|
|
Field(const char * data, size_t size)
|
|
|
|
|
{
|
2013-01-07 06:47:15 +00:00
|
|
|
|
create(data, size);
|
2013-01-07 05:33:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Field(const unsigned char * data, size_t size)
|
|
|
|
|
{
|
2013-01-07 06:47:15 +00:00
|
|
|
|
create(data, size);
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-20 03:33:56 +00:00
|
|
|
|
/// NOTE In case when field already has string type, more direct assign is possible.
|
2013-01-07 06:47:15 +00:00
|
|
|
|
void assignString(const char * data, size_t size)
|
|
|
|
|
{
|
|
|
|
|
destroy();
|
|
|
|
|
create(data, size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void assignString(const unsigned char * data, size_t size)
|
|
|
|
|
{
|
|
|
|
|
destroy();
|
|
|
|
|
create(data, size);
|
2013-01-07 05:33:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-12-20 12:04:22 +00:00
|
|
|
|
Field & operator= (const Field & rhs)
|
|
|
|
|
{
|
|
|
|
|
if (this != &rhs)
|
|
|
|
|
{
|
2017-01-20 03:33:56 +00:00
|
|
|
|
if (which != rhs.which)
|
|
|
|
|
{
|
|
|
|
|
destroy();
|
|
|
|
|
create(rhs);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
assign(rhs); /// This assigns string or vector without deallocation of existing buffer.
|
2016-12-20 12:04:22 +00:00
|
|
|
|
}
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Field & operator= (Field && rhs)
|
|
|
|
|
{
|
|
|
|
|
if (this != &rhs)
|
|
|
|
|
{
|
2017-01-20 03:33:56 +00:00
|
|
|
|
if (which != rhs.which)
|
|
|
|
|
{
|
|
|
|
|
destroy();
|
|
|
|
|
create(std::move(rhs));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
assign(std::move(rhs));
|
2016-12-20 12:04:22 +00:00
|
|
|
|
}
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-05 20:03:19 +00:00
|
|
|
|
template <typename T>
|
2017-01-20 04:06:05 +00:00
|
|
|
|
typename std::enable_if<!std::is_same<typename std::decay<T>::type, Field>::value, Field &>::type
|
|
|
|
|
operator= (T && rhs)
|
2013-01-05 20:03:19 +00:00
|
|
|
|
{
|
2017-01-20 03:33:56 +00:00
|
|
|
|
if (which != TypeToEnum<T>::value)
|
|
|
|
|
{
|
|
|
|
|
destroy();
|
2017-01-20 04:06:05 +00:00
|
|
|
|
createConcrete(std::forward<T>(rhs));
|
2017-01-20 03:33:56 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
2017-01-20 04:06:05 +00:00
|
|
|
|
assignConcrete(std::forward<T>(rhs));
|
2017-01-20 03:33:56 +00:00
|
|
|
|
|
2013-01-05 20:03:19 +00:00
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~Field()
|
|
|
|
|
{
|
|
|
|
|
destroy();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Types::Which getType() const { return which; }
|
|
|
|
|
const char * getTypeName() const { return Types::toString(which); }
|
|
|
|
|
|
2013-02-08 19:34:44 +00:00
|
|
|
|
bool isNull() const { return which == Types::Null; }
|
|
|
|
|
|
2013-01-05 20:03:19 +00:00
|
|
|
|
|
|
|
|
|
template <typename T> T & get()
|
|
|
|
|
{
|
2016-05-28 10:35:44 +00:00
|
|
|
|
using TWithoutRef = typename std::remove_reference<T>::type;
|
2013-01-05 20:03:19 +00:00
|
|
|
|
TWithoutRef * __attribute__((__may_alias__)) ptr = reinterpret_cast<TWithoutRef*>(storage);
|
|
|
|
|
return *ptr;
|
|
|
|
|
};
|
2013-02-25 23:08:25 +00:00
|
|
|
|
|
2013-01-05 20:03:19 +00:00
|
|
|
|
template <typename T> const T & get() const
|
|
|
|
|
{
|
2016-05-28 10:35:44 +00:00
|
|
|
|
using TWithoutRef = typename std::remove_reference<T>::type;
|
2013-01-05 20:03:19 +00:00
|
|
|
|
const TWithoutRef * __attribute__((__may_alias__)) ptr = reinterpret_cast<const TWithoutRef*>(storage);
|
|
|
|
|
return *ptr;
|
2010-03-01 16:59:51 +00:00
|
|
|
|
};
|
2013-01-05 20:03:19 +00:00
|
|
|
|
|
|
|
|
|
template <typename T> T & safeGet()
|
|
|
|
|
{
|
2017-01-20 04:06:05 +00:00
|
|
|
|
const Types::Which requested = TypeToEnum<typename std::decay<T>::type>::value;
|
2013-01-05 20:03:19 +00:00
|
|
|
|
if (which != requested)
|
|
|
|
|
throw Exception("Bad get: has " + std::string(getTypeName()) + ", requested " + std::string(Types::toString(requested)), ErrorCodes::BAD_GET);
|
|
|
|
|
return get<T>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T> const T & safeGet() const
|
|
|
|
|
{
|
2017-01-20 04:06:05 +00:00
|
|
|
|
const Types::Which requested = TypeToEnum<typename std::decay<T>::type>::value;
|
2013-01-05 20:03:19 +00:00
|
|
|
|
if (which != requested)
|
|
|
|
|
throw Exception("Bad get: has " + std::string(getTypeName()) + ", requested " + std::string(Types::toString(requested)), ErrorCodes::BAD_GET);
|
|
|
|
|
return get<T>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool operator< (const Field & rhs) const
|
|
|
|
|
{
|
|
|
|
|
if (which < rhs.which)
|
|
|
|
|
return true;
|
|
|
|
|
if (which > rhs.which)
|
|
|
|
|
return false;
|
2013-02-25 23:08:25 +00:00
|
|
|
|
|
2013-01-05 20:03:19 +00:00
|
|
|
|
switch (which)
|
|
|
|
|
{
|
2013-01-08 20:31:24 +00:00
|
|
|
|
case Types::Null: return false;
|
2013-01-05 20:03:19 +00:00
|
|
|
|
case Types::UInt64: return get<UInt64>() < rhs.get<UInt64>();
|
|
|
|
|
case Types::Int64: return get<Int64>() < rhs.get<Int64>();
|
|
|
|
|
case Types::Float64: return get<Float64>() < rhs.get<Float64>();
|
|
|
|
|
case Types::String: return get<String>() < rhs.get<String>();
|
|
|
|
|
case Types::Array: return get<Array>() < rhs.get<Array>();
|
2015-12-24 14:31:41 +00:00
|
|
|
|
case Types::Tuple: return get<Tuple>() < rhs.get<Tuple>();
|
2013-01-05 20:03:19 +00:00
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool operator> (const Field & rhs) const
|
|
|
|
|
{
|
|
|
|
|
return rhs < *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool operator<= (const Field & rhs) const
|
|
|
|
|
{
|
|
|
|
|
if (which < rhs.which)
|
|
|
|
|
return true;
|
|
|
|
|
if (which > rhs.which)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
switch (which)
|
|
|
|
|
{
|
2013-01-08 20:31:24 +00:00
|
|
|
|
case Types::Null: return true;
|
2013-01-05 20:03:19 +00:00
|
|
|
|
case Types::UInt64: return get<UInt64>() <= rhs.get<UInt64>();
|
|
|
|
|
case Types::Int64: return get<Int64>() <= rhs.get<Int64>();
|
|
|
|
|
case Types::Float64: return get<Float64>() <= rhs.get<Float64>();
|
|
|
|
|
case Types::String: return get<String>() <= rhs.get<String>();
|
|
|
|
|
case Types::Array: return get<Array>() <= rhs.get<Array>();
|
2015-12-24 14:31:41 +00:00
|
|
|
|
case Types::Tuple: return get<Tuple>() <= rhs.get<Tuple>();
|
2013-01-05 20:03:19 +00:00
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool operator>= (const Field & rhs) const
|
|
|
|
|
{
|
|
|
|
|
return rhs <= *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool operator== (const Field & rhs) const
|
|
|
|
|
{
|
|
|
|
|
if (which != rhs.which)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
switch (which)
|
|
|
|
|
{
|
2013-01-08 20:31:24 +00:00
|
|
|
|
case Types::Null: return true;
|
|
|
|
|
case Types::UInt64:
|
|
|
|
|
case Types::Int64:
|
|
|
|
|
case Types::Float64: return get<UInt64>() == rhs.get<UInt64>();
|
2013-01-05 20:03:19 +00:00
|
|
|
|
case Types::String: return get<String>() == rhs.get<String>();
|
|
|
|
|
case Types::Array: return get<Array>() == rhs.get<Array>();
|
2015-12-24 14:31:41 +00:00
|
|
|
|
case Types::Tuple: return get<Tuple>() == rhs.get<Tuple>();
|
2013-01-05 20:03:19 +00:00
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool operator!= (const Field & rhs) const
|
|
|
|
|
{
|
|
|
|
|
return !(*this == rhs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2016-01-14 01:43:14 +00:00
|
|
|
|
static const size_t storage_size = std::max({
|
|
|
|
|
DBMS_MIN_FIELD_SIZE - sizeof(Types::Which),
|
|
|
|
|
sizeof(Null), sizeof(UInt64), sizeof(Int64), sizeof(Float64), sizeof(String), sizeof(Array), sizeof(Tuple)});
|
2013-01-05 20:03:19 +00:00
|
|
|
|
|
2013-01-08 20:31:24 +00:00
|
|
|
|
char storage[storage_size] __attribute__((aligned(8)));
|
2013-01-05 20:03:19 +00:00
|
|
|
|
Types::Which which;
|
|
|
|
|
|
|
|
|
|
|
2017-01-20 03:33:56 +00:00
|
|
|
|
/// Assuming there was no allocated state or it was deallocated (see destroy).
|
2013-01-05 20:03:19 +00:00
|
|
|
|
template <typename T>
|
2017-01-20 04:06:05 +00:00
|
|
|
|
void createConcrete(T && x)
|
2013-01-05 20:03:19 +00:00
|
|
|
|
{
|
2017-01-20 04:06:05 +00:00
|
|
|
|
using JustT = typename std::decay<T>::type;
|
|
|
|
|
which = TypeToEnum<JustT>::value;
|
|
|
|
|
JustT * __attribute__((__may_alias__)) ptr = reinterpret_cast<JustT *>(storage);
|
|
|
|
|
new (ptr) JustT(std::forward<T>(x));
|
2013-01-05 20:03:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-01-20 03:33:56 +00:00
|
|
|
|
/// Assuming same types.
|
|
|
|
|
template <typename T>
|
2017-01-20 04:06:05 +00:00
|
|
|
|
void assignConcrete(T && x)
|
2017-01-20 03:33:56 +00:00
|
|
|
|
{
|
2017-01-20 04:06:05 +00:00
|
|
|
|
using JustT = typename std::decay<T>::type;
|
|
|
|
|
JustT * __attribute__((__may_alias__)) ptr = reinterpret_cast<JustT *>(storage);
|
|
|
|
|
*ptr = std::forward<T>(x);
|
2017-01-20 03:33:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <typename F, typename Field> /// Field template parameter may be const or non-const Field.
|
|
|
|
|
static void dispatch(F && f, Field & field)
|
|
|
|
|
{
|
|
|
|
|
switch (field.which)
|
2013-01-05 20:03:19 +00:00
|
|
|
|
{
|
2017-01-20 04:08:31 +00:00
|
|
|
|
case Types::Null: f(field.template get<Null>()); return;
|
|
|
|
|
case Types::UInt64: f(field.template get<UInt64>()); return;
|
|
|
|
|
case Types::Int64: f(field.template get<Int64>()); return;
|
|
|
|
|
case Types::Float64: f(field.template get<Float64>()); return;
|
|
|
|
|
case Types::String: f(field.template get<String>()); return;
|
|
|
|
|
case Types::Array: f(field.template get<Array>()); return;
|
|
|
|
|
case Types::Tuple: f(field.template get<Tuple>()); return;
|
2017-01-20 03:33:56 +00:00
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD);
|
2013-01-05 20:03:19 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-20 03:33:56 +00:00
|
|
|
|
|
|
|
|
|
void create(const Field & x)
|
|
|
|
|
{
|
2017-01-20 04:06:05 +00:00
|
|
|
|
dispatch([this] (auto & value) { createConcrete(value); }, x);
|
2017-01-20 03:33:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void create(Field && x)
|
|
|
|
|
{
|
2017-01-20 04:06:05 +00:00
|
|
|
|
dispatch([this] (auto & value) { createConcrete(std::move(value)); }, x);
|
2017-01-20 03:33:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void assign(const Field & x)
|
|
|
|
|
{
|
2017-01-20 04:06:05 +00:00
|
|
|
|
dispatch([this] (auto & value) { assignConcrete(value); }, x);
|
2017-01-20 03:33:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void assign(Field && x)
|
|
|
|
|
{
|
2017-01-20 04:06:05 +00:00
|
|
|
|
dispatch([this] (auto & value) { assignConcrete(std::move(value)); }, x);
|
2017-01-20 03:33:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-01-07 06:47:15 +00:00
|
|
|
|
void create(const char * data, size_t size)
|
|
|
|
|
{
|
|
|
|
|
which = Types::String;
|
|
|
|
|
String * __attribute__((__may_alias__)) ptr = reinterpret_cast<String*>(storage);
|
|
|
|
|
new (ptr) String(data, size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void create(const unsigned char * data, size_t size)
|
|
|
|
|
{
|
|
|
|
|
create(reinterpret_cast<const char *>(data), size);
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-07 08:27:39 +00:00
|
|
|
|
__attribute__((__always_inline__)) void destroy()
|
2013-01-05 20:03:19 +00:00
|
|
|
|
{
|
2013-01-07 06:53:24 +00:00
|
|
|
|
if (which < Types::MIN_NON_POD)
|
|
|
|
|
return;
|
2013-02-25 23:08:25 +00:00
|
|
|
|
|
2013-01-05 20:03:19 +00:00
|
|
|
|
switch (which)
|
|
|
|
|
{
|
|
|
|
|
case Types::String:
|
|
|
|
|
destroy<String>();
|
|
|
|
|
break;
|
|
|
|
|
case Types::Array:
|
|
|
|
|
destroy<Array>();
|
|
|
|
|
break;
|
2015-12-24 14:31:41 +00:00
|
|
|
|
case Types::Tuple:
|
|
|
|
|
destroy<Tuple>();
|
|
|
|
|
break;
|
2013-01-07 06:47:15 +00:00
|
|
|
|
default:
|
|
|
|
|
break;
|
2013-01-05 20:03:19 +00:00
|
|
|
|
}
|
2017-01-20 03:33:56 +00:00
|
|
|
|
|
|
|
|
|
which = Types::Null; /// for exception safety in subsequent calls to destroy and create, when create fails.
|
2013-01-05 20:03:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
void destroy()
|
|
|
|
|
{
|
|
|
|
|
T * __attribute__((__may_alias__)) ptr = reinterpret_cast<T*>(storage);
|
|
|
|
|
ptr->~T();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2016-01-14 01:43:14 +00:00
|
|
|
|
#undef DBMS_MIN_FIELD_SIZE
|
2015-10-12 07:05:54 +00:00
|
|
|
|
|
2014-05-12 00:45:50 +00:00
|
|
|
|
|
2013-02-03 23:11:21 +00:00
|
|
|
|
template <> struct Field::TypeToEnum<Null> { static const Types::Which value = Types::Null; };
|
|
|
|
|
template <> struct Field::TypeToEnum<UInt64> { static const Types::Which value = Types::UInt64; };
|
|
|
|
|
template <> struct Field::TypeToEnum<Int64> { static const Types::Which value = Types::Int64; };
|
|
|
|
|
template <> struct Field::TypeToEnum<Float64> { static const Types::Which value = Types::Float64; };
|
|
|
|
|
template <> struct Field::TypeToEnum<String> { static const Types::Which value = Types::String; };
|
2013-10-11 11:43:50 +00:00
|
|
|
|
template <> struct Field::TypeToEnum<Array> { static const Types::Which value = Types::Array; };
|
2015-12-24 14:31:41 +00:00
|
|
|
|
template <> struct Field::TypeToEnum<Tuple> { static const Types::Which value = Types::Tuple; };
|
2013-01-05 20:03:19 +00:00
|
|
|
|
|
2017-01-20 03:33:56 +00:00
|
|
|
|
template <> struct Field::EnumToType<Field::Types::Null> { using Type = Null ; };
|
2016-05-28 10:35:44 +00:00
|
|
|
|
template <> struct Field::EnumToType<Field::Types::UInt64> { using Type = UInt64 ; };
|
|
|
|
|
template <> struct Field::EnumToType<Field::Types::Int64> { using Type = Int64 ; };
|
|
|
|
|
template <> struct Field::EnumToType<Field::Types::Float64> { using Type = Float64 ; };
|
|
|
|
|
template <> struct Field::EnumToType<Field::Types::String> { using Type = String ; };
|
|
|
|
|
template <> struct Field::EnumToType<Field::Types::Array> { using Type = Array ; };
|
|
|
|
|
template <> struct Field::EnumToType<Field::Types::Tuple> { using Type = Tuple ; };
|
2013-01-05 20:03:19 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
T get(const Field & field)
|
|
|
|
|
{
|
|
|
|
|
return field.template get<T>();
|
2010-03-01 16:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-05 20:03:19 +00:00
|
|
|
|
template <typename T>
|
|
|
|
|
T get(Field & field)
|
|
|
|
|
{
|
|
|
|
|
return field.template get<T>();
|
|
|
|
|
}
|
2010-03-01 16:59:51 +00:00
|
|
|
|
|
2013-01-05 20:03:19 +00:00
|
|
|
|
template <typename T>
|
|
|
|
|
T safeGet(const Field & field)
|
2010-03-01 16:59:51 +00:00
|
|
|
|
{
|
2013-01-05 20:03:19 +00:00
|
|
|
|
return field.template safeGet<T>();
|
|
|
|
|
}
|
2010-03-01 16:59:51 +00:00
|
|
|
|
|
2013-01-05 20:03:19 +00:00
|
|
|
|
template <typename T>
|
|
|
|
|
T safeGet(Field & field)
|
2010-03-01 16:59:51 +00:00
|
|
|
|
{
|
2013-01-05 20:03:19 +00:00
|
|
|
|
return field.template safeGet<T>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <> struct TypeName<Array> { static std::string get() { return "Array"; } };
|
2015-12-24 14:31:41 +00:00
|
|
|
|
template <> struct TypeName<Tuple> { static std::string get() { return "Tuple"; } };
|
2013-01-05 20:03:19 +00:00
|
|
|
|
|
|
|
|
|
|
2010-03-18 19:32:14 +00:00
|
|
|
|
template <typename T> struct NearestFieldType;
|
|
|
|
|
|
2016-05-28 10:35:44 +00:00
|
|
|
|
template <> struct NearestFieldType<UInt8> { using Type = UInt64 ; };
|
|
|
|
|
template <> struct NearestFieldType<UInt16> { using Type = UInt64 ; };
|
|
|
|
|
template <> struct NearestFieldType<UInt32> { using Type = UInt64 ; };
|
|
|
|
|
template <> struct NearestFieldType<UInt64> { using Type = UInt64 ; };
|
|
|
|
|
template <> struct NearestFieldType<Int8> { using Type = Int64 ; };
|
|
|
|
|
template <> struct NearestFieldType<Int16> { using Type = Int64 ; };
|
|
|
|
|
template <> struct NearestFieldType<Int32> { using Type = Int64 ; };
|
|
|
|
|
template <> struct NearestFieldType<Int64> { using Type = Int64 ; };
|
|
|
|
|
template <> struct NearestFieldType<Float32> { using Type = Float64 ; };
|
|
|
|
|
template <> struct NearestFieldType<Float64> { using Type = Float64 ; };
|
|
|
|
|
template <> struct NearestFieldType<String> { using Type = String ; };
|
|
|
|
|
template <> struct NearestFieldType<Array> { using Type = Array ; };
|
|
|
|
|
template <> struct NearestFieldType<Tuple> { using Type = Tuple ; };
|
|
|
|
|
template <> struct NearestFieldType<bool> { using Type = UInt64 ; };
|
2017-01-20 04:06:05 +00:00
|
|
|
|
template <> struct NearestFieldType<Null> { using Type = Null; };
|
2012-06-07 18:32:21 +00:00
|
|
|
|
|
2013-10-04 20:15:42 +00:00
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
typename NearestFieldType<T>::Type nearestFieldType(const T & x)
|
|
|
|
|
{
|
|
|
|
|
return typename NearestFieldType<T>::Type(x);
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-01 16:59:51 +00:00
|
|
|
|
}
|
2012-09-05 19:51:09 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Заглушки, чтобы DBObject-ы с полем типа Array компилировались.
|
2015-10-12 07:05:54 +00:00
|
|
|
|
#include <mysqlxx/Manip.h>
|
|
|
|
|
|
2012-09-05 19:51:09 +00:00
|
|
|
|
namespace mysqlxx
|
|
|
|
|
{
|
2015-10-12 07:05:54 +00:00
|
|
|
|
std::ostream & operator<< (mysqlxx::EscapeManipResult res, const DB::Array & value);
|
|
|
|
|
std::ostream & operator<< (mysqlxx::QuoteManipResult res, const DB::Array & value);
|
|
|
|
|
std::istream & operator>> (mysqlxx::UnEscapeManipResult res, DB::Array & value);
|
|
|
|
|
std::istream & operator>> (mysqlxx::UnQuoteManipResult res, DB::Array & value);
|
2015-12-24 14:31:41 +00:00
|
|
|
|
|
|
|
|
|
std::ostream & operator<< (mysqlxx::EscapeManipResult res, const DB::Tuple & value);
|
|
|
|
|
std::ostream & operator<< (mysqlxx::QuoteManipResult res, const DB::Tuple & value);
|
|
|
|
|
std::istream & operator>> (mysqlxx::UnEscapeManipResult res, DB::Tuple & value);
|
|
|
|
|
std::istream & operator>> (mysqlxx::UnQuoteManipResult res, DB::Tuple & value);
|
2012-09-05 19:51:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
class ReadBuffer;
|
|
|
|
|
class WriteBuffer;
|
2014-08-09 22:36:07 +00:00
|
|
|
|
|
2013-03-09 05:44:26 +00:00
|
|
|
|
/// Предполагается что у всех элементов массива одинаковый тип.
|
2015-10-12 07:05:54 +00:00
|
|
|
|
void readBinary(Array & x, ReadBuffer & buf);
|
2014-08-09 22:36:07 +00:00
|
|
|
|
|
2012-09-05 19:51:09 +00:00
|
|
|
|
inline void readText(Array & x, ReadBuffer & buf) { throw Exception("Cannot read Array.", ErrorCodes::NOT_IMPLEMENTED); }
|
|
|
|
|
inline void readQuoted(Array & x, ReadBuffer & buf) { throw Exception("Cannot read Array.", ErrorCodes::NOT_IMPLEMENTED); }
|
|
|
|
|
|
2013-03-09 05:44:26 +00:00
|
|
|
|
/// Предполагается что у всех элементов массива одинаковый тип.
|
2015-10-12 07:05:54 +00:00
|
|
|
|
void writeBinary(const Array & x, WriteBuffer & buf);
|
2014-08-09 22:36:07 +00:00
|
|
|
|
|
2015-10-12 07:05:54 +00:00
|
|
|
|
void writeText(const Array & x, WriteBuffer & buf);
|
2014-08-09 22:36:07 +00:00
|
|
|
|
|
2013-03-11 10:29:41 +00:00
|
|
|
|
inline void writeQuoted(const Array & x, WriteBuffer & buf) { throw Exception("Cannot write Array quoted.", ErrorCodes::NOT_IMPLEMENTED); }
|
2012-09-05 19:51:09 +00:00
|
|
|
|
}
|
2015-12-24 14:31:41 +00:00
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
void readBinary(Tuple & x, ReadBuffer & buf);
|
|
|
|
|
|
|
|
|
|
inline void readText(Tuple & x, ReadBuffer & buf) { throw Exception("Cannot read Tuple.", ErrorCodes::NOT_IMPLEMENTED); }
|
|
|
|
|
inline void readQuoted(Tuple & x, ReadBuffer & buf) { throw Exception("Cannot read Tuple.", ErrorCodes::NOT_IMPLEMENTED); }
|
|
|
|
|
|
|
|
|
|
void writeBinary(const Tuple & x, WriteBuffer & buf);
|
|
|
|
|
|
|
|
|
|
void writeText(const Tuple & x, WriteBuffer & buf);
|
|
|
|
|
|
|
|
|
|
inline void writeQuoted(const Tuple & x, WriteBuffer & buf) { throw Exception("Cannot write Tuple quoted.", ErrorCodes::NOT_IMPLEMENTED); }
|
|
|
|
|
}
|