Merge branch 'master' of github.com:yandex/ClickHouse

This commit is contained in:
Alexey Milovidov 2017-06-02 18:54:43 +03:00
commit ba499585cd
434 changed files with 1343 additions and 1187 deletions

1
.gitignore vendored
View File

@ -223,3 +223,4 @@ config-preprocessed.xml
# Gulp dependencies used to minify website # Gulp dependencies used to minify website
node_modules node_modules
public public
website/docs

View File

@ -1,6 +1,6 @@
#This strings autochanged from release_lib.sh : #This strings autochanged from release_lib.sh :
set(VERSION_DESCRIBE v1.1.54236-testing) set(VERSION_DESCRIBE v1.1.54237-testing)
set(VERSION_REVISION 54236) set(VERSION_REVISION 54237)
#===end of autochange #===end of autochange
set (VERSION_MAJOR 1) set (VERSION_MAJOR 1)

View File

@ -216,7 +216,7 @@ struct StdDevPopImpl
} }
/** If `compute_marginal_moments` flag is set this class provides the heir /** If `compute_marginal_moments` flag is set this class provides the successor
* CovarianceData support of marginal moments for calculating the correlation. * CovarianceData support of marginal moments for calculating the correlation.
*/ */
template<bool compute_marginal_moments> template<bool compute_marginal_moments>

View File

@ -6,7 +6,8 @@
#include <Poco/Mutex.h> #include <Poco/Mutex.h>
#include <Poco/Semaphore.h> #include <Poco/Semaphore.h>
#include <Core/Types.h> #include <common/Types.h>
namespace detail namespace detail
{ {
@ -66,8 +67,8 @@ public:
fill_count.set(); fill_count.set();
} }
template <class ... Args> template <typename... Args>
void emplace(Args && ... args) void emplace(Args &&... args)
{ {
empty_count.wait(); empty_count.wait();
{ {
@ -88,7 +89,7 @@ public:
empty_count.set(); empty_count.set();
} }
bool tryPush(const T & x, DB::UInt64 milliseconds = 0) bool tryPush(const T & x, UInt64 milliseconds = 0)
{ {
if (empty_count.tryWait(milliseconds)) if (empty_count.tryWait(milliseconds))
{ {
@ -102,8 +103,8 @@ public:
return false; return false;
} }
template <class ... Args> template <typename... Args>
bool tryEmplace(DB::UInt64 milliseconds, Args && ... args) bool tryEmplace(UInt64 milliseconds, Args &&... args)
{ {
if (empty_count.tryWait(milliseconds)) if (empty_count.tryWait(milliseconds))
{ {
@ -117,7 +118,7 @@ public:
return false; return false;
} }
bool tryPop(T & x, DB::UInt64 milliseconds = 0) bool tryPop(T & x, UInt64 milliseconds = 0)
{ {
if (fill_count.tryWait(milliseconds)) if (fill_count.tryWait(milliseconds))
{ {

View File

@ -1,4 +1,4 @@
#include <IO/ReadHelpers.h> #include <Common/hex.h>
#include <Common/StringUtils.h> #include <Common/StringUtils.h>
#include <Common/escapeForFileName.h> #include <Common/escapeForFileName.h>
@ -11,8 +11,6 @@ std::string escapeForFileName(const std::string & s)
const char * pos = s.data(); const char * pos = s.data();
const char * end = pos + s.size(); const char * end = pos + s.size();
static const char * hex = "0123456789ABCDEF";
while (pos != end) while (pos != end)
{ {
char c = *pos; char c = *pos;
@ -22,8 +20,8 @@ std::string escapeForFileName(const std::string & s)
else else
{ {
res += '%'; res += '%';
res += hex[c / 16]; res += hexUppercase(c / 16);
res += hex[c % 16]; res += hexUppercase(c % 16);
} }
++pos; ++pos;

View File

@ -1,6 +1,9 @@
#include <Common/hex.h> #include <Common/hex.h>
const char * const char_to_digit_table = ( const char * const hex_digit_to_char_uppercase_table = "0123456789ABCDEF";
const char * const hex_digit_to_char_lowercase_table = "0123456789abcdef";
const char * const hex_char_to_digit_table =
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
@ -16,5 +19,4 @@ const char * const char_to_digit_table = (
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
);

View File

@ -1,3 +1,27 @@
#pragma once #pragma once
extern const char * const char_to_digit_table;
/// Maps 0..15 to 0..9A..F or 0..9a..f correspondingly.
extern const char * const hex_digit_to_char_uppercase_table;
extern const char * const hex_digit_to_char_lowercase_table;
inline char hexUppercase(unsigned char c)
{
return hex_digit_to_char_uppercase_table[c];
}
inline char hexLowercase(unsigned char c)
{
return hex_digit_to_char_lowercase_table[c];
}
/// Maps 0..9, A..F, a..f to 0..15. Other chars are mapped to implementation specific value.
extern const char * const hex_char_to_digit_table;
inline char unhex(char c)
{
return hex_char_to_digit_table[static_cast<unsigned char>(c)];
}

View File

@ -195,7 +195,7 @@ protected:
QuotaForIntervals * quota = nullptr; /// If nullptr - the quota is not used. QuotaForIntervals * quota = nullptr; /// If nullptr - the quota is not used.
double prev_elapsed = 0; double prev_elapsed = 0;
/// The heirs must implement this function. /// The successors must implement this function.
virtual Block readImpl() = 0; virtual Block readImpl() = 0;
/// Here you can do a preliminary initialization. /// Here you can do a preliminary initialization.

View File

@ -1,11 +1,12 @@
#include <DataStreams/verbosePrintString.h> #include <DataStreams/verbosePrintString.h>
#include <Common/hex.h>
#include <IO/Operators.h> #include <IO/Operators.h>
namespace DB namespace DB
{ {
void verbosePrintString(BufferBase::Position begin, BufferBase::Position end, WriteBuffer & out) void verbosePrintString(const char * begin, const char * end, WriteBuffer & out)
{ {
if (end == begin) if (end == begin)
{ {
@ -50,10 +51,7 @@ void verbosePrintString(BufferBase::Position begin, BufferBase::Position end, Wr
default: default:
{ {
if (*pos >= 0 && *pos < 32) if (*pos >= 0 && *pos < 32)
{ out << "<0x" << hexUppercase(*pos / 16) << hexUppercase(*pos % 16) << ">";
static const char * hex = "0123456789ABCDEF";
out << "<0x" << hex[*pos / 16] << hex[*pos % 16] << ">";
}
else else
out << *pos; out << *pos;
} }

View File

@ -1,12 +1,14 @@
#pragma once #pragma once
#include <IO/WriteBuffer.h>
namespace DB namespace DB
{ {
class WriteBuffer;
/** Print string in double quotes and with control characters in "<NAME>" form - for output diagnostic info to user. /** Print string in double quotes and with control characters in "<NAME>" form - for output diagnostic info to user.
*/ */
void verbosePrintString(BufferBase::Position begin, BufferBase::Position end, WriteBuffer & out); void verbosePrintString(const char * begin, const char * end, WriteBuffer & out);
} }

View File

@ -35,28 +35,29 @@ namespace ErrorCodes
} }
/** Функции по работе с массивами: /** Array functions:
* *
* array(с1, с2, ...) - создать массив из констант. * array(c1, c2, ...) - create an array.
* arrayElement(arr, i) - получить элемент массива по индексу. * arrayElement(arr, i) - get the array element by index. If index is not constant and out of range - return default value of data type.
* Индекс начинается с 1. Также индекс может быть отрицательным - тогда он считается с конца массива. * The index begins with 1. Also, the index can be negative - then it is counted from the end of the array.
* has(arr, x) - есть ли в массиве элемент x. * has(arr, x) - whether there is an element x in the array.
* indexOf(arr, x) - возвращает индекс элемента x (начиная с 1), если он есть в массиве, или 0, если его нет. * indexOf(arr, x) - returns the index of the element x (starting with 1), if it exists in the array, or 0 if it is not.
* arrayEnumerate(arr) - возаращает массив [1,2,3,..., length(arr)] * arrayEnumerate(arr) - Returns the array [1,2,3,..., length(arr)]
* *
* arrayUniq(arr) - считает количество разных элементов в массиве, * arrayUniq(arr) - counts the number of different elements in the array,
* arrayUniq(arr1, arr2, ...) - считает количество разных кортежей из элементов на соответствующих позициях в нескольких массивах. * arrayUniq(arr1, arr2, ...) - counts the number of different tuples from the elements in the corresponding positions in several arrays.
* *
* arrayEnumerateUniq(arr) * arrayEnumerateUniq(arr)
* - возаращает массив, параллельный данному, где для каждого элемента указано, * - outputs an array parallel (having same size) to this, where for each element specified
* какой он по счету среди элементов с таким значением. * how much times this element was encountered before (including this element) among elements with the same value.
* Например: arrayEnumerateUniq([10, 20, 10, 30]) = [1, 1, 2, 1] * For example: arrayEnumerateUniq([10, 20, 10, 30]) = [1, 1, 2, 1]
* arrayEnumerateUniq(arr1, arr2...) * arrayEnumerateUniq(arr1, arr2...)
* - для кортежей из элементов на соответствующих позициях в нескольких массивах. * - for tuples from elements in the corresponding positions in several arrays.
* *
* emptyArrayToSingle(arr) - заменить пустые массивы на массивы из одного элемента со значением "по-умолчанию". * emptyArrayToSingle(arr) - replace empty arrays with arrays of one element with a default value.
* *
* arrayReduce('agg', arr1, ...) - применить агрегатную функцию agg к массивам arr1... * arrayReduce('agg', arr1, ...) - apply the aggregate function `agg` to arrays `arr1...`
* If multiple arrays passed, then elements on corresponding positions are passed as multiple arguments to the aggregate function.
*/ */
@ -142,7 +143,7 @@ private:
template <typename IndexType> template <typename IndexType>
bool executeArgument(Block & block, const ColumnNumbers & arguments, size_t result, ArrayImpl::NullMapBuilder & builder); bool executeArgument(Block & block, const ColumnNumbers & arguments, size_t result, ArrayImpl::NullMapBuilder & builder);
/** Для массива кортежей функция вычисляется покомпонентно - для каждого элемента кортежа. /** For a tuple array, the function is evaluated component-wise for each element of the tuple.
*/ */
bool executeTuple(Block & block, const ColumnNumbers & arguments, size_t result); bool executeTuple(Block & block, const ColumnNumbers & arguments, size_t result);
}; };
@ -159,7 +160,7 @@ struct IndexToOne
struct IndexIdentity struct IndexIdentity
{ {
using ResultType = UInt64; using ResultType = UInt64;
/// Индекс возвращается начиная с единицы. /// The index is returned starting from 1.
static bool apply(size_t j, ResultType & current) { current = j + 1; return false; } static bool apply(size_t j, ResultType & current) { current = j + 1; return false; }
}; };
@ -193,7 +194,7 @@ private:
static bool hasNull(const U & value, const PaddedPODArray<UInt8> & null_map, size_t i) static bool hasNull(const U & value, const PaddedPODArray<UInt8> & null_map, size_t i)
{ {
throw Exception{"Internal error", ErrorCodes::LOGICAL_ERROR}; throw Exception{"Logical error: constant column cannot have null map.", ErrorCodes::LOGICAL_ERROR};
} }
/// Both function arguments are ordinary. /// Both function arguments are ordinary.
@ -1033,7 +1034,7 @@ public:
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override
{ {
/// If one or both arguments passed to this function are nullable, /// If one or both arguments passed to this function are nullable,
/// we create a new block that contains non-nullable parameters: /// we create a new block that contains non-nullable arguments:
/// - if the 1st argument is a non-constant array of nullable values, /// - if the 1st argument is a non-constant array of nullable values,
/// it is turned into a non-constant array of ordinary values + a null /// it is turned into a non-constant array of ordinary values + a null
/// byte map; /// byte map;
@ -1181,8 +1182,8 @@ public:
}; };
/// Считает количество разных элементов в массиве, или количество разных кортежей из элементов на соответствующих позициях в нескольких массивах. /// Counts the number of different elements in the array, or the number of different tuples from the elements at the corresponding positions in several arrays.
/// NOTE Реализация частично совпадает с arrayEnumerateUniq. /// NOTE The implementation partially matches arrayEnumerateUniq.
class FunctionArrayUniq : public IFunction class FunctionArrayUniq : public IFunction
{ {
public: public:
@ -1199,7 +1200,7 @@ public:
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override; void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override;
private: private:
/// Изначально выделить кусок памяти для 512 элементов. /// Initially allocate a piece of memory for 512 elements. NOTE: This is just a guess.
static constexpr size_t INITIAL_SIZE_DEGREE = 9; static constexpr size_t INITIAL_SIZE_DEGREE = 9;
template <typename T> template <typename T>
@ -1239,7 +1240,7 @@ public:
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override; void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override;
private: private:
/// Изначально выделить кусок памяти для 512 элементов. /// Initially allocate a piece of memory for 512 elements. NOTE: This is just a guess.
static constexpr size_t INITIAL_SIZE_DEGREE = 9; static constexpr size_t INITIAL_SIZE_DEGREE = 9;
template <typename T> template <typename T>
@ -1382,7 +1383,7 @@ class IAggregateFunction;
using AggregateFunctionPtr = std::shared_ptr<IAggregateFunction>; using AggregateFunctionPtr = std::shared_ptr<IAggregateFunction>;
/** Applies an aggregate function to array and returns its result. /** Applies an aggregate function to array and returns its result.
* If aggregate function has multiple arguments, then this function can be applied to multiple arrays with the same size. * If aggregate function has multiple arguments, then this function can be applied to multiple arrays of the same size.
*/ */
class FunctionArrayReduce : public IFunction class FunctionArrayReduce : public IFunction
{ {
@ -1406,9 +1407,9 @@ private:
}; };
struct NameHas { static constexpr auto name = "has"; }; struct NameHas { static constexpr auto name = "has"; };
struct NameIndexOf { static constexpr auto name = "indexOf"; }; struct NameIndexOf { static constexpr auto name = "indexOf"; };
struct NameCountEqual { static constexpr auto name = "countEqual"; }; struct NameCountEqual { static constexpr auto name = "countEqual"; };
using FunctionHas = FunctionArrayIndex<IndexToOne, NameHas>; using FunctionHas = FunctionArrayIndex<IndexToOne, NameHas>;
using FunctionIndexOf = FunctionArrayIndex<IndexIdentity, NameIndexOf>; using FunctionIndexOf = FunctionArrayIndex<IndexIdentity, NameIndexOf>;

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <Common/hex.h>
#include <IO/ReadBufferFromString.h> #include <IO/ReadBufferFromString.h>
#include <IO/ReadHelpers.h>
#include <IO/WriteHelpers.h> #include <IO/WriteHelpers.h>
#include <DataTypes/DataTypesNumber.h> #include <DataTypes/DataTypesNumber.h>
#include <DataTypes/DataTypeString.h> #include <DataTypes/DataTypeString.h>
@ -24,24 +24,22 @@
namespace DB namespace DB
{ {
/** Функции кодирования: /** Encoding functions:
* *
* IPv4NumToString(num) - См. ниже. * IPv4NumToString (num) - See below.
* IPv4StringToNum(string) - Преобразуют, например, '192.168.0.1' в 3232235521 и наоборот. * IPv4StringToNum(string) - Convert, for example, '192.168.0.1' to 3232235521 and vice versa.
* *
* hex(x) - Возвращает hex; буквы заглавные; префиксов 0x или суффиксов h нет. * hex(x) - Returns hex; capital letters; there are no prefixes 0x or suffixes h.
* Для чисел возвращает строку переменной длины - hex в "человеческом" (big endian) формате, с вырезанием старших нулей, но только по целым байтам. Для дат и дат-с-временем - как для чисел. * For numbers, returns a variable-length string - hex in the "human" (big endian) format, with the leading zeros being cut,
* Например, hex(257) = '0101'. * but only by whole bytes. For dates and datetimes - the same as for numbers.
* unhex(string) - Возвращает строку, hex от которой равен string с точностью до регистра и отбрасывания одного ведущего нуля. * For example, hex(257) = '0101'.
* Если такой строки не существует, оставляет за собой право вернуть любой мусор. * unhex(string) - Returns a string, hex of which is equal to `string` with regard of case and discarding one leading zero.
* If such a string does not exist, could return arbitary implementation specific value.
* *
* bitmaskToArray(x) - Возвращает массив степеней двойки в двоичной записи x. Например, bitmaskToArray(50) = [2, 16, 32]. * bitmaskToArray(x) - Returns an array of powers of two in the binary form of x. For example, bitmaskToArray(50) = [2, 16, 32].
*/ */
/// Включая нулевой символ в конце.
#define MAX_UINT_HEX_LENGTH 20
const auto ipv4_bytes_length = 4; const auto ipv4_bytes_length = 4;
const auto ipv6_bytes_length = 16; const auto ipv6_bytes_length = 16;
const auto uuid_bytes_length = 16; const auto uuid_bytes_length = 16;
@ -56,9 +54,6 @@ private:
return value >= base ? 1 + int_log(value / base, base, value % base || carry) : value % base > 1 || carry; return value >= base ? 1 + int_log(value / base, base, value % base || carry) : value % base > 1 || carry;
} }
/// mapping of digits up to base 16
static constexpr auto && digits = "0123456789abcdef";
/// print integer in desired base, faster than sprintf /// print integer in desired base, faster than sprintf
template <uint32_t base, typename T, uint32_t buffer_size = sizeof(T) * int_log(256, base, false)> template <uint32_t base, typename T, uint32_t buffer_size = sizeof(T) * int_log(256, base, false)>
static void print_integer(char *& out, T value) static void print_integer(char *& out, T value)
@ -72,7 +67,7 @@ private:
while (value > 0) while (value > 0)
{ {
*ptr++ = digits[value % base]; *ptr++ = hexLowercase(value % base);
value /= base; value /= base;
} }
@ -664,16 +659,16 @@ public:
{ {
char * begin = out; char * begin = out;
/// Запишем все задом наперед. /// Write everything backwards.
for (size_t offset = 0; offset <= 24; offset += 8) for (size_t offset = 0; offset <= 24; offset += 8)
{ {
if (offset > 0) if (offset > 0)
*(out++) = '.'; *(out++) = '.';
/// Достаем очередной байт. /// Get the next byte.
UInt32 value = (ip >> offset) & static_cast<UInt32>(255); UInt32 value = (ip >> offset) & static_cast<UInt32>(255);
/// Быстрее, чем sprintf. /// Faster than sprintf.
if (value == 0) if (value == 0)
{ {
*(out++) = '0'; *(out++) = '0';
@ -688,7 +683,7 @@ public:
} }
} }
/// И развернем. /// And reverse.
std::reverse(begin, out); std::reverse(begin, out);
*(out++) = '\0'; *(out++) = '\0';
@ -708,7 +703,7 @@ public:
ColumnString::Chars_t & vec_res = col_res->getChars(); ColumnString::Chars_t & vec_res = col_res->getChars();
ColumnString::Offsets_t & offsets_res = col_res->getOffsets(); ColumnString::Offsets_t & offsets_res = col_res->getOffsets();
vec_res.resize(vec_in.size() * INET_ADDRSTRLEN); /// самое длинное значение: 255.255.255.255\0 vec_res.resize(vec_in.size() * INET_ADDRSTRLEN); /// the longest value is: 255.255.255.255\0
offsets_res.resize(vec_in.size()); offsets_res.resize(vec_in.size());
char * begin = reinterpret_cast<char *>(&vec_res[0]); char * begin = reinterpret_cast<char *>(&vec_res[0]);
char * pos = begin; char * pos = begin;
@ -847,16 +842,16 @@ public:
for (auto i = 0; i < 3; ++i) for (auto i = 0; i < 3; ++i)
*(out++) = 'x'; *(out++) = 'x';
/// Запишем все задом наперед. /// Write everything backwards.
for (size_t offset = 8; offset <= 24; offset += 8) for (size_t offset = 8; offset <= 24; offset += 8)
{ {
if (offset > 0) if (offset > 0)
*(out++) = '.'; *(out++) = '.';
/// Достаем очередной байт. /// Get the next byte.
UInt32 value = (ip >> offset) & static_cast<UInt32>(255); UInt32 value = (ip >> offset) & static_cast<UInt32>(255);
/// Быстрее, чем sprintf. /// Faster than sprintf.
if (value == 0) if (value == 0)
{ {
*(out++) = '0'; *(out++) = '0';
@ -871,7 +866,7 @@ public:
} }
} }
/// И развернем. /// And reverse.
std::reverse(begin, out); std::reverse(begin, out);
*(out++) = '\0'; *(out++) = '\0';
@ -891,7 +886,7 @@ public:
ColumnString::Chars_t & vec_res = col_res->getChars(); ColumnString::Chars_t & vec_res = col_res->getChars();
ColumnString::Offsets_t & offsets_res = col_res->getOffsets(); ColumnString::Offsets_t & offsets_res = col_res->getOffsets();
vec_res.resize(vec_in.size() * INET_ADDRSTRLEN); /// самое длинное значение: 255.255.255.255\0 vec_res.resize(vec_in.size() * INET_ADDRSTRLEN); /// the longest value is: 255.255.255.255\0
offsets_res.resize(vec_in.size()); offsets_res.resize(vec_in.size());
char * begin = reinterpret_cast<char *>(&vec_res[0]); char * begin = reinterpret_cast<char *>(&vec_res[0]);
char * pos = begin; char * pos = begin;
@ -1012,19 +1007,16 @@ public:
{ {
char * begin = out; char * begin = out;
/// mapping of digits up to base 16 /// Write everything backwards.
static char digits[] = "0123456789ABCDEF";
/// Запишем все задом наперед.
for (size_t offset = 0; offset <= 40; offset += 8) for (size_t offset = 0; offset <= 40; offset += 8)
{ {
if (offset > 0) if (offset > 0)
*(out++) = ':'; *(out++) = ':';
/// Достаем очередной байт. /// Get the next byte.
UInt64 value = (mac >> offset) & static_cast<UInt64>(255); UInt64 value = (mac >> offset) & static_cast<UInt64>(255);
/// Быстрее, чем sprintf. /// Faster than sprintf.
if (value < 16) if (value < 16)
{ {
*(out++) = '0'; *(out++) = '0';
@ -1037,13 +1029,13 @@ public:
{ {
while (value > 0) while (value > 0)
{ {
*(out++) = digits[value % 16]; *(out++) = hexUppercase(value % 16);
value /= 16; value /= 16;
} }
} }
} }
/// И развернем. /// And reverse.
std::reverse(begin, out); std::reverse(begin, out);
*(out++) = '\0'; *(out++) = '\0';
@ -1063,7 +1055,7 @@ public:
ColumnString::Chars_t & vec_res = col_res->getChars(); ColumnString::Chars_t & vec_res = col_res->getChars();
ColumnString::Offsets_t & offsets_res = col_res->getOffsets(); ColumnString::Offsets_t & offsets_res = col_res->getOffsets();
vec_res.resize(vec_in.size() * 18); /// самое длинное значение: xx:xx:xx:xx:xx:xx\0 vec_res.resize(vec_in.size() * 18); /// the longest value is: xx:xx:xx:xx:xx:xx\0
offsets_res.resize(vec_in.size()); offsets_res.resize(vec_in.size());
char * begin = reinterpret_cast<char *>(&vec_res[0]); char * begin = reinterpret_cast<char *>(&vec_res[0]);
char * pos = begin; char * pos = begin;
@ -1595,20 +1587,19 @@ public:
template <typename T> template <typename T>
void executeOneUInt(T x, char *& out) void executeOneUInt(T x, char *& out)
{ {
const char digit[17] = "0123456789ABCDEF";
bool was_nonzero = false; bool was_nonzero = false;
for (int offset = (sizeof(T) - 1) * 8; offset >= 0; offset -= 8) for (int offset = (sizeof(T) - 1) * 8; offset >= 0; offset -= 8)
{ {
UInt8 byte = static_cast<UInt8>((x >> offset) & 255); UInt8 byte = static_cast<UInt8>((x >> offset) & 255);
/// Ведущие нули. /// Leading zeros.
if (byte == 0 && !was_nonzero && offset) if (byte == 0 && !was_nonzero && offset)
continue; continue;
was_nonzero = true; was_nonzero = true;
*(out++) = digit[byte >> 4]; *(out++) = hexUppercase(byte / 16);
*(out++) = digit[byte & 15]; *(out++) = hexUppercase(byte % 16);
} }
*(out++) = '\0'; *(out++) = '\0';
} }
@ -1619,6 +1610,8 @@ public:
const ColumnVector<T> * col_vec = typeid_cast<const ColumnVector<T> *>(col); const ColumnVector<T> * col_vec = typeid_cast<const ColumnVector<T> *>(col);
const ColumnConst<T> * col_const = typeid_cast<const ColumnConst<T> *>(col); const ColumnConst<T> * col_const = typeid_cast<const ColumnConst<T> *>(col);
static constexpr size_t MAX_UINT_HEX_LENGTH = sizeof(T) * 2 + 1; /// Including trailing zero byte.
if (col_vec) if (col_vec)
{ {
auto col_str = std::make_shared<ColumnString>(); auto col_str = std::make_shared<ColumnString>();
@ -1630,12 +1623,12 @@ public:
size_t size = in_vec.size(); size_t size = in_vec.size();
out_offsets.resize(size); out_offsets.resize(size);
out_vec.resize(size * 3 + MAX_UINT_HEX_LENGTH); out_vec.resize(size * 3 + MAX_UINT_HEX_LENGTH); /// 3 is length of one byte in hex plus zero byte.
size_t pos = 0; size_t pos = 0;
for (size_t i = 0; i < size; ++i) for (size_t i = 0; i < size; ++i)
{ {
/// Ручной экспоненциальный рост, чтобы не полагаться на линейное амортизированное время работы resize (его никто не гарантирует). /// Manual exponential growth, so as not to rely on the linear amortized work time of `resize` (no one guarantees it).
if (pos + MAX_UINT_HEX_LENGTH > out_vec.size()) if (pos + MAX_UINT_HEX_LENGTH > out_vec.size())
out_vec.resize(out_vec.size() * 2 + MAX_UINT_HEX_LENGTH); out_vec.resize(out_vec.size() * 2 + MAX_UINT_HEX_LENGTH);
@ -1669,12 +1662,11 @@ public:
void executeOneString(const UInt8 * pos, const UInt8 * end, char *& out) void executeOneString(const UInt8 * pos, const UInt8 * end, char *& out)
{ {
const char digit[17] = "0123456789ABCDEF";
while (pos < end) while (pos < end)
{ {
UInt8 byte = *(pos++); UInt8 byte = *(pos++);
*(out++) = digit[byte >> 4]; *(out++) = hexUppercase(byte / 16);
*(out++) = digit[byte & 15]; *(out++) = hexUppercase(byte % 16);
} }
*(out++) = '\0'; *(out++) = '\0';
} }
@ -1718,13 +1710,13 @@ public:
return true; return true;
} }
else if(col_const_in) else if (col_const_in)
{ {
const std::string & src = col_const_in->getData(); const std::string & src = col_const_in->getData();
std::string res(src.size() * 2, '\0'); std::string res(src.size() * 2, '\0');
char * pos = &res[0]; char * pos = &res[0];
const UInt8 * src_ptr = reinterpret_cast<const UInt8 *>(src.c_str()); const UInt8 * src_ptr = reinterpret_cast<const UInt8 *>(src.c_str());
/// Запишем ноль в res[res.size()]. Начиная с C++11, это корректно. /// Let's write zero into res[res.size()]. Starting with C++ 11, this is correct.
executeOneString(src_ptr, src_ptr + src.size(), pos); executeOneString(src_ptr, src_ptr + src.size(), pos);
col_res = std::make_shared<ColumnConstString>(col_const_in->size(), res); col_res = std::make_shared<ColumnConstString>(col_const_in->size(), res);
@ -1828,28 +1820,26 @@ public:
return std::make_shared<DataTypeString>(); return std::make_shared<DataTypeString>();
} }
UInt8 undigitUnsafe(char c)
{
if (c <= '9')
return c - '0';
if (c <= 'Z')
return c - ('A' - 10);
return c - ('a' - 10);
}
void unhexOne(const char * pos, const char * end, char *& out) void unhexOne(const char * pos, const char * end, char *& out)
{ {
if ((end - pos) & 1) if ((end - pos) & 1)
{ {
*(out++) = undigitUnsafe(*(pos++)); *out = unhex(*pos);
++out;
++pos;
} }
while (pos < end) while (pos < end)
{ {
UInt8 major = undigitUnsafe(*(pos++)); UInt8 major = unhex(*pos);
UInt8 minor = undigitUnsafe(*(pos++)); ++pos;
*(out++) = (major << 4) | minor; UInt8 minor = unhex(*pos);
++pos;
*out = (major << 4) | minor;
++out;
} }
*(out++) = '\0'; *out = '\0';
++out;
} }
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override

View File

@ -29,20 +29,20 @@
namespace DB namespace DB
{ {
/** Функции сравнения: ==, !=, <, >, <=, >=. /** Comparison functions: ==, !=, <, >, <=, >=.
* Функции сравнения возвращают всегда 0 или 1 (UInt8). * The comparison functions always return 0 or 1 (UInt8).
* *
* Сравнивать можно следующие типы: * You can compare the following types:
* - числа; * - numbers;
* - строки и фиксированные строки; * - strings and fixed strings;
* - даты; * - dates;
* - даты-с-временем; * - datetimes;
* внутри каждой группы, но не из разных групп; * within each group, but not from different groups;
* - кортежи (сравнение лексикографическое). * - tuples (lexicographic comparison).
* *
* Исключение: можно сравнивать дату и дату-с-временем с константной строкой. Пример: EventDate = '2015-01-01'. * Exception: You can compare the date and datetime with a constant string. Example: EventDate = '2015-01-01'.
* *
* TODO Массивы. * TODO Arrays.
*/ */
template <typename A, typename B> struct EqualsOp template <typename A, typename B> struct EqualsOp
@ -94,9 +94,9 @@ struct NumComparisonImpl
/// If you don't specify NO_INLINE, the compiler will inline this function, but we don't need this as this function contains tight loop inside. /// If you don't specify NO_INLINE, the compiler will inline this function, but we don't need this as this function contains tight loop inside.
static void NO_INLINE vector_vector(const PaddedPODArray<A> & a, const PaddedPODArray<B> & b, PaddedPODArray<UInt8> & c) static void NO_INLINE vector_vector(const PaddedPODArray<A> & a, const PaddedPODArray<B> & b, PaddedPODArray<UInt8> & c)
{ {
/** GCC 4.8.2 векторизует цикл только если его записать в такой форме. /** GCC 4.8.2 vectorizes a loop only if it is written in this form.
* В данном случае, если сделать цикл по индексу массива (код будет выглядеть проще), * In this case, if you loop through the array index (the code will look simpler),
* цикл не будет векторизовываться. * the loop will not be vectorized.
*/ */
size_t size = a.size(); size_t size = a.size();
@ -178,7 +178,7 @@ struct StringComparisonImpl
{ {
if (i == 0) if (i == 0)
{ {
/// Завершающий ноль в меньшей по длине строке входит в сравнение. /// The trailing zero in the smaller string is included in the comparison.
c[i] = Op::apply(memcmp(&a_data[0], &b_data[0], std::min(a_offsets[0], b_offsets[0])), 0); c[i] = Op::apply(memcmp(&a_data[0], &b_data[0], std::min(a_offsets[0], b_offsets[0])), 0);
} }
else else
@ -742,7 +742,7 @@ private:
Block & block, size_t result, const IColumn * col_left_untyped, const IColumn * col_right_untyped, Block & block, size_t result, const IColumn * col_left_untyped, const IColumn * col_right_untyped,
const DataTypePtr & left_type, const DataTypePtr & right_type, bool left_is_num, bool right_is_num) const DataTypePtr & left_type, const DataTypePtr & right_type, bool left_is_num, bool right_is_num)
{ {
/// Уже не такой и особый случай - сравнение дат, дат-с-временем и перечислений со строковой константой. /// This is no longer very special case - comparing dates, datetimes, and enumerations with a string constant.
const IColumn * column_string_untyped = !left_is_num ? col_left_untyped : col_right_untyped; const IColumn * column_string_untyped = !left_is_num ? col_left_untyped : col_right_untyped;
const IColumn * column_number = left_is_num ? col_left_untyped : col_right_untyped; const IColumn * column_number = left_is_num ? col_left_untyped : col_right_untyped;
const IDataType * number_type = left_is_num ? left_type.get() : right_type.get(); const IDataType * number_type = left_is_num ? left_type.get() : right_type.get();
@ -817,7 +817,7 @@ private:
void executeTuple(Block & block, size_t result, const IColumn * c0, const IColumn * c1) void executeTuple(Block & block, size_t result, const IColumn * c0, const IColumn * c1)
{ {
/** Сравнивать кортежи будем лексикографически. Это делается следующим образом: /** We will lexicographically compare the tuples. This is done as follows:
* x == y : x1 == y1 && x2 == y2 ... * x == y : x1 == y1 && x2 == y2 ...
* x != y : x1 != y1 || x2 != y2 ... * x != y : x1 != y1 || x2 != y2 ...
* *
@ -825,7 +825,7 @@ private:
* x > y: x1 > y1 || (x1 == y1 && (x2 > y2 || (x2 == y2 ... && xn > yn)) * x > y: x1 > y1 || (x1 == y1 && (x2 > y2 || (x2 == y2 ... && xn > yn))
* x <= y: x1 < y1 || (x1 == y1 && (x2 < y2 || (x2 == y2 ... && xn <= yn)) * x <= y: x1 < y1 || (x1 == y1 && (x2 < y2 || (x2 == y2 ... && xn <= yn))
* *
* Рекурсивная запись: * Recursive record:
* x <= y: x1 < y1 || (x1 == y1 && x_tail <= y_tail) * x <= y: x1 < y1 || (x1 == y1 && x_tail <= y_tail)
* *
* x >= y: x1 > y1 || (x1 == y1 && (x2 > y2 || (x2 == y2 ... && xn >= yn)) * x >= y: x1 > y1 || (x1 == y1 && (x2 > y2 || (x2 == y2 ... && xn >= yn))
@ -874,12 +874,12 @@ private:
tmp_block.insert(x->getData().safeGetByPosition(i)); tmp_block.insert(x->getData().safeGetByPosition(i));
tmp_block.insert(y->getData().safeGetByPosition(i)); tmp_block.insert(y->getData().safeGetByPosition(i));
/// Сравнение элементов. /// Comparison of the elements.
tmp_block.insert({ nullptr, std::make_shared<DataTypeUInt8>(), "" }); tmp_block.insert({ nullptr, std::make_shared<DataTypeUInt8>(), "" });
func_compare.execute(tmp_block, {i * 3, i * 3 + 1}, i * 3 + 2); func_compare.execute(tmp_block, {i * 3, i * 3 + 1}, i * 3 + 2);
} }
/// Логическая свёртка. /// Logical convolution.
tmp_block.insert({ nullptr, std::make_shared<DataTypeUInt8>(), "" }); tmp_block.insert({ nullptr, std::make_shared<DataTypeUInt8>(), "" });
ColumnNumbers convolution_args(tuple_size); ColumnNumbers convolution_args(tuple_size);
@ -901,7 +901,7 @@ private:
Block tmp_block; Block tmp_block;
/// Попарное сравнение на неравенство всех элементов; на равенство всех элементов кроме последнего. /// Pairwise comparison of the inequality of all elements; on the equality of all elements except the last.
for (size_t i = 0; i < tuple_size; ++i) for (size_t i = 0; i < tuple_size; ++i)
{ {
tmp_block.insert(x->getData().safeGetByPosition(i)); tmp_block.insert(x->getData().safeGetByPosition(i));
@ -921,7 +921,7 @@ private:
func_compare_tail.execute(tmp_block, {i * 4, i * 4 + 1}, i * 4 + 2); func_compare_tail.execute(tmp_block, {i * 4, i * 4 + 1}, i * 4 + 2);
} }
/// Комбинирование. Сложный код - сделайте рисунок. Можно заменить на рекурсивное сравнение кортежей. /// Combination. Complex code - make a drawing. It can be replaced by a recursive comparison of tuples.
size_t i = tuple_size - 1; size_t i = tuple_size - 1;
while (i > 0) while (i > 0)
{ {
@ -970,7 +970,7 @@ public:
size_t getNumberOfArguments() const override { return 2; } size_t getNumberOfArguments() const override { return 2; }
/// Получить типы результата по типам аргументов. Если функция неприменима для данных аргументов - кинуть исключение. /// Get result types by argument types. If the function does not apply to these arguments, throw an exception.
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
{ {
bool left_is_date = false; bool left_is_date = false;
@ -1001,32 +1001,32 @@ public:
const DataTypeTuple * right_tuple = nullptr; const DataTypeTuple * right_tuple = nullptr;
false false
|| (right_is_date = typeid_cast<const DataTypeDate *>(arguments[1].get())) || (right_is_date = typeid_cast<const DataTypeDate *>(arguments[1].get()))
|| (right_is_date_time = typeid_cast<const DataTypeDateTime *>(arguments[1].get())) || (right_is_date_time = typeid_cast<const DataTypeDateTime *>(arguments[1].get()))
|| (right_is_enum8 = typeid_cast<const DataTypeEnum8 *>(arguments[1].get())) || (right_is_enum8 = typeid_cast<const DataTypeEnum8 *>(arguments[1].get()))
|| (right_is_enum16 = typeid_cast<const DataTypeEnum16 *>(arguments[1].get())) || (right_is_enum16 = typeid_cast<const DataTypeEnum16 *>(arguments[1].get()))
|| (right_is_string = typeid_cast<const DataTypeString *>(arguments[1].get())) || (right_is_string = typeid_cast<const DataTypeString *>(arguments[1].get()))
|| (right_is_fixed_string = typeid_cast<const DataTypeFixedString *>(arguments[1].get())) || (right_is_fixed_string = typeid_cast<const DataTypeFixedString *>(arguments[1].get()))
|| (right_tuple = typeid_cast<const DataTypeTuple *>(arguments[1].get())); || (right_tuple = typeid_cast<const DataTypeTuple *>(arguments[1].get()));
const bool right_is_enum = right_is_enum8 || right_is_enum16; const bool right_is_enum = right_is_enum8 || right_is_enum16;
if (!( (arguments[0]->behavesAsNumber() && arguments[1]->behavesAsNumber() && !(left_is_enum ^ right_is_enum)) if (!((arguments[0]->behavesAsNumber() && arguments[1]->behavesAsNumber() && !(left_is_enum ^ right_is_enum))
|| ((left_is_string || left_is_fixed_string) && (right_is_string || right_is_fixed_string)) || ((left_is_string || left_is_fixed_string) && (right_is_string || right_is_fixed_string))
|| (left_is_date && right_is_date) || (left_is_date && right_is_date)
|| (left_is_date && right_is_string) /// Можно сравнивать дату, дату-с-временем и перечисление с константной строкой. || (left_is_date && right_is_string) /// You can compare the date, datetime and an enumeration with a constant string.
|| (left_is_string && right_is_date) || (left_is_string && right_is_date)
|| (left_is_date_time && right_is_date_time) || (left_is_date_time && right_is_date_time)
|| (left_is_date_time && right_is_string) || (left_is_date_time && right_is_string)
|| (left_is_string && right_is_date_time) || (left_is_string && right_is_date_time)
|| (left_is_date_time && right_is_date_time) || (left_is_date_time && right_is_date_time)
|| (left_is_date_time && right_is_string) || (left_is_date_time && right_is_string)
|| (left_is_string && right_is_date_time) || (left_is_string && right_is_date_time)
|| (left_is_enum && right_is_enum && arguments[0]->getName() == arguments[1]->getName()) /// only equivalent enum type values can be compared against || (left_is_enum && right_is_enum && arguments[0]->getName() == arguments[1]->getName()) /// only equivalent enum type values can be compared against
|| (left_is_enum && right_is_string) || (left_is_enum && right_is_string)
|| (left_is_string && right_is_enum) || (left_is_string && right_is_enum)
|| (left_tuple && right_tuple && left_tuple->getElements().size() == right_tuple->getElements().size()) || (left_tuple && right_tuple && left_tuple->getElements().size() == right_tuple->getElements().size())
|| (arguments[0]->equals(*arguments[1])))) || (arguments[0]->equals(*arguments[1]))))
throw Exception("Illegal types of arguments (" + arguments[0]->getName() + ", " + arguments[1]->getName() + ")" throw Exception("Illegal types of arguments (" + arguments[0]->getName() + ", " + arguments[1]->getName() + ")"
" of function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); " of function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
@ -1052,16 +1052,16 @@ public:
if (left_is_num && right_is_num) if (left_is_num && right_is_num)
{ {
if (!( executeNumLeftType<UInt8>(block, result, col_left_untyped, col_right_untyped) if (!( executeNumLeftType<UInt8>(block, result, col_left_untyped, col_right_untyped)
|| executeNumLeftType<UInt16>(block, result, col_left_untyped, col_right_untyped) || executeNumLeftType<UInt16>(block, result, col_left_untyped, col_right_untyped)
|| executeNumLeftType<UInt32>(block, result, col_left_untyped, col_right_untyped) || executeNumLeftType<UInt32>(block, result, col_left_untyped, col_right_untyped)
|| executeNumLeftType<UInt64>(block, result, col_left_untyped, col_right_untyped) || executeNumLeftType<UInt64>(block, result, col_left_untyped, col_right_untyped)
|| executeNumLeftType<Int8>(block, result, col_left_untyped, col_right_untyped) || executeNumLeftType<Int8>(block, result, col_left_untyped, col_right_untyped)
|| executeNumLeftType<Int16>(block, result, col_left_untyped, col_right_untyped) || executeNumLeftType<Int16>(block, result, col_left_untyped, col_right_untyped)
|| executeNumLeftType<Int32>(block, result, col_left_untyped, col_right_untyped) || executeNumLeftType<Int32>(block, result, col_left_untyped, col_right_untyped)
|| executeNumLeftType<Int64>(block, result, col_left_untyped, col_right_untyped) || executeNumLeftType<Int64>(block, result, col_left_untyped, col_right_untyped)
|| executeNumLeftType<Float32>(block, result, col_left_untyped, col_right_untyped) || executeNumLeftType<Float32>(block, result, col_left_untyped, col_right_untyped)
|| executeNumLeftType<Float64>(block, result, col_left_untyped, col_right_untyped))) || executeNumLeftType<Float64>(block, result, col_left_untyped, col_right_untyped)))
throw Exception("Illegal column " + col_left_untyped->getName() throw Exception("Illegal column " + col_left_untyped->getName()
+ " of first argument of function " + getName(), + " of first argument of function " + getName(),
ErrorCodes::ILLEGAL_COLUMN); ErrorCodes::ILLEGAL_COLUMN);
@ -1077,15 +1077,15 @@ public:
block, result, col_left_untyped, col_right_untyped, block, result, col_left_untyped, col_right_untyped,
col_with_type_and_name_left.type, col_with_type_and_name_right.type, col_with_type_and_name_left.type, col_with_type_and_name_right.type,
left_is_num, right_is_num); left_is_num, right_is_num);
} }
}; };
using FunctionEquals = FunctionComparison<EqualsOp, NameEquals> ; using FunctionEquals = FunctionComparison<EqualsOp, NameEquals>;
using FunctionNotEquals = FunctionComparison<NotEqualsOp, NameNotEquals> ; using FunctionNotEquals = FunctionComparison<NotEqualsOp, NameNotEquals>;
using FunctionLess = FunctionComparison<LessOp, NameLess> ; using FunctionLess = FunctionComparison<LessOp, NameLess>;
using FunctionGreater = FunctionComparison<GreaterOp, NameGreater> ; using FunctionGreater = FunctionComparison<GreaterOp, NameGreater>;
using FunctionLessOrEquals = FunctionComparison<LessOrEqualsOp, NameLessOrEquals> ; using FunctionLessOrEquals = FunctionComparison<LessOrEqualsOp, NameLessOrEquals>;
using FunctionGreaterOrEquals = FunctionComparison<GreaterOrEqualsOp, NameGreaterOrEquals>; using FunctionGreaterOrEquals = FunctionComparison<GreaterOrEqualsOp, NameGreaterOrEquals>;
} }

View File

@ -19,9 +19,9 @@
namespace DB namespace DB
{ {
/** Функция выбора по условию: if(cond, then, else). /** Selection function by condition: if(cond, then, else).
* cond - UInt8 * cond - UInt8
* then, else - числовые типы, для которых есть общий тип, либо даты, даты-с-временем, либо строки, либо массивы таких типов. * then, else - numeric types for which there is a general type, or dates, datetimes, or strings, or arrays of these types.
*/ */
@ -610,9 +610,9 @@ public:
}; };
/** Реализация для массивов строк. /** Implementation for string arrays.
* NOTE: Код слишком сложный, потому что он работает в внутренностями массивов строк. * NOTE: The code is too complex because it works with the internals of the arrays of strings.
* NOTE: Массивы из FixedString не поддерживаются. * NOTE: Arrays of FixedString are not supported.
*/ */
struct StringArrayIfImpl struct StringArrayIfImpl
{ {
@ -666,7 +666,7 @@ struct StringArrayIfImpl
for (size_t j = 0; j < array_size; ++j) for (size_t j = 0; j < array_size; ++j)
{ {
const String & str = from_data[j].get<const String &>(); const String & str = from_data[j].get<const String &>();
size_t string_size = str.size() + 1; /// Включая 0 на конце. size_t string_size = str.size() + 1; /// Including 0 at the end.
to_data.resize(to_string_prev_offset + string_size); to_data.resize(to_string_prev_offset + string_size);
memcpy(&to_data[to_string_prev_offset], str.data(), string_size); memcpy(&to_data[to_string_prev_offset], str.data(), string_size);
@ -1121,7 +1121,7 @@ private:
{ {
if (col_then_fixed && col_else_fixed) if (col_then_fixed && col_else_fixed)
{ {
/// Результат - FixedString. /// The result is FixedString.
if (col_then_fixed->getN() != col_else_fixed->getN()) if (col_then_fixed->getN() != col_else_fixed->getN())
throw Exception("FixedString columns as 'then' and 'else' arguments of function 'if' has different sizes", ErrorCodes::ILLEGAL_COLUMN); throw Exception("FixedString columns as 'then' and 'else' arguments of function 'if' has different sizes", ErrorCodes::ILLEGAL_COLUMN);
@ -1142,7 +1142,7 @@ private:
} }
else else
{ {
/// Результат - String. /// The result is String.
std::shared_ptr<ColumnString> col_res = std::make_shared<ColumnString>(); std::shared_ptr<ColumnString> col_res = std::make_shared<ColumnString>();
block.safeGetByPosition(result).column = col_res; block.safeGetByPosition(result).column = col_res;
@ -1582,7 +1582,7 @@ public:
bool hasSpecialSupportForNulls() const override { return true; } bool hasSpecialSupportForNulls() const override { return true; }
/// Получить типы результата по типам аргументов. Если функция неприменима для данных аргументов - кинуть исключение. /// Get result types by argument types. If the function does not apply to these arguments, throw an exception.
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
{ {
bool cond_is_null = arguments[0]->isNull(); bool cond_is_null = arguments[0]->isNull();
@ -1640,7 +1640,7 @@ public:
} }
else if (type_arr1 && type_arr2) else if (type_arr1 && type_arr2)
{ {
/// NOTE Сообщения об ошибках будут относится к типам элементов массивов, что немного некорректно. /// NOTE Error messages will refer to the types of array elements, which is slightly incorrect.
return std::make_shared<DataTypeArray>(getReturnTypeImpl({arguments[0], type_arr1->getNestedType(), type_arr2->getNestedType()})); return std::make_shared<DataTypeArray>(getReturnTypeImpl({arguments[0], type_arr1->getNestedType(), type_arr2->getNestedType()}));
} }
else if (type_tuple1 && type_tuple2) else if (type_tuple1 && type_tuple2)

View File

@ -23,7 +23,7 @@
namespace DB namespace DB
{ {
/** Функции работы с датой и временем. /** Functions for working with date and time.
* *
* toYear, toMonth, toDayOfMonth, toDayOfWeek, toHour, toMinute, toSecond, * toYear, toMonth, toDayOfMonth, toDayOfWeek, toHour, toMinute, toSecond,
* toMonday, toStartOfMonth, toStartOfYear, toStartOfMinute, toStartOfFiveMinute * toMonday, toStartOfMonth, toStartOfYear, toStartOfMinute, toStartOfFiveMinute
@ -31,43 +31,43 @@ namespace DB
* now * now
* TODO: makeDate, makeDateTime * TODO: makeDate, makeDateTime
* *
* (toDate - расположена в файле FunctionsConversion.h) * (toDate - located in FunctionConversion.h file)
* *
* Возвращаемые типы: * Return types:
* toYear -> UInt16 * toYear -> UInt16
* toMonth, toDayOfMonth, toDayOfWeek, toHour, toMinute, toSecond -> UInt8 * toMonth, toDayOfMonth, toDayOfWeek, toHour, toMinute, toSecond -> UInt8
* toMonday, toStartOfMonth, toStartOfYear -> Date * toMonday, toStartOfMonth, toStartOfYear -> Date
* toStartOfMinute, toStartOfHour, toTime, now -> DateTime * toStartOfMinute, toStartOfHour, toTime, now -> DateTime
* *
* А также: * And also:
* *
* timeSlot(EventTime) * timeSlot(EventTime)
* - округляет время до получаса. * - rounds the time to half an hour.
* *
* timeSlots(StartTime, Duration) * timeSlots(StartTime, Duration)
* - для интервала времени, начинающегося в StartTime и продолжающегося Duration секунд, * - for the time interval beginning at `StartTime` and continuing `Duration` seconds,
* возвращает массив моментов времени, состоящий из округлений вниз до получаса точек из этого интервала. * returns an array of time points, consisting of rounding down to half an hour of points from this interval.
* Например, timeSlots(toDateTime('2012-01-01 12:20:00'), 600) = [toDateTime('2012-01-01 12:00:00'), toDateTime('2012-01-01 12:30:00')]. * For example, timeSlots(toDateTime('2012-01-01 12:20:00'), 600) = [toDateTime('2012-01-01 12:00:00'), toDateTime('2012-01-01 12:30:00')].
* Это нужно для поиска хитов, входящих в соответствующий визит. * This is necessary to search for hits that are part of the corresponding visit.
*/ */
#define TIME_SLOT_SIZE 1800 #define TIME_SLOT_SIZE 1800
/** Всевозможные преобразования. /** Extra transformations.
* Представляют собой две функции - от даты-с-временем (UInt32) и от даты (UInt16). * Represents two functions - from datetime (UInt32) and from date (UInt16).
* *
* Также для преобразования T определяется "фактор-преобразование" F. * Also, the "factor transformation" F is defined for the T transformation.
* Это такое преобразование F, что его значение идентифицирует область монотонности T * This is a transformation of F such that its value identifies the region of monotonicity T
* (при фиксированном значении F, преобразование T является монотонным). * (for a fixed value of F, the transformation T is monotonic).
* *
* Или, образно, если T аналогично взятию остатка от деления, то F аналогично делению. * Or, figuratively, if T is similar to taking the remainder of division, then F is similar to division.
* *
* Пример: для преобразования T "получить номер дня в месяце" (2015-02-03 -> 3), * Example: to convert T "get the day number in the month" (2015-02-03 -> 3),
* фактор-преобразованием F является "округлить до месяца" (2015-02-03 -> 2015-02-01). * factor-transformation F is "round to the nearest month" (2015-02-03 -> 2015-02-01).
*/ */
/// Это фактор-преобразование будет говорить, что функция монотонна всюду. /// This factor transformation will say that the function is monotone everywhere.
struct ZeroTransform struct ZeroTransform
{ {
static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone) { return 0; } static inline UInt16 execute(UInt32 t, const DateLUTImpl & time_zone) { return 0; }
@ -161,7 +161,7 @@ struct ToStartOfYearImpl
struct ToTimeImpl struct ToTimeImpl
{ {
/// При переводе во время, дату будем приравнивать к 1970-01-02. /// When transforming to time, the date will be equated to 1970-01-02.
static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone) static inline UInt32 execute(UInt32 t, const DateLUTImpl & time_zone)
{ {
return time_zone.toTime(t) + 86400; return time_zone.toTime(t) + 86400;
@ -554,13 +554,13 @@ public:
if (std::is_same<typename Transform::FactorTransform, ZeroTransform>::value) if (std::is_same<typename Transform::FactorTransform, ZeroTransform>::value)
return is_monotonic; return is_monotonic;
/// Этот метод вызывается только если у функции один аргумент. Поэтому, нас пока не волнует не-локальная тайм-зона. /// This method is called only if the function has one argument. Therefore, we do not care about the non-local time zone.
const DateLUTImpl & date_lut = DateLUT::instance(); const DateLUTImpl & date_lut = DateLUT::instance();
if (left.isNull() || right.isNull()) if (left.isNull() || right.isNull())
return is_not_monotonic; return is_not_monotonic;
/// Функция монотонна на отрезке [left, right], если фактор-преобразование возвращает для них одинаковые значения. /// The function is monotonous on the [left, right] segment, if the factor transformation returns the same values for them.
if (typeid_cast<const DataTypeDate *>(&type)) if (typeid_cast<const DataTypeDate *>(&type))
{ {
@ -578,7 +578,7 @@ public:
}; };
/// Получить текущее время. (Оно - константа, вычисляется один раз за весь запрос.) /// Get the current time. (It is a constant, it is evaluated once for the entire query.)
class FunctionNow : public IFunction class FunctionNow : public IFunction
{ {
public: public:

View File

@ -31,21 +31,21 @@
namespace DB namespace DB
{ {
/** Функции хэширования. /** Hashing functions.
* *
* Половинка MD5: * Half MD5:
* halfMD5: String -> UInt64 * halfMD5: String -> UInt64
* *
* Более быстрая криптографическая хэш-функция: * A faster cryptographic hash function:
* sipHash64: String -> UInt64 * sipHash64: String -> UInt64
* *
* Быстрая некриптографическая хэш функция для строк: * Fast non-cryptographic hash function for strings:
* cityHash64: String -> UInt64 * cityHash64: String -> UInt64
* *
* Некриптографический хеш от кортежа значений любых типов (использует cityHash64 для строк и intHash64 для чисел): * A non-cryptographic hash from a tuple of values of any types (uses cityHash64 for strings and intHash64 for numbers):
* cityHash64: any* -> UInt64 * cityHash64: any* -> UInt64
* *
* Быстрая некриптографическая хэш функция от любого целого числа: * Fast non-cryptographic hash function from any integer:
* intHash32: number -> UInt32 * intHash32: number -> UInt32
* intHash64: number -> UInt64 * intHash64: number -> UInt64
* *
@ -66,7 +66,7 @@ struct HalfMD5Impl
MD5_Update(&ctx, reinterpret_cast<const unsigned char *>(begin), size); MD5_Update(&ctx, reinterpret_cast<const unsigned char *>(begin), size);
MD5_Final(buf.char_data, &ctx); MD5_Final(buf.char_data, &ctx);
return Poco::ByteOrder::flipBytes(buf.uint64_data); /// Совместимость с существующим кодом. return Poco::ByteOrder::flipBytes(buf.uint64_data); /// Compatibility with existing code.
} }
}; };
@ -151,7 +151,7 @@ struct IntHash32Impl
static UInt32 apply(UInt64 x) static UInt32 apply(UInt64 x)
{ {
/// seed взят из /dev/urandom. Он позволяет избежать нежелательных зависимостей с хэшами в разных структурах данных. /// seed is taken from /dev/urandom. It allows you to avoid undesirable dependencies with hashes in different data structures.
return intHash32<0x75D9543DE018BF45ULL>(x); return intHash32<0x75D9543DE018BF45ULL>(x);
} }
}; };
@ -371,8 +371,8 @@ template <>
UInt64 toInteger<Float64>(Float64 x); UInt64 toInteger<Float64>(Float64 x);
/** Используются хэш-функции под названием CityHash, FarmHash, MetroHash. /** We use hash functions called CityHash, FarmHash, MetroHash.
* В связи с этим, этот шаблон назван со словами NeighbourhoodHash. * In this regard, this template is named with the words `NeighborhoodHash`.
*/ */
template <typename Impl> template <typename Impl>
class FunctionNeighbourhoodHash64 : public IFunction class FunctionNeighbourhoodHash64 : public IFunction
@ -507,7 +507,7 @@ private:
} }
else if (const ColumnConstArray * col_from = typeid_cast<const ColumnConstArray *>(column)) else if (const ColumnConstArray * col_from = typeid_cast<const ColumnConstArray *>(column))
{ {
/// NOTE: тут, конечно, можно обойтись без материалиации столбца. /// NOTE: here, of course, you can do without the materialization of the column.
ColumnPtr full_column = col_from->convertToFullColumn(); ColumnPtr full_column = col_from->convertToFullColumn();
executeArray<first>(type, &*full_column, vec_to); executeArray<first>(type, &*full_column, vec_to);
} }
@ -644,15 +644,15 @@ struct URLHierarchyHashImpl
{ {
auto pos = begin; auto pos = begin;
/// Распарсим всё, что идёт до пути /// Let's parse everything that goes before the path
/// Предположим, что протокол уже переведён в нижний регистр. /// Suppose that the protocol has already been changed to lowercase.
while (pos < end && ((*pos > 'a' && *pos < 'z') || (*pos > '0' && *pos < '9'))) while (pos < end && ((*pos > 'a' && *pos < 'z') || (*pos > '0' && *pos < '9')))
++pos; ++pos;
/** Будем вычислять иерархию только для URL-ов, в которых есть протокол, и после него идут два слеша. /** We will calculate the hierarchy only for URLs in which there is a protocol, and after it there are two slashes.
* (http, file - подходят, mailto, magnet - не подходят), и после двух слешей ещё хоть что-нибудь есть * (http, file - fit, mailto, magnet - do not fit), and after two slashes there is still something
* Для остальных просто вернём полный URL как единственный элемент иерархии. * For the rest, simply return the full URL as the only element of the hierarchy.
*/ */
if (pos == begin || pos == end || !(*pos++ == ':' && pos < end && *pos++ == '/' && pos < end && *pos++ == '/' && pos < end)) if (pos == begin || pos == end || !(*pos++ == ':' && pos < end && *pos++ == '/' && pos < end && *pos++ == '/' && pos < end))
{ {
@ -660,7 +660,7 @@ struct URLHierarchyHashImpl
return 0 == level ? pos - begin : 0; return 0 == level ? pos - begin : 0;
} }
/// Доменом для простоты будем считать всё, что после протокола и двух слешей, до следующего слеша или до ? или до # /// The domain for simplicity is everything that after the protocol and the two slashes, until the next slash or before `?` or `#`
while (pos < end && !(*pos == '/' || *pos == '?' || *pos == '#')) while (pos < end && !(*pos == '/' || *pos == '?' || *pos == '#'))
++pos; ++pos;
@ -674,7 +674,7 @@ struct URLHierarchyHashImpl
while (current_level != level && pos < end) while (current_level != level && pos < end)
{ {
/// Идём до следующего / или ? или #, пропуская все те, что вначале. /// We go to the next `/` or `?` or `#`, skipping all at the beginning.
while (pos < end && (*pos == '/' || *pos == '?' || *pos == '#')) while (pos < end && (*pos == '/' || *pos == '?' || *pos == '#'))
++pos; ++pos;
if (pos == end) if (pos == end)

View File

@ -20,24 +20,24 @@ namespace ErrorCodes
extern const int SIZES_OF_ARRAYS_DOESNT_MATCH; extern const int SIZES_OF_ARRAYS_DOESNT_MATCH;
} }
/** Функции высшего порядка для массивов: /** Higher-order functions for arrays:
* *
* arrayMap(x1,...,xn -> expression, array1,...,arrayn) - применить выражение к каждому элементу массива (или набора параллельных массивов). * arrayMap(x1,...,xn -> expression, array1,...,arrayn) - apply the expression to each element of the array (or set of parallel arrays).
* arrayFilter(x -> predicate, array) - оставить в массиве только элементы, для которых выражение истинно. * arrayFilter(x -> predicate, array) - leave in the array only the elements for which the expression is true.
* arrayCount(x1,...,xn -> expression, array1,...,arrayn) - для скольки элементов массива выражение истинно. * arrayCount(x1,...,xn -> expression, array1,...,arrayn) - for how many elements of the array the expression is true.
* arrayExists(x1,...,xn -> expression, array1,...,arrayn) - истинно ли выражение для хотя бы одного элемента массива. * arrayExists(x1,...,xn -> expression, array1,...,arrayn) - is the expression true for at least one array element.
* arrayAll(x1,...,xn -> expression, array1,...,arrayn) - истинно ли выражение для всех элементов массива. * arrayAll(x1,...,xn -> expression, array1,...,arrayn) - is the expression true for all elements of the array.
* *
* Для функций arrayCount, arrayExists, arrayAll доступна еще перегрузка вида f(array), которая работает так же, как f(x -> x, array). * For functions arrayCount, arrayExists, arrayAll, an overload of the form f(array) is available, which works in the same way as f(x -> x, array).
*/ */
struct ArrayMapImpl struct ArrayMapImpl
{ {
/// true, если выражение (для перегрузки f(expression, arrays)) или массив (для f(array)) должно быть булевым. /// true if the expression (for an overload of f(expression, arrays)) or an array (for f(array)) should be boolean.
static bool needBoolean() { return false; } static bool needBoolean() { return false; }
/// true, если перегрузка f(array) недоступна. /// true if the f(array) overload is unavailable.
static bool needExpression() { return true; } static bool needExpression() { return true; }
/// true, если массив должен быть ровно один. /// true if the array must be exactly one.
static bool needOneArray() { return false; } static bool needOneArray() { return false; }
static DataTypePtr getReturnType(const DataTypePtr & expression_return, const DataTypePtr & array_element) static DataTypePtr getReturnType(const DataTypePtr & expression_return, const DataTypePtr & array_element)
@ -64,7 +64,7 @@ struct ArrayFilterImpl
return std::make_shared<DataTypeArray>(array_element); return std::make_shared<DataTypeArray>(array_element);
} }
/// Если массивов несколько, сюда передается первый. /// If there are several arrays, the first one is passed here.
static ColumnPtr execute(const ColumnArray & array, ColumnPtr mapped) static ColumnPtr execute(const ColumnArray & array, ColumnPtr mapped)
{ {
const ColumnUInt8 * column_filter = typeid_cast<const ColumnUInt8 *>(&*mapped); const ColumnUInt8 * column_filter = typeid_cast<const ColumnUInt8 *>(&*mapped);
@ -610,8 +610,8 @@ public:
bool isVariadic() const override { return true; } bool isVariadic() const override { return true; }
size_t getNumberOfArguments() const override { return 0; } size_t getNumberOfArguments() const override { return 0; }
/// Вызывается, если хоть один агрумент функции - лямбда-выражение. /// Called if at least one function argument is a lambda expression.
/// Для аргументов-лямбда-выражений определяет типы аргументов этих выражений. /// For argument-lambda expressions, it defines the types of arguments of these expressions.
void getLambdaArgumentTypesImpl(DataTypes & arguments) const override void getLambdaArgumentTypesImpl(DataTypes & arguments) const override
{ {
if (arguments.size() < 1) if (arguments.size() < 1)
@ -679,7 +679,7 @@ public:
throw Exception("Type of first argument for function " + getName() + " must be an expression.", throw Exception("Type of first argument for function " + getName() + " must be an expression.",
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
/// Типы остальных аргументов уже проверены в getLambdaArgumentTypes. /// The types of the remaining arguments are already checked in getLambdaArgumentTypes.
DataTypePtr return_type = expression->getReturnType(); DataTypePtr return_type = expression->getReturnType();
if (Impl::needBoolean() && !typeid_cast<const DataTypeUInt8 *>(&*return_type)) if (Impl::needBoolean() && !typeid_cast<const DataTypeUInt8 *>(&*return_type))
@ -735,9 +735,9 @@ public:
throw Exception("Column of first argument for function " + getName() + " must be an expression.", throw Exception("Column of first argument for function " + getName() + " must be an expression.",
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
/// Типы остальных аргументов уже проверены в getLambdaArgumentTypes. /// The types of the remaining arguments are already checked in getLambdaArgumentTypes.
/// Попросим добавить в блок все столбцы, упоминаемые в выражении, размноженные в массив, параллельный обрабатываемому. /// Let's add to the block all the columns mentioned in the expression, multiplied into an array parallel to the one being processed.
const ExpressionActions & expression = *column_expression->getExpression(); const ExpressionActions & expression = *column_expression->getExpression();
const NamesAndTypesList & required_columns = expression.getRequiredColumnsWithTypes(); const NamesAndTypesList & required_columns = expression.getRequiredColumnsWithTypes();
@ -803,7 +803,7 @@ public:
ColumnPtr column_first_array_ptr; ColumnPtr column_first_array_ptr;
const ColumnArray * column_first_array = nullptr; const ColumnArray * column_first_array = nullptr;
/// Положим в блок аргументы выражения. /// Put the expression arguments in the block.
for (size_t i = 0; i < expression_arguments.size(); ++i) for (size_t i = 0; i < expression_arguments.size(); ++i)
{ {
@ -828,7 +828,7 @@ public:
} }
else else
{ {
/// Первое условие - оптимизация: не сравнивать данные, если указатели равны. /// The first condition is optimization: do not compare data if the pointers are equal.
if (column_array->getOffsetsColumn() != offsets_column if (column_array->getOffsetsColumn() != offsets_column
&& column_array->getOffsets() != typeid_cast<const ColumnArray::ColumnOffsets_t &>(*offsets_column).getData()) && column_array->getOffsets() != typeid_cast<const ColumnArray::ColumnOffsets_t &>(*offsets_column).getData())
throw Exception("Arrays passed to " + getName() + " must have equal size", ErrorCodes::SIZES_OF_ARRAYS_DOESNT_MATCH); throw Exception("Arrays passed to " + getName() + " must have equal size", ErrorCodes::SIZES_OF_ARRAYS_DOESNT_MATCH);
@ -848,7 +848,7 @@ public:
argument_names.insert(argument_name); argument_names.insert(argument_name);
} }
/// Положим в блок все нужные столбцы, размноженные по размерам массивов. /// Put all the necessary columns multiplied by the sizes of arrays into the block.
Names required_columns = expression.getRequiredColumns(); Names required_columns = expression.getRequiredColumns();
size_t prerequisite_index = 0; size_t prerequisite_index = 0;

View File

@ -11,8 +11,8 @@
namespace DB namespace DB
{ {
/** Функции - логические связки: and, or, not, xor. /** Functions are logical links: and, or, not, xor.
* Принимают любые числовые типы, возвращают UInt8, содержащий 0 или 1. * Accept any numeric types, return a UInt8 containing 0 or 1.
*/ */
template<typename B> template<typename B>
@ -91,7 +91,7 @@ using UInt8ColumnPtrs = std::vector<const ColumnUInt8 *>;
template <typename Op, size_t N> template <typename Op, size_t N>
struct AssociativeOperationImpl struct AssociativeOperationImpl
{ {
/// Выбрасывает N последних столбцов из in (если их меньше, то все) и кладет в result их комбинацию. /// Erases the N last columns from `in` (if there are less, then all) and puts into `result` their combination.
static void execute(UInt8ColumnPtrs & in, UInt8Container & result) static void execute(UInt8ColumnPtrs & in, UInt8Container & result)
{ {
if (N > in.size()) if (N > in.size())
@ -113,11 +113,11 @@ struct AssociativeOperationImpl
const UInt8Container & vec; const UInt8Container & vec;
AssociativeOperationImpl<Op, N - 1> continuation; AssociativeOperationImpl<Op, N - 1> continuation;
/// Запоминает последние N столбцов из in. /// Remembers the last N columns from `in`.
AssociativeOperationImpl(UInt8ColumnPtrs & in) AssociativeOperationImpl(UInt8ColumnPtrs & in)
: vec(in[in.size() - N]->getData()), continuation(in) {} : vec(in[in.size() - N]->getData()), continuation(in) {}
/// Возвращает комбинацию значений в i-й строке всех столбцов, запомненных в конструкторе. /// Returns a combination of values in the i-th row of all columns stored in the constructor.
inline UInt8 apply(size_t i) const inline UInt8 apply(size_t i) const
{ {
if (Op::isSaturable()) if (Op::isSaturable())
@ -252,7 +252,7 @@ public:
bool isVariadic() const override { return true; } bool isVariadic() const override { return true; }
size_t getNumberOfArguments() const override { return 0; } size_t getNumberOfArguments() const override { return 0; }
/// Получить типы результата по типам аргументов. Если функция неприменима для данных аргументов - кинуть исключение. /// Get result types by argument types. If the function does not apply to these arguments, throw an exception.
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
{ {
if (arguments.size() < 2) if (arguments.size() < 2)
@ -281,11 +281,11 @@ public:
} }
size_t n = in[0]->size(); size_t n = in[0]->size();
/// Скомбинируем все константные столбцы в одно значение. /// Combine all constant columns into a single value.
UInt8 const_val = 0; UInt8 const_val = 0;
bool has_consts = extractConstColumns(in, const_val); bool has_consts = extractConstColumns(in, const_val);
// Если это значение однозначно определяет результат, вернем его. // If this value uniquely determines the result, return it.
if (has_consts && (in.empty() || Impl<UInt8>::apply(const_val, 0) == Impl<UInt8>::apply(const_val, 1))) if (has_consts && (in.empty() || Impl<UInt8>::apply(const_val, 0) == Impl<UInt8>::apply(const_val, 1)))
{ {
if (!in.empty()) if (!in.empty())
@ -295,7 +295,7 @@ public:
return; return;
} }
/// Если это значение - нейтральный элемент, забудем про него. /// If this value is a neutral element, let's forget about it.
if (has_consts && Impl<UInt8>::apply(const_val, 0) == 0 && Impl<UInt8>::apply(const_val, 1) == 1) if (has_consts && Impl<UInt8>::apply(const_val, 0) == 0 && Impl<UInt8>::apply(const_val, 1) == 1)
has_consts = false; has_consts = false;
@ -313,8 +313,8 @@ public:
vec_res.resize(n); vec_res.resize(n);
} }
/// Разделим входные столбцы на UInt8 и остальные. Первые обработаем более эффективно. /// Divide the input columns into UInt8 and the rest. The first will be processed more efficiently.
/// col_res в каждый момент будет либо находится в конце uint8_in, либо не содержаться в uint8_in. /// col_res at each moment will either be at the end of uint8_in, or not contained in uint8_in.
UInt8ColumnPtrs uint8_in; UInt8ColumnPtrs uint8_in;
ColumnPlainPtrs other_in; ColumnPlainPtrs other_in;
for (IColumn * column : in) for (IColumn * column : in)
@ -325,7 +325,7 @@ public:
other_in.push_back(column); other_in.push_back(column);
} }
/// Нужен хотя бы один столбец в uint8_in, чтобы было с кем комбинировать столбцы из other_in. /// You need at least one column in uint8_in, so that you can combine columns from other_in.
if (uint8_in.empty()) if (uint8_in.empty())
{ {
if (other_in.empty()) if (other_in.empty())
@ -336,16 +336,16 @@ public:
uint8_in.push_back(col_res.get()); uint8_in.push_back(col_res.get());
} }
/// Эффективно скомбинируем все столбцы правильного типа. /// Effectively combine all the columns of the correct type.
while (uint8_in.size() > 1) while (uint8_in.size() > 1)
{ {
/// При большом размере блока объединять по 6 толбцов за проход быстрее всего. /// With a large block size, combining 6 columns per pass is the fastest.
/// При маленьком - чем больше, тем быстрее. /// When small - more, is faster.
AssociativeOperationImpl<Impl<UInt8>, 10>::execute(uint8_in, vec_res); AssociativeOperationImpl<Impl<UInt8>, 10>::execute(uint8_in, vec_res);
uint8_in.push_back(col_res.get()); uint8_in.push_back(col_res.get());
} }
/// По одному добавим все столбцы неправильного типа. /// Add all the columns of the wrong type one at a time.
while (!other_in.empty()) while (!other_in.empty())
{ {
executeUInt8Other(uint8_in[0]->getData(), other_in.back(), vec_res); executeUInt8Other(uint8_in[0]->getData(), other_in.back(), vec_res);
@ -353,7 +353,7 @@ public:
uint8_in[0] = col_res.get(); uint8_in[0] = col_res.get();
} }
/// Такое возможно, если среди аргументов ровно один неконстантный, и он имеет тип UInt8. /// This is possible if there is exactly one non-constant among the arguments, and it is of type UInt8.
if (uint8_in[0] != col_res.get()) if (uint8_in[0] != col_res.get())
{ {
vec_res.assign(uint8_in[0]->getData()); vec_res.assign(uint8_in[0]->getData());

View File

@ -12,24 +12,24 @@
namespace DB namespace DB
{ {
/** Функции генерации псевдослучайных чисел. /** Pseudo-random number generation functions.
* Функция может быть вызвана без аргументов или с одним аргументом. * The function can be called without arguments or with one argument.
* Аргумент игнорируется и служит лишь для того, чтобы несколько вызовов одной функции считались разными и не склеивались. * The argument is ignored and only serves to ensure that several calls to one function are considered different and do not stick together.
* *
* Пример: * Example:
* SELECT rand(), rand() - выдаст два одинаковых столбца. * SELECT rand(), rand() - will output two identical columns.
* SELECT rand(1), rand(2) - выдаст два разных столбца. * SELECT rand(1), rand(2) - will output two different columns.
* *
* Некриптографические генераторы: * Non-cryptographic generators:
* *
* rand - linear congruental generator 0 .. 2^32 - 1. * rand - linear congruental generator 0 .. 2^32 - 1.
* rand64 - комбинирует несколько значений rand, чтобы получить значения из диапазона 0 .. 2^64 - 1. * rand64 - combines several rand values to get values from the range 0 .. 2^64 - 1.
* *
* randConstant - служебная функция, выдаёт константный столбец со случайным значением. * randConstant - service function, produces a constant column with a random value.
* *
* В качестве затравки используют время. * The time is used as the seed.
* Замечание: переинициализируется на каждый блок. * Note: it is reinitialized for each block.
* Это значит, что таймер должен быть достаточного разрешения, чтобы выдавать разные значения на каждый блок. * This means that the timer must be of sufficient resolution to give different values to each block.
*/ */
namespace detail namespace detail
@ -42,11 +42,11 @@ namespace detail
struct LinearCongruentialGenerator struct LinearCongruentialGenerator
{ {
/// Константы из man lrand48_r. /// Constants from man lrand48_r.
static constexpr UInt64 a = 0x5DEECE66D; static constexpr UInt64 a = 0x5DEECE66D;
static constexpr UInt64 c = 0xB; static constexpr UInt64 c = 0xB;
/// А эта - из head -c8 /dev/urandom | xxd -p /// And this is from `head -c8 /dev/urandom | Xxd -p`
UInt64 current = 0x09826f4a081cee35ULL; UInt64 current = 0x09826f4a081cee35ULL;
LinearCongruentialGenerator() {} LinearCongruentialGenerator() {}
@ -194,7 +194,7 @@ class FunctionRandomConstant : public IFunction
private: private:
using ToType = typename Impl::ReturnType; using ToType = typename Impl::ReturnType;
/// Значение одно для разных блоков. /// The value is one for different blocks.
bool is_initialized = false; bool is_initialized = false;
ToType value; ToType value;

View File

@ -15,19 +15,19 @@
namespace DB namespace DB
{ {
/** Функции округления: /** Rounding Functions:
* roundToExp2 - вниз до ближайшей степени двойки; * roundToExp2 - down to the nearest power of two;
* roundDuration - вниз до ближайшего из: 0, 1, 10, 30, 60, 120, 180, 240, 300, 600, 1200, 1800, 3600, 7200, 18000, 36000; * roundDuration - down to the nearest of: 0, 1, 10, 30, 60, 120, 180, 240, 300, 600, 1200, 1800, 3600, 7200, 18000, 36000;
* roundAge - вниз до ближайшего из: 0, 18, 25, 35, 45, 55. * roundAge - down to the nearest of: 0, 18, 25, 35, 45, 55.
* *
* round(x, N) - арифметическое округление (N = 0 по умолчанию). * round(x, N) - arithmetic rounding (N = 0 by default).
* ceil(x, N) - наименьшее число, которое не меньше x (N = 0 по умолчанию). * ceil(x, N) is the smallest number that is at least x (N = 0 by default).
* floor(x, N) - наибольшее число, которое не больше x (N = 0 по умолчанию). * floor(x, N) is the largest number that is not greater than x (N = 0 by default).
* *
* Значение параметра N: * The value of the parameter N:
* - N > 0: округлять до числа с N десятичными знаками после запятой * - N > 0: round to the number with N decimal places after the decimal point
* - N < 0: окурглять до целого числа с N нулевыми знаками * - N < 0: round to an integer with N zero characters
* - N = 0: округлять до целого числа * - N = 0: round to an integer
*/ */
template<typename A> template<typename A>
@ -106,8 +106,8 @@ struct RoundAgeImpl
} }
}; };
/** Быстрое вычисление остатка от деления для применения к округлению целых чисел. /** Quick calculation of the remainder of the division to apply to the rounding of integers.
* Без проверки, потому что делитель всегда положительный. * Without verification, because the divisor is always positive.
*/ */
template<typename T, typename Enable = void> template<typename T, typename Enable = void>
struct FastModulo; struct FastModulo;
@ -161,14 +161,14 @@ public:
} }
}; };
/** Этот параметр контролирует поведение функций округления. /** This parameter controls the behavior of the rounding functions.
*/ */
enum ScaleMode enum ScaleMode
{ {
PositiveScale, // округлять до числа с N десятичными знаками после запятой PositiveScale, // round to a number with N decimal places after the decimal point
NegativeScale, // окурглять до целого числа с N нулевыми знаками NegativeScale, // round to an integer with N zero characters
ZeroScale, // округлять до целого числа ZeroScale, // round to an integer
NullScale // возвращать нулевое значение NullScale // return zero value
}; };
#if !defined(_MM_FROUND_NINT) #if !defined(_MM_FROUND_NINT)
@ -177,7 +177,7 @@ enum ScaleMode
#define _MM_FROUND_CEIL 2 #define _MM_FROUND_CEIL 2
#endif #endif
/** Реализация низкоуровневых функций округления для целочисленных значений. /** Implementing low-level rounding functions for integer values.
*/ */
template<typename T, int rounding_mode, ScaleMode scale_mode, typename Enable = void> template<typename T, int rounding_mode, ScaleMode scale_mode, typename Enable = void>
struct IntegerRoundingComputation; struct IntegerRoundingComputation;
@ -283,7 +283,7 @@ public:
static const size_t data_count = 4; static const size_t data_count = 4;
protected: protected:
/// Предотвратить появление отрицательных нолей определённых в стандарте IEEE-754. /// Prevent the appearance of negative zeros defined in the IEEE-754 standard.
static inline void normalize(__m128 & val, const __m128 & mask) static inline void normalize(__m128 & val, const __m128 & mask)
{ {
__m128 mask1 = _mm_cmpeq_ps(val, getZero()); __m128 mask1 = _mm_cmpeq_ps(val, getZero());
@ -321,7 +321,7 @@ public:
static const size_t data_count = 2; static const size_t data_count = 2;
protected: protected:
/// Предотвратить появление отрицательных нолей определённых в стандарте IEEE-754. /// Prevent the occurrence of negative zeros defined in the IEEE-754 standard.
static inline void normalize(__m128d & val, const __m128d & mask) static inline void normalize(__m128d & val, const __m128d & mask)
{ {
__m128d mask1 = _mm_cmpeq_pd(val, getZero()); __m128d mask1 = _mm_cmpeq_pd(val, getZero());
@ -351,7 +351,7 @@ protected:
} }
}; };
/** Реализация низкоуровневых функций округления для значений с плавающей точкой. /** Implementation of low-level round-off functions for floating-point values.
*/ */
template<typename T, int rounding_mode, ScaleMode scale_mode> template<typename T, int rounding_mode, ScaleMode scale_mode>
class FloatRoundingComputation; class FloatRoundingComputation;
@ -372,7 +372,7 @@ public:
__m128 val = _mm_loadu_ps(in); __m128 val = _mm_loadu_ps(in);
__m128 mask = _mm_cmplt_ps(val, getZero()); __m128 mask = _mm_cmplt_ps(val, getZero());
/// Алгоритм округления. /// Rounding algorithm.
val = _mm_mul_ps(val, scale); val = _mm_mul_ps(val, scale);
val = _mm_round_ps(val, rounding_mode); val = _mm_round_ps(val, rounding_mode);
val = _mm_div_ps(val, scale); val = _mm_div_ps(val, scale);
@ -398,20 +398,20 @@ public:
__m128 val = _mm_loadu_ps(in); __m128 val = _mm_loadu_ps(in);
__m128 mask = _mm_cmplt_ps(val, getZero()); __m128 mask = _mm_cmplt_ps(val, getZero());
/// Превратить отрицательные значения в положительные. /// Turn negative values into positive values.
__m128 factor = _mm_cmpge_ps(val, getZero()); __m128 factor = _mm_cmpge_ps(val, getZero());
factor = _mm_min_ps(factor, getTwo()); factor = _mm_min_ps(factor, getTwo());
factor = _mm_sub_ps(factor, getOne()); factor = _mm_sub_ps(factor, getOne());
val = _mm_mul_ps(val, factor); val = _mm_mul_ps(val, factor);
/// Алгоритм округления. /// Rounding algorithm.
val = _mm_div_ps(val, scale); val = _mm_div_ps(val, scale);
__m128 res = _mm_cmpge_ps(val, getOneTenth()); __m128 res = _mm_cmpge_ps(val, getOneTenth());
val = _mm_round_ps(val, rounding_mode); val = _mm_round_ps(val, rounding_mode);
val = _mm_mul_ps(val, scale); val = _mm_mul_ps(val, scale);
val = _mm_and_ps(val, res); val = _mm_and_ps(val, res);
/// Вернуть настоящие знаки всех значений. /// Return the real signs of all values.
val = _mm_mul_ps(val, factor); val = _mm_mul_ps(val, factor);
normalize(val, mask); normalize(val, mask);
@ -463,7 +463,7 @@ public:
__m128d val = _mm_loadu_pd(in); __m128d val = _mm_loadu_pd(in);
__m128d mask = _mm_cmplt_pd(val, getZero()); __m128d mask = _mm_cmplt_pd(val, getZero());
/// Алгоритм округления. /// Rounding algorithm.
val = _mm_mul_pd(val, scale); val = _mm_mul_pd(val, scale);
val = _mm_round_pd(val, rounding_mode); val = _mm_round_pd(val, rounding_mode);
val = _mm_div_pd(val, scale); val = _mm_div_pd(val, scale);
@ -489,20 +489,20 @@ public:
__m128d val = _mm_loadu_pd(in); __m128d val = _mm_loadu_pd(in);
__m128d mask = _mm_cmplt_pd(val, getZero()); __m128d mask = _mm_cmplt_pd(val, getZero());
/// Превратить отрицательные значения в положительные. /// Turn negative values into positive values.
__m128d factor = _mm_cmpge_pd(val, getZero()); __m128d factor = _mm_cmpge_pd(val, getZero());
factor = _mm_min_pd(factor, getTwo()); factor = _mm_min_pd(factor, getTwo());
factor = _mm_sub_pd(factor, getOne()); factor = _mm_sub_pd(factor, getOne());
val = _mm_mul_pd(val, factor); val = _mm_mul_pd(val, factor);
/// Алгоритм округления. /// Rounding algorithm.
val = _mm_div_pd(val, scale); val = _mm_div_pd(val, scale);
__m128d res = _mm_cmpge_pd(val, getOneTenth()); __m128d res = _mm_cmpge_pd(val, getOneTenth());
val = _mm_round_pd(val, rounding_mode); val = _mm_round_pd(val, rounding_mode);
val = _mm_mul_pd(val, scale); val = _mm_mul_pd(val, scale);
val = _mm_and_pd(val, res); val = _mm_and_pd(val, res);
/// Вернуть настоящие знаки всех значений. /// Return the real signs of all values.
val = _mm_mul_pd(val, factor); val = _mm_mul_pd(val, factor);
normalize(val, mask); normalize(val, mask);
@ -538,7 +538,7 @@ public:
} }
}; };
#else #else
/// Реализация для ARM. Не векторизована. Не исправляет отрицательные нули. /// Implementation for ARM. Not vectorized. Does not fix negative zeros.
template <int mode> template <int mode>
float roundWithMode(float x) float roundWithMode(float x)
@ -613,12 +613,12 @@ public:
#endif #endif
/** Реализация высокоуровневых функций округления. /** Implementing high-level rounding functions.
*/ */
template<typename T, int rounding_mode, ScaleMode scale_mode, typename Enable = void> template<typename T, int rounding_mode, ScaleMode scale_mode, typename Enable = void>
struct FunctionRoundingImpl; struct FunctionRoundingImpl;
/** Реализация высокоуровневых функций округления для целочисленных значений. /** Implement high-level rounding functions for integer values.
*/ */
template<typename T, int rounding_mode, ScaleMode scale_mode> template<typename T, int rounding_mode, ScaleMode scale_mode>
struct FunctionRoundingImpl<T, rounding_mode, scale_mode, struct FunctionRoundingImpl<T, rounding_mode, scale_mode,
@ -650,7 +650,7 @@ public:
} }
}; };
/** Реализация высокоуровневых функций округления для значений с плавающей точкой. /** Implement high-level round-off functions for floating-point values.
*/ */
template<typename T, int rounding_mode, ScaleMode scale_mode> template<typename T, int rounding_mode, ScaleMode scale_mode>
struct FunctionRoundingImpl<T, rounding_mode, scale_mode, struct FunctionRoundingImpl<T, rounding_mode, scale_mode,
@ -730,7 +730,7 @@ public:
} }
}; };
/** Реализация высокоуровневых функций округления в том случае, когда возвращается нулевое значение. /** Implementation of high-level rounding functions in the case when a zero value is returned.
*/ */
template<typename T, int rounding_mode, ScaleMode scale_mode> template<typename T, int rounding_mode, ScaleMode scale_mode>
struct FunctionRoundingImpl<T, rounding_mode, scale_mode, struct FunctionRoundingImpl<T, rounding_mode, scale_mode,
@ -748,11 +748,11 @@ public:
} }
}; };
/// Следующий код генерирует во время сборки таблицу степеней числа 10. /// The following code generates a table of powers of 10 during the build.
namespace namespace
{ {
/// Отдельные степени числа 10. /// Individual degrees of the number 10.
template<size_t N> template<size_t N>
struct PowerOf10 struct PowerOf10
@ -767,7 +767,7 @@ namespace
}; };
} }
/// Объявление и определение контейнера содержащего таблицу степеней числа 10. /// Declaring and defining a container containing a table of powers of 10.
template<size_t... TArgs> template<size_t... TArgs>
struct TableContainer struct TableContainer
@ -778,7 +778,7 @@ struct TableContainer
template<size_t... TArgs> template<size_t... TArgs>
const std::array<size_t, sizeof...(TArgs)> TableContainer<TArgs...>::values {{ TArgs... }}; const std::array<size_t, sizeof...(TArgs)> TableContainer<TArgs...>::values {{ TArgs... }};
/// Генератор первых N степеней. /// The generator of the first N degrees.
template<size_t N, size_t... TArgs> template<size_t N, size_t... TArgs>
struct FillArrayImpl struct FillArrayImpl
@ -798,9 +798,9 @@ struct FillArray
using result = typename FillArrayImpl<N - 1>::result; using result = typename FillArrayImpl<N - 1>::result;
}; };
/** Этот шаблон определяет точность, которую используют функции round/ceil/floor, /** This pattern defines the precision that the round/ceil/floor functions use,
* затем преобразовывает её в значение, которое можно использовать в операциях * then converts it to a value that can be used in operations of
* умножения и деления. Поэтому оно называется масштабом. * multiplication and division. Therefore, it is called a scale.
*/ */
template<typename T, typename U, typename Enable = void> template<typename T, typename U, typename Enable = void>
struct ScaleForRightType; struct ScaleForRightType;
@ -944,7 +944,7 @@ struct ScaleForRightType<T, U,
} }
}; };
/** Превратить параметр точности в масштаб. /** Turn the precision parameter into a scale.
*/ */
template<typename T> template<typename T>
struct ScaleForLeftType struct ScaleForLeftType
@ -968,7 +968,7 @@ struct ScaleForLeftType
} }
}; };
/** Главный шаблон применяющий функцию округления к значению или столбцу. /** The main template that applies the rounding function to a value or column.
*/ */
template<typename T, int rounding_mode, ScaleMode scale_mode> template<typename T, int rounding_mode, ScaleMode scale_mode>
struct Cruncher struct Cruncher
@ -997,7 +997,7 @@ struct Cruncher
} }
}; };
/** Выбрать подходящий алгоритм обработки в зависимости от масштаба. /** Select the appropriate processing algorithm depending on the scale.
*/ */
template<typename T, template <typename> class U, int rounding_mode> template<typename T, template <typename> class U, int rounding_mode>
struct Dispatcher struct Dispatcher
@ -1028,9 +1028,9 @@ struct Dispatcher
} }
}; };
/** Шаблон для функций, которые округляют значение входного параметра типа /** A template for functions that round the value of an input parameter of type
* (U)Int8/16/32/64 или Float32/64, и принимают дополнительный необязятельный * (U)Int8/16/32/64 or Float32/64, and accept an additional optional
* параметр (по умолчанию - 0). * parameter (default is 0).
*/ */
template<typename Name, int rounding_mode> template<typename Name, int rounding_mode>
class FunctionRounding : public IFunction class FunctionRounding : public IFunction
@ -1072,7 +1072,7 @@ public:
bool isVariadic() const override { return true; } bool isVariadic() const override { return true; }
size_t getNumberOfArguments() const override { return 0; } size_t getNumberOfArguments() const override { return 0; }
/// Получить типы результата по типам аргументов. Если функция неприменима для данных аргументов - кинуть исключение. /// Get result types by argument types. If the function does not apply to these arguments, throw an exception.
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
{ {
if ((arguments.size() < 1) || (arguments.size() > 2)) if ((arguments.size() < 1) || (arguments.size() > 2))

View File

@ -102,6 +102,7 @@ struct LengthImpl
/** If the string is UTF-8 encoded text, it returns the length of the text in code points. /** If the string is UTF-8 encoded text, it returns the length of the text in code points.
* (not in characters: the length of the text "ё" can be either 1 or 2, depending on the normalization) * (not in characters: the length of the text "ё" can be either 1 or 2, depending on the normalization)
* (not in characters: the length of the text "" can be either 1 or 2, depending on the normalization)
* Otherwise, the behavior is undefined. * Otherwise, the behavior is undefined.
*/ */
struct LengthUTF8Impl struct LengthUTF8Impl

View File

@ -13,7 +13,7 @@
namespace DB namespace DB
{ {
/** Функции работы со строками: /** String functions
* *
* length, empty, notEmpty, * length, empty, notEmpty,
* concat, substring, lower, upper, reverse * concat, substring, lower, upper, reverse
@ -26,11 +26,11 @@ namespace DB
* s, c1, c2 -> s: substring, substringUTF8 * s, c1, c2 -> s: substring, substringUTF8
* s, c1, c2, s2 -> s: replace, replaceUTF8 * s, c1, c2, s2 -> s: replace, replaceUTF8
* *
* Функции поиска строк и регулярных выражений расположены отдельно. * The search functions for strings and regular expressions are located separately.
* Функции работы с URL расположены отдельно. * URL functions are located separately.
* Функции кодирования строк, конвертации в другие типы расположены отдельно. * String encoding functions, converting to other types are located separately.
* *
* Функции length, empty, notEmpty, reverse также работают с массивами. * The functions length, empty, notEmpty, reverse also work with arrays.
*/ */
@ -89,10 +89,10 @@ inline void UTF8CyrillicToCase(const UInt8 *& src, const UInt8 * const src_end,
} }
/** Если строка содержит текст в кодировке UTF-8 - перевести его в нижний (верхний) регистр. /** If the string contains UTF-8 encoded text, convert it to the lower (upper) case.
* Замечание: предполагается, что после перевода символа в другой регистр, * Note: It is assumed that after the character is converted to another case,
* длина его мультибайтовой последовательности в UTF-8 не меняется. * the length of its multibyte sequence in UTF-8 does not change.
* Иначе - поведение не определено. * Otherwise, the behavior is undefined.
*/ */
template <char not_case_lower_bound, template <char not_case_lower_bound,
char not_case_upper_bound, char not_case_upper_bound,

View File

@ -15,31 +15,31 @@
namespace DB namespace DB
{ {
/** Функции, разделяющие строки на массив строк или наоборот. /** Functions that split strings into an array of strings or vice versa.
* *
* splitByChar(sep, s) * splitByChar(sep, s)
* splitByString(sep, s) * splitByString(sep, s)
* splitByRegexp(regexp, s) * splitByRegexp(regexp, s)
* *
* extractAll(s, regexp) - выделить из строки подпоследовательности, соответствующие регекспу. * extractAll(s, regexp) - select from the string the subsequences corresponding to the regexp.
* - первый subpattern, если в regexp-е есть subpattern; * - first subpattern, if regexp has subpattern;
* - нулевой subpattern (сматчившуюся часть, иначе); * - zero subpattern (the match part, otherwise);
* - инача, пустой массив * - otherwise, an empty array
* *
* arrayStringConcat(arr) * arrayStringConcat(arr)
* arrayStringConcat(arr, delimiter) * arrayStringConcat(arr, delimiter)
* - склеить массив строк в одну строку через разделитель. * - join an array of strings into one string via a separator.
* *
* alphaTokens(s) - выделить из строки подпоследовательности [a-zA-Z]+. * alphaTokens(s) - select from the string subsequence `[a-zA-Z]+`.
* *
* Функции работы с URL расположены отдельно. * URL functions are located separately.
*/ */
using Pos = const char *; using Pos = const char *;
/// Генераторы подстрок. Все они обладают общим интерфейсом. /// Substring generators. All of them have a common interface.
class AlphaTokensImpl class AlphaTokensImpl
{ {
@ -48,13 +48,13 @@ private:
Pos end; Pos end;
public: public:
/// Получить имя фукнции. /// Get the name of the function.
static constexpr auto name = "alphaTokens"; static constexpr auto name = "alphaTokens";
static String getName() { return name; } static String getName() { return name; }
static size_t getNumberOfArguments() { return 1; } static size_t getNumberOfArguments() { return 1; }
/// Проверить типы агрументов функции. /// Check the type of the function's arguments.
static void checkArguments(const DataTypes & arguments) static void checkArguments(const DataTypes & arguments)
{ {
if (!typeid_cast<const DataTypeString *>(&*arguments[0])) if (!typeid_cast<const DataTypeString *>(&*arguments[0]))
@ -62,23 +62,23 @@ public:
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
} }
/// Инициализировать по аргументам функции. /// Initialize by the function arguments.
void init(Block & block, const ColumnNumbers & arguments) {} void init(Block & block, const ColumnNumbers & arguments) {}
/// Вызывается для каждой следующей строки. /// Called for each next string.
void set(Pos pos_, Pos end_) void set(Pos pos_, Pos end_)
{ {
pos = pos_; pos = pos_;
end = end_; end = end_;
} }
/// Возвращает позицию аргумента, являющегося столбцом строк /// Returns the position of the argument, that is the column of strings
size_t getStringsArgumentPosition() size_t getStringsArgumentPosition()
{ {
return 0; return 0;
} }
/// Получить следующий токен, если есть, или вернуть false. /// Get the next token, if any, or return false.
bool get(Pos & token_begin, Pos & token_end) bool get(Pos & token_begin, Pos & token_end)
{ {
/// Skip garbage /// Skip garbage
@ -141,7 +141,7 @@ public:
sep = sep_str[0]; sep = sep_str[0];
} }
/// Возвращает позицию аргумента, являющегося столбцом строк /// Returns the position of the argument, that is the column of strings
size_t getStringsArgumentPosition() size_t getStringsArgumentPosition()
{ {
return 1; return 1;
@ -204,20 +204,20 @@ public:
sep = col->getData(); sep = col->getData();
} }
/// Возвращает позицию аргумента, являющегося столбцом строк /// Returns the position of the argument that is the column of strings
size_t getStringsArgumentPosition() size_t getStringsArgumentPosition()
{ {
return 1; return 1;
} }
/// Вызывается для каждой следующей строки. /// Called for each next string.
void set(Pos pos_, Pos end_) void set(Pos pos_, Pos end_)
{ {
pos = pos_; pos = pos_;
end = end_; end = end_;
} }
/// Получить следующий токен, если есть, или вернуть false. /// Get the next token, if any, or return false.
bool get(Pos & token_begin, Pos & token_end) bool get(Pos & token_begin, Pos & token_end)
{ {
if (!pos) if (!pos)
@ -252,13 +252,13 @@ public:
static String getName() { return name; } static String getName() { return name; }
static size_t getNumberOfArguments() { return 2; } static size_t getNumberOfArguments() { return 2; }
/// Проверить типы агрументов функции. /// Check the type of function arguments.
static void checkArguments( const DataTypes & arguments ) static void checkArguments( const DataTypes & arguments )
{ {
SplitByStringImpl::checkArguments(arguments); SplitByStringImpl::checkArguments(arguments);
} }
/// Инициализировать по аргументам функции. /// Initialize by the function arguments.
void init(Block & block, const ColumnNumbers & arguments) void init(Block & block, const ColumnNumbers & arguments)
{ {
const ColumnConstString * col = typeid_cast<const ColumnConstString *>(block.safeGetByPosition(arguments[1]).column.get()); const ColumnConstString * col = typeid_cast<const ColumnConstString *>(block.safeGetByPosition(arguments[1]).column.get());
@ -274,20 +274,20 @@ public:
matches.resize(capture + 1); matches.resize(capture + 1);
} }
/// Возвращает позицию аргумента, являющегося столбцом строк /// Returns the position of the argument that is the column of strings
size_t getStringsArgumentPosition() size_t getStringsArgumentPosition()
{ {
return 0; return 0;
} }
/// Вызывается для каждой следующей строки. /// Called for each next string.
void set(Pos pos_, Pos end_) void set(Pos pos_, Pos end_)
{ {
pos = pos_; pos = pos_;
end = end_; end = end_;
} }
/// Получить следующий токен, если есть, или вернуть false. /// Get the next token, if any, or return false.
bool get(Pos & token_begin, Pos & token_end) bool get(Pos & token_begin, Pos & token_end)
{ {
if (!pos || pos > end) if (!pos || pos > end)
@ -305,7 +305,7 @@ public:
} }
}; };
/// Функция, принимающая строку, и возвращающая массив подстрок, создаваемый некоторым генератором. /// A function that takes a string, and returns an array of substrings created by some generator.
template <typename Generator> template <typename Generator>
class FunctionTokens : public IFunction class FunctionTokens : public IFunction
{ {
@ -350,7 +350,7 @@ public:
const ColumnString::Offsets_t & src_offsets = col_str->getOffsets(); const ColumnString::Offsets_t & src_offsets = col_str->getOffsets();
res_offsets.reserve(src_offsets.size()); res_offsets.reserve(src_offsets.size());
res_strings_offsets.reserve(src_offsets.size() * 5); /// Константа 5 - наугад. res_strings_offsets.reserve(src_offsets.size() * 5); /// Constant 5 - at random.
res_strings_chars.reserve(src_chars.size()); res_strings_chars.reserve(src_chars.size());
Pos token_begin = nullptr; Pos token_begin = nullptr;
@ -411,7 +411,7 @@ public:
}; };
/// Склеивает массив строк в одну строку через разделитель. /// Joins an array of strings into one string via a separator.
class FunctionArrayStringConcat : public IFunction class FunctionArrayStringConcat : public IFunction
{ {
private: private:
@ -428,14 +428,14 @@ private:
if (!size) if (!size)
return; return;
/// С небольшим запасом - как будто разделитель идёт и после последней строки массива. /// With a small margin - as if the separator goes after the last string of the array.
dst_chars.resize( dst_chars.resize(
src_chars.size() src_chars.size()
+ delimiter_size * src_string_offsets.size() /// Разделители после каждой строки... + delimiter_size * src_string_offsets.size() /// Separators after each string...
+ src_array_offsets.size() /// Нулевой байт после каждой склеенной строки + src_array_offsets.size() /// Zero byte after each joined string
- src_string_offsets.size()); /// Бывший нулевой байт после каждой строки массива - src_string_offsets.size()); /// The former zero byte after each string of the array
/// Будет столько строк, сколько было массивов. /// There will be as many strings as there were arrays.
dst_string_offsets.resize(src_array_offsets.size()); dst_string_offsets.resize(src_array_offsets.size());
ColumnArray::Offset_t current_src_array_offset = 0; ColumnArray::Offset_t current_src_array_offset = 0;
@ -443,10 +443,10 @@ private:
ColumnString::Offset_t current_dst_string_offset = 0; ColumnString::Offset_t current_dst_string_offset = 0;
/// Цикл по массивам строк. /// Loop through the array of strings.
for (size_t i = 0; i < size; ++i) for (size_t i = 0; i < size; ++i)
{ {
/// Цикл по строкам внутри массива. /// NOTE Можно всё сделать за одно копирование, если разделитель имеет размер 1. /// Loop through the rows within the array. /// NOTE You can do everything in one copy, if the separator has a size of 1.
for (auto next_src_array_offset = src_array_offsets[i]; current_src_array_offset < next_src_array_offset; ++current_src_array_offset) for (auto next_src_array_offset = src_array_offsets[i]; current_src_array_offset < next_src_array_offset; ++current_src_array_offset)
{ {
size_t bytes_to_copy = src_string_offsets[current_src_array_offset] - current_src_string_offset - 1; size_t bytes_to_copy = src_string_offsets[current_src_array_offset] - current_src_string_offset - 1;

View File

@ -10,31 +10,31 @@
namespace DB namespace DB
{ {
/** Функции поиска и замены в строках: /** Search and replace functions in strings:
* *
* position(haystack, needle) - обычный поиск подстроки в строке, возвращает позицию (в байтах) найденной подстроки, начиная с 1, или 0, если подстрока не найдена. * position(haystack, needle) - the normal search for a substring in a string, returns the position (in bytes) of the found substring starting with 1, or 0 if no substring is found.
* positionUTF8(haystack, needle) - то же самое, но позиция вычисляется в кодовых точках, при условии, что строка в кодировке UTF-8. * positionUTF8(haystack, needle) - the same, but the position is calculated at code points, provided that the string is encoded in UTF-8.
* positionCaseInsensitive(haystack, needle) * positionCaseInsensitive(haystack, needle)
* positionCaseInsensitiveUTF8(haystack, needle) * positionCaseInsensitiveUTF8(haystack, needle)
* *
* like(haystack, pattern) - поиск по регулярному выражению LIKE; возвращает 0 или 1. Регистронезависимое, но только для латиницы. * like(haystack, pattern) - search by the regular expression LIKE; Returns 0 or 1. Case-insensitive, but only for Latin.
* notLike(haystack, pattern) * notLike(haystack, pattern)
* *
* match(haystack, pattern) - поиск по регулярному выражению re2; возвращает 0 или 1. * match(haystack, pattern) - search by regular expression re2; Returns 0 or 1.
* *
* Применяет регексп re2 и достаёт: * Applies regexp re2 and pulls:
* - первый subpattern, если в regexp-е есть subpattern; * - the first subpattern, if the regexp has a subpattern;
* - нулевой subpattern (сматчившуюся часть, иначе); * - the zero subpattern (the match part, otherwise);
* - если не сматчилось - пустую строку. * - if not match - an empty string.
* extract(haystack, pattern) * extract(haystack, pattern)
* *
* replaceOne(haystack, pattern, replacement) - замена шаблона по заданным правилам, только первое вхождение. * replaceOne(haystack, pattern, replacement) - replacing the pattern with the specified rules, only the first occurrence.
* replaceAll(haystack, pattern, replacement) - замена шаблона по заданным правилам, все вхождения. * replaceAll(haystack, pattern, replacement) - replacing the pattern with the specified rules, all occurrences.
* *
* replaceRegexpOne(haystack, pattern, replacement) - замена шаблона по заданному регекспу, только первое вхождение. * replaceRegexpOne(haystack, pattern, replacement) - replaces the pattern with the specified regexp, only the first occurrence.
* replaceRegexpAll(haystack, pattern, replacement) - замена шаблона по заданному регекспу, все вхождения. * replaceRegexpAll(haystack, pattern, replacement) - replaces the pattern with the specified type, all occurrences.
* *
* Внимание! На данный момент, аргументы needle, pattern, n, replacement обязаны быть константами. * Warning! At this point, the arguments needle, pattern, n, replacement must be constants.
*/ */

View File

@ -25,30 +25,30 @@ namespace ErrorCodes
} }
/** transform(x, from_array, to_array[, default]) - преобразовать x согласно переданному явным образом соответствию. /** transform(x, from_array, to_array[, default]) - convert x according to an explicitly passed match.
*/ */
DataTypeTraits::EnrichedDataTypePtr getSmallestCommonNumericType(const DataTypeTraits::EnrichedDataTypePtr & type1, const IDataType & type2); DataTypeTraits::EnrichedDataTypePtr getSmallestCommonNumericType(const DataTypeTraits::EnrichedDataTypePtr & type1, const IDataType & type2);
/** transform(x, [from...], [to...], default) /** transform(x, [from...], [to...], default)
* - преобразует значения согласно явно указанному отображению. * - converts the values according to the explicitly specified mapping.
* *
* x - что преобразовывать. * x - what to transform.
* from - константный массив значений для преобразования. * from - a constant array of values for the transformation.
* to - константный массив значений, в которые должны быть преобразованы значения из from. * to - a constant array of values into which values from `from` must be transformed.
* default - какое значение использовать, если x не равен ни одному из значений во from. * default - what value to use if x is not equal to any of the values in `from`.
* from и to - массивы одинаковых размеров. * `from` and `to` - arrays of the same size.
* *
* Типы: * Types:
* transform(T, Array(T), Array(U), U) -> U * transform(T, Array(T), Array(U), U) -> U
* *
* transform(x, [from...], [to...]) * transform(x, [from...], [to...])
* - eсли default не указан, то для значений x, для которых нет соответствующего элемента во from, возвращается не изменённое значение x. * - if `default` is not specified, then for values of `x` for which there is no corresponding element in `from`, the unchanged value of `x` is returned.
* *
* Типы: * Types:
* transform(T, Array(T), Array(T)) -> T * transform(T, Array(T), Array(T)) -> T
* *
* Замечание: реализация довольно громоздкая. * Note: the implementation is rather cumbersome.
*/ */
class FunctionTransform : public IFunction class FunctionTransform : public IFunction
{ {
@ -131,12 +131,12 @@ public:
if (type_arr_to_nested->behavesAsNumber() && type_default->behavesAsNumber()) if (type_arr_to_nested->behavesAsNumber() && type_default->behavesAsNumber())
{ {
/// Берём наименьший общий тип для элементов массива значений to и для default-а. /// We take the smallest common type for the elements of the array of values `to` and for `default`.
DataTypeTraits::EnrichedDataTypePtr res = getSmallestCommonNumericType(enriched_type_arr_to_nested, *type_default); DataTypeTraits::EnrichedDataTypePtr res = getSmallestCommonNumericType(enriched_type_arr_to_nested, *type_default);
return res.first; return res.first;
} }
/// TODO Больше проверок. /// TODO More checks.
return type_arr_to_nested->clone(); return type_arr_to_nested->clone();
} }
} }
@ -189,7 +189,7 @@ public:
private: private:
void executeConst(Block & block, const ColumnNumbers & arguments, const size_t result) void executeConst(Block & block, const ColumnNumbers & arguments, const size_t result)
{ {
/// Составим блок из полноценных столбцов размера 1 и вычислим функцию как обычно. /// Construct a block of full-size columns of size 1 and compute the function as usual.
Block tmp_block; Block tmp_block;
ColumnNumbers tmp_arguments; ColumnNumbers tmp_arguments;
@ -724,10 +724,10 @@ private:
} }
/// Разные варианты хэш-таблиц для реализации отображения. /// Different versions of the hash tables to implement the mapping.
using NumToNum = HashMap<UInt64, UInt64, HashCRC32<UInt64>>; using NumToNum = HashMap<UInt64, UInt64, HashCRC32<UInt64>>;
using NumToString = HashMap<UInt64, StringRef, HashCRC32<UInt64>>; /// Везде StringRef-ы с завершающим нулём. using NumToString = HashMap <UInt64, StringRef, HashCRC32 <UInt64 >>; /// Everywhere StringRef's with trailing zero.
using StringToNum = HashMap<StringRef, UInt64, StringRefHash>; using StringToNum = HashMap<StringRef, UInt64, StringRefHash>;
using StringToString = HashMap<StringRef, StringRef, StringRefHash>; using StringToString = HashMap<StringRef, StringRef, StringRefHash>;
@ -738,12 +738,12 @@ private:
Arena string_pool; Arena string_pool;
Field const_default_value; /// Null, если не задано. Field const_default_value; /// Null, if not specified.
bool prepared = false; bool prepared = false;
std::mutex mutex; std::mutex mutex;
/// Может вызываться из разных потоков. Срабатывает только при первом вызове. /// Can be called from different threads. It works only on the first call.
void prepare(const Array & from, const Array & to, Block & block, const ColumnNumbers & arguments) void prepare(const Array & from, const Array & to, Block & block, const ColumnNumbers & arguments)
{ {
if (prepared) if (prepared)
@ -764,7 +764,7 @@ private:
Array converted_to; Array converted_to;
const Array * used_to = &to; const Array * used_to = &to;
/// Задано ли значение по-умолчанию. /// Whether the default value is set.
if (arguments.size() == 4) if (arguments.size() == 4)
{ {
@ -774,7 +774,7 @@ private:
if (const_default_col) if (const_default_col)
const_default_value = (*const_default_col)[0]; const_default_value = (*const_default_col)[0];
/// Нужно ли преобразовать элементы to и default_value к наименьшему общему типу, который является Float64? /// Do I need to convert the elements `to` and `default_value` to the smallest common type that is Float64?
bool default_col_is_float = bool default_col_is_float =
typeid_cast<const ColumnFloat32 *>(default_col) typeid_cast<const ColumnFloat32 *>(default_col)
|| typeid_cast<const ColumnFloat64 *>(default_col) || typeid_cast<const ColumnFloat64 *>(default_col)
@ -797,7 +797,7 @@ private:
} }
} }
/// Замечание: не делается проверка дубликатов в массиве from. /// Note: Do not check the duplicates in the `from` array.
if (from[0].getType() != Field::Types::String && to[0].getType() != Field::Types::String) if (from[0].getType() != Field::Types::String && to[0].getType() != Field::Types::String)
{ {

View File

@ -20,7 +20,9 @@ static size_t decodeURL(const char * src, size_t src_size, char * dst)
src_curr_pos = find_first_symbols<'%'>(src_curr_pos, src_end); src_curr_pos = find_first_symbols<'%'>(src_curr_pos, src_end);
if (src_curr_pos == src_end) if (src_curr_pos == src_end)
{
break; break;
}
else if (src_end - src_curr_pos < 3) else if (src_end - src_curr_pos < 3)
{ {
src_curr_pos = src_end; src_curr_pos = src_end;
@ -28,8 +30,8 @@ static size_t decodeURL(const char * src, size_t src_size, char * dst)
} }
else else
{ {
unsigned char high = char_to_digit_table[static_cast<unsigned char>(src_curr_pos[1])]; unsigned char high = unhex(src_curr_pos[1]);
unsigned char low = char_to_digit_table[static_cast<unsigned char>(src_curr_pos[2])]; unsigned char low = unhex(src_curr_pos[2]);
if (high != 0xFF && low != 0xFF) if (high != 0xFF && low != 0xFF)
{ {

View File

@ -258,7 +258,7 @@ struct ExtractTopLevelDomain
if (!last_dot) if (!last_dot)
return; return;
/// Для IPv4-адресов не выделяем ничего. /// For IPv4 addresses select nothing.
if (last_dot[1] <= '9') if (last_dot[1] <= '9')
return; return;
@ -380,7 +380,7 @@ struct ExtractQueryStringAndFragment
} }
}; };
/// С точкой на конце. /// With dot at the end.
struct ExtractWWW struct ExtractWWW
{ {
static void execute(Pos data, size_t size, Pos & res_data, size_t & res_size) static void execute(Pos data, size_t size, Pos & res_data, size_t & res_size)
@ -526,11 +526,11 @@ struct CutURLParameterImpl
begin_pos = pos; begin_pos = pos;
end_pos = begin_pos + param_len; end_pos = begin_pos + param_len;
/// Пропустим значение. /// Skip the value.
while (*end_pos && *end_pos != '&' && *end_pos != '#') while (*end_pos && *end_pos != '&' && *end_pos != '#')
++end_pos; ++end_pos;
/// Захватим '&' до или после параметра. /// Capture '&' before or after the parameter.
if (*end_pos == '&') if (*end_pos == '&')
++end_pos; ++end_pos;
else if (begin_pos[-1] == '&') else if (begin_pos[-1] == '&')
@ -573,13 +573,13 @@ public:
void init(Block & block, const ColumnNumbers & arguments) {} void init(Block & block, const ColumnNumbers & arguments) {}
/// Возвращает позицию аргумента, являющегося столбцом строк /// Returns the position of the argument that is the column of rows
size_t getStringsArgumentPosition() size_t getStringsArgumentPosition()
{ {
return 0; return 0;
} }
/// Вызывается для каждой следующей строки. /// Called for each next string.
void set(Pos pos_, Pos end_) void set(Pos pos_, Pos end_)
{ {
pos = pos_; pos = pos_;
@ -587,7 +587,7 @@ public:
first = true; first = true;
} }
/// Получить следующий токен, если есть, или вернуть false. /// Get the next token, if any, or return false.
bool get(Pos & token_begin, Pos & token_end) bool get(Pos & token_begin, Pos & token_end)
{ {
if (pos == nullptr) if (pos == nullptr)
@ -656,7 +656,7 @@ public:
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
} }
/// Возвращает позицию аргумента, являющегося столбцом строк /// Returns the position of the argument that is the column of rows
size_t getStringsArgumentPosition() size_t getStringsArgumentPosition()
{ {
return 0; return 0;
@ -664,7 +664,7 @@ public:
void init(Block & block, const ColumnNumbers & arguments) {} void init(Block & block, const ColumnNumbers & arguments) {}
/// Вызывается для каждой следующей строки. /// Called for each next string.
void set(Pos pos_, Pos end_) void set(Pos pos_, Pos end_)
{ {
pos = pos_; pos = pos_;
@ -672,7 +672,7 @@ public:
first = true; first = true;
} }
/// Получить следующий токен, если есть, или вернуть false. /// Get the next token, if any, or return false.
bool get(Pos & token_begin, Pos & token_end) bool get(Pos & token_begin, Pos & token_end)
{ {
if (pos == nullptr) if (pos == nullptr)
@ -735,38 +735,37 @@ public:
void init(Block & block, const ColumnNumbers & arguments) {} void init(Block & block, const ColumnNumbers & arguments) {}
/// Возвращает позицию аргумента, являющегося столбцом строк /// Returns the position of the argument that is the column of rows
size_t getStringsArgumentPosition() size_t getStringsArgumentPosition()
{ {
return 0; return 0;
} }
/// Вызывается для каждой следующей строки. /// Called for each next string.
void set(Pos pos_, Pos end_) void set(Pos pos_, Pos end_)
{ {
begin = pos = pos_; begin = pos = pos_;
end = end_; end = end_;
} }
/// Получить следующий токен, если есть, или вернуть false. /// Get the next token, if any, or return false.
bool get(Pos & token_begin, Pos & token_end) bool get(Pos & token_begin, Pos & token_end)
{ {
/// Код из URLParser. /// Code from URLParser.
if (pos == end) if (pos == end)
return false; return false;
if (pos == begin) if (pos == begin)
{ {
/// Распарсим всё, что идёт до пути /// Let's parse everything that goes before the path
/// Предположим, что протокол уже переведён в нижний регистр. /// Assume that the protocol has already been changed to lowercase.
while (pos < end && ((*pos > 'a' && *pos < 'z') || (*pos > '0' && *pos < '9'))) while (pos < end && ((*pos > 'a' && *pos < 'z') || (*pos > '0' && *pos < '9')))
++pos; ++pos;
/** Будем вычислять иерархию только для URL-ов, в которых есть протокол, и после него идут два слеша. /** We will calculate the hierarchy only for URLs in which there is a protocol, and after it there are two slashes.
* (http, file - подходят, mailto, magnet - не подходят), и после двух слешей ещё хоть что-нибудь есть * (http, file - fit, mailto, magnet - do not fit), and after two slashes still at least something is there
* Для остальных просто вернём полный URL как единственный элемент иерархии. * For the rest, simply return the full URL as the only element of the hierarchy.
*/ */
if (pos == begin || pos == end || !(*pos++ == ':' && pos < end && *pos++ == '/' && pos < end && *pos++ == '/' && pos < end)) if (pos == begin || pos == end || !(*pos++ == ':' && pos < end && *pos++ == '/' && pos < end && *pos++ == '/' && pos < end))
{ {
@ -776,7 +775,7 @@ public:
return true; return true;
} }
/// Доменом для простоты будем считать всё, что после протокола и двух слешей, до следующего слеша или до ? или до # /// The domain for simplicity is everything that after the protocol and two slashes, until the next slash or `?` or `#`
while (pos < end && !(*pos == '/' || *pos == '?' || *pos == '#')) while (pos < end && !(*pos == '/' || *pos == '?' || *pos == '#'))
++pos; ++pos;
@ -789,7 +788,7 @@ public:
return true; return true;
} }
/// Идём до следующего / или ? или #, пропуская все те, что вначале. /// We go to the next `/` or `?` or `#`, skipping all those at the beginning.
while (pos < end && (*pos == '/' || *pos == '?' || *pos == '#')) while (pos < end && (*pos == '/' || *pos == '?' || *pos == '#'))
++pos; ++pos;
if (pos == end) if (pos == end)
@ -831,13 +830,13 @@ public:
void init(Block & block, const ColumnNumbers & arguments) {} void init(Block & block, const ColumnNumbers & arguments) {}
/// Возвращает позицию аргумента, являющегося столбцом строк /// Returns the position of the argument that is the column of rows
size_t getStringsArgumentPosition() size_t getStringsArgumentPosition()
{ {
return 0; return 0;
} }
/// Вызывается для каждой следующей строки. /// Called for each next string.
void set(Pos pos_, Pos end_) void set(Pos pos_, Pos end_)
{ {
begin = pos = pos_; begin = pos = pos_;
@ -845,25 +844,25 @@ public:
end = end_; end = end_;
} }
/// Получить следующий токен, если есть, или вернуть false. /// Get the next token, if any, or return false.
bool get(Pos & token_begin, Pos & token_end) bool get(Pos & token_begin, Pos & token_end)
{ {
/// Код из URLParser. /// Code from URLParser.
if (pos == end) if (pos == end)
return false; return false;
if (pos == begin) if (pos == begin)
{ {
/// Распарсим всё, что идёт до пути /// Let's parse everything that goes before the path
/// Предположим, что протокол уже переведён в нижний регистр. /// Assume that the protocol has already been changed to lowercase.
while (pos < end && ((*pos > 'a' && *pos < 'z') || (*pos > '0' && *pos < '9'))) while (pos < end && ((*pos > 'a' && *pos < 'z') || (*pos > '0' && *pos < '9')))
++pos; ++pos;
/** Будем вычислять иерархию только для URL-ов, в которых есть протокол, и после него идут два слеша. /** We will calculate the hierarchy only for URLs in which there is a protocol, and after it there are two slashes.
* (http, file - подходят, mailto, magnet - не подходят), и после двух слешей ещё хоть что-нибудь есть * (http, file - fit, mailto, magnet - do not fit), and after two slashes still at least something is there.
* Для остальных просто вернём пустой массив. * For the rest, just return an empty array.
*/ */
if (pos == begin || pos == end || !(*pos++ == ':' && pos < end && *pos++ == '/' && pos < end && *pos++ == '/' && pos < end)) if (pos == begin || pos == end || !(*pos++ == ':' && pos < end && *pos++ == '/' && pos < end && *pos++ == '/' && pos < end))
{ {
@ -871,7 +870,7 @@ public:
return false; return false;
} }
/// Доменом для простоты будем считать всё, что после протокола и двух слешей, до следующего слеша или до ? или до # /// The domain for simplicity is everything that after the protocol and the two slashes, until the next slash or `?` or `#`
while (pos < end && !(*pos == '/' || *pos == '?' || *pos == '#')) while (pos < end && !(*pos == '/' || *pos == '?' || *pos == '#'))
++pos; ++pos;
@ -881,7 +880,7 @@ public:
++pos; ++pos;
} }
/// Идём до следующего / или ? или #, пропуская все те, что вначале. /// We go to the next `/` or `?` or `#`, skipping all those at the beginning.
while (pos < end && (*pos == '/' || *pos == '?' || *pos == '#')) while (pos < end && (*pos == '/' || *pos == '?' || *pos == '#'))
++pos; ++pos;
if (pos == end) if (pos == end)
@ -900,7 +899,7 @@ public:
}; };
/** Выделить кусок строки, используя Extractor. /** Select part of string using the Extractor.
*/ */
template <typename Extractor> template <typename Extractor>
struct ExtractSubstringImpl struct ExtractSubstringImpl
@ -915,7 +914,7 @@ struct ExtractSubstringImpl
size_t prev_offset = 0; size_t prev_offset = 0;
size_t res_offset = 0; size_t res_offset = 0;
/// Выделенный кусок. /// Matched part.
Pos start; Pos start;
size_t length; size_t length;
@ -950,7 +949,7 @@ struct ExtractSubstringImpl
}; };
/** Удалить кусок строки, используя Extractor. /** Delete part of string using the Extractor.
*/ */
template <typename Extractor> template <typename Extractor>
struct CutSubstringImpl struct CutSubstringImpl
@ -965,7 +964,7 @@ struct CutSubstringImpl
size_t prev_offset = 0; size_t prev_offset = 0;
size_t res_offset = 0; size_t res_offset = 0;
/// Выделенный кусок. /// Matched part.
Pos start; Pos start;
size_t length; size_t length;

View File

@ -10,26 +10,29 @@
#include <Columns/ColumnArray.h> #include <Columns/ColumnArray.h>
#include <Columns/ColumnFixedString.h> #include <Columns/ColumnFixedString.h>
#include <Columns/ColumnConst.h> #include <Columns/ColumnConst.h>
#include <Common/hex.h>
#include <Common/Volnitsky.h> #include <Common/Volnitsky.h>
#include <Functions/IFunction.h> #include <Functions/IFunction.h>
#include <IO/ReadBufferFromMemory.h> #include <IO/ReadBufferFromMemory.h>
#include <IO/ReadHelpers.h> #include <IO/ReadHelpers.h>
/** Функции для извлечения параметров визитов. /** Functions for retrieving "visit parameters".
* Реализованы через шаблоны из FunctionsStringSearch.h. * Visit parameters in Yandex.Metrika are a special kind of JSONs.
* These functions are applicable to almost any JSONs.
* Implemented via templates from FunctionsStringSearch.h.
* *
* Проверить есть ли параметр * Check if there is a parameter
* visitParamHas * visitParamHas
* *
* Извлечь числовое значение параметра * Retrieve the numeric value of the parameter
* visitParamExtractUInt * visitParamExtractUInt
* visitParamExtractInt * visitParamExtractInt
* visitParamExtractFloat * visitParamExtractFloat
* visitParamExtractBool * visitParamExtractBool
* *
* Извлечь строкое значение параметра * Retrieve the string value of the parameter
* visitParamExtractString - значение разэскейпливается * visitParamExtractString - unescape value
* visitParamExtractRaw * visitParamExtractRaw
*/ */
@ -55,7 +58,7 @@ struct ExtractNumericType
{ {
ReadBufferFromMemory in(begin, end - begin); ReadBufferFromMemory in(begin, end - begin);
/// Учимся читать числа в двойных кавычках /// Read numbers in double quotes
if (!in.eof() && *in.position() == '"') if (!in.eof() && *in.position() == '"')
++in.position(); ++in.position();
@ -140,50 +143,12 @@ struct ExtractRaw
struct ExtractString struct ExtractString
{ {
static bool tryParseDigit(UInt8 c, UInt8 & res) static UInt64 unhexCodePoint(const UInt8 * pos)
{ {
if ('0' <= c && c <= '9') return unhex(pos[0]) * 0xFFF
{ + unhex(pos[1]) * 0xFF
res = c - '0'; + unhex(pos[2]) * 0xF
return true; + unhex(pos[3]);
}
if ('A' <= c && c <= 'Z')
{
res = c - ('A' - 10);
return true;
}
if ('a' <= c && c <= 'z')
{
res = c - ('a' - 10);
return true;
}
return false;
}
static bool tryUnhex(const UInt8 * pos, const UInt8 * end, int & res)
{
if (pos + 3 >= end)
return false;
res = 0;
{
UInt8 major, minor;
if (!tryParseDigit(*(pos++), major))
return false;
if (!tryParseDigit(*(pos++), minor))
return false;
res |= (major << 4) | minor;
}
res <<= 8;
{
UInt8 major, minor;
if (!tryParseDigit(*(pos++), major))
return false;
if (!tryParseDigit(*(pos++), minor))
return false;
res |= (major << 4) | minor;
}
return true;
} }
static bool tryExtract(const UInt8 * pos, const UInt8 * end, ColumnString::Chars_t & res_data) static bool tryExtract(const UInt8 * pos, const UInt8 * end, ColumnString::Chars_t & res_data)
@ -231,20 +196,25 @@ struct ExtractString
{ {
++pos; ++pos;
int unicode; if (pos + 4 > end)
if (!tryUnhex(pos, end, unicode))
return false; return false;
UInt16 code_point = unhexCodePoint(pos);
pos += 3; pos += 3;
res_data.resize(res_data.size() + 6); /// максимальный размер UTF8 многобайтовой последовательности static constexpr size_t max_code_point_byte_length = 4;
size_t old_size = res_data.size();
res_data.resize(old_size + max_code_point_byte_length);
Poco::UTF8Encoding utf8; Poco::UTF8Encoding utf8;
int length = utf8.convert(unicode, const_cast<UInt8 *>(&res_data[0]) + res_data.size() - 6, 6); int length = utf8.convert(code_point,
&res_data[old_size], max_code_point_byte_length);
if (!length) if (!length)
return false; return false;
res_data.resize(res_data.size() - 6 + length); res_data.resize(old_size + length);
break; break;
} }
default: default:
@ -274,47 +244,47 @@ struct ExtractString
}; };
/** Ищет вхождения поля в параметре визитов и вызывает ParamExtractor /** Searches for occurrences of a field in the visit parameter and calls ParamExtractor
* на каждое вхождение поля, передавая ему указатель на часть строки, * for each occurrence of the field, passing it a pointer to the part of the string,
* где начинается вхождение значения поля. * where the occurrence of the field value begins.
* ParamExtractor должен распарсить и вернуть значение нужного типа. * ParamExtractor must parse and return the value of the desired type.
* *
* Если поле не было найдено или полю соответствует некорректное значение, * If a field was not found or an incorrect value is associated with the field,
* то используется значение по умолчанию - 0. * then the default value used - 0.
*/ */
template <typename ParamExtractor> template <typename ParamExtractor>
struct ExtractParamImpl struct ExtractParamImpl
{ {
using ResultType = typename ParamExtractor::ResultType; using ResultType = typename ParamExtractor::ResultType;
/// Предполагается, что res нужного размера и инициализирован нулями. /// It is assumed that `res` is the correct size and initialized with zeros.
static void vector_constant(const ColumnString::Chars_t & data, const ColumnString::Offsets_t & offsets, static void vector_constant(const ColumnString::Chars_t & data, const ColumnString::Offsets_t & offsets,
std::string needle, std::string needle,
PaddedPODArray<ResultType> & res) PaddedPODArray<ResultType> & res)
{ {
/// Ищем параметр просто как подстроку вида "name": /// We are looking for a parameter simply as a substring of the form "name"
needle = "\"" + needle + "\":"; needle = "\"" + needle + "\":";
const UInt8 * begin = &data[0]; const UInt8 * begin = &data[0];
const UInt8 * pos = begin; const UInt8 * pos = begin;
const UInt8 * end = pos + data.size(); const UInt8 * end = pos + data.size();
/// Текущий индекс в массиве строк. /// The current index in the string array.
size_t i = 0; size_t i = 0;
Volnitsky searcher(needle.data(), needle.size(), end - pos); Volnitsky searcher(needle.data(), needle.size(), end - pos);
/// Искать будем следующее вхождение сразу во всех строках. /// We will search for the next occurrence in all strings at once.
while (pos < end && end != (pos = searcher.search(pos, end - pos))) while (pos < end && end != (pos = searcher.search(pos, end - pos)))
{ {
/// Определим, к какому индексу оно относится. /// Let's determine which index it belongs to.
while (begin + offsets[i] <= pos) while (begin + offsets[i] <= pos)
{ {
res[i] = 0; res[i] = 0;
++i; ++i;
} }
/// Проверяем, что вхождение не переходит через границы строк. /// We check that the entry does not pass through the boundaries of strings.
if (pos + needle.size() < begin + offsets[i]) if (pos + needle.size() < begin + offsets[i])
res[i] = ParamExtractor::extract(pos + needle.size(), begin + offsets[i]); res[i] = ParamExtractor::extract(pos + needle.size(), begin + offsets[i]);
else else
@ -358,7 +328,7 @@ struct ExtractParamImpl
}; };
/** Для случая когда тип поля, которое нужно извлечь - строка. /** For the case where the type of field to extract is a string.
*/ */
template<typename ParamExtractor> template<typename ParamExtractor>
struct ExtractParamToStringImpl struct ExtractParamToStringImpl
@ -367,26 +337,26 @@ struct ExtractParamToStringImpl
std::string needle, std::string needle,
ColumnString::Chars_t & res_data, ColumnString::Offsets_t & res_offsets) ColumnString::Chars_t & res_data, ColumnString::Offsets_t & res_offsets)
{ {
/// Константа 5 взята из функции, выполняющей похожую задачу FunctionsStringSearch.h::ExtractImpl /// Constant 5 is taken from a function that performs a similar task FunctionsStringSearch.h::ExtractImpl
res_data.reserve(data.size() / 5); res_data.reserve(data.size() / 5);
res_offsets.resize(offsets.size()); res_offsets.resize(offsets.size());
/// Ищем параметр просто как подстроку вида "name": /// We are looking for a parameter simply as a substring of the form "name"
needle = "\"" + needle + "\":"; needle = "\"" + needle + "\":";
const UInt8 * begin = &data[0]; const UInt8 * begin = &data[0];
const UInt8 * pos = begin; const UInt8 * pos = begin;
const UInt8 * end = pos + data.size(); const UInt8 * end = pos + data.size();
/// Текущий индекс в массиве строк. /// The current index in the string array.
size_t i = 0; size_t i = 0;
Volnitsky searcher(needle.data(), needle.size(), end - pos); Volnitsky searcher(needle.data(), needle.size(), end - pos);
/// Искать будем следующее вхождение сразу во всех строках. /// We will search for the next occurrence in all strings at once.
while (pos < end && end != (pos = searcher.search(pos, end - pos))) while (pos < end && end != (pos = searcher.search(pos, end - pos)))
{ {
/// Определим, к какому индексу оно относится. /// Determine which index it belongs to.
while (begin + offsets[i] <= pos) while (begin + offsets[i] <= pos)
{ {
res_data.push_back(0); res_data.push_back(0);
@ -394,7 +364,7 @@ struct ExtractParamToStringImpl
++i; ++i;
} }
/// Проверяем, что вхождение не переходит через границы строк. /// We check that the entry does not pass through the boundaries of strings.
if (pos + needle.size() < begin + offsets[i]) if (pos + needle.size() < begin + offsets[i])
ParamExtractor::extract(pos + needle.size(), begin + offsets[i], res_data); ParamExtractor::extract(pos + needle.size(), begin + offsets[i], res_data);

View File

@ -24,29 +24,29 @@ namespace ErrorCodes
struct ExpressionAction; struct ExpressionAction;
/** Интерфейс для обычных функций. /** Interface for normal functions.
* Обычные функции - это функции, которые не меняют количество строк в таблице, * Normal functions are functions that do not change the number of rows in the table,
* и результат работы которых для каждой строчки не зависит от других строк. * and the result of which for each row does not depend on other rows.
* *
* Функция может принимать произвольное количество аргументов; возвращает ровно одно значение. * A function can take an arbitrary number of arguments; returns exactly one value.
* Тип результата зависит от типов и количества аргументов. * The type of the result depends on the type and number of arguments.
* *
* Функция диспетчеризуется для целого блока. Это позволяет производить всевозможные проверки редко, * The function is dispatched for the whole block. This allows you to perform all kinds of checks rarely,
* и делать основную работу в виде эффективного цикла. * and do the main job as an efficient loop.
* *
* Функция применяется к одному или нескольким столбцам блока, и записывает свой результат, * The function is applied to one or more columns of the block, and writes its result,
* добавляя новый столбец к блоку. Функция не модифицирует свои агрументы. * adding a new column to the block. The function does not modify its arguments.
*/ */
class IFunction class IFunction
{ {
public: public:
/** Наследник IFunction должен реализовать: /** The successor of IFunction must implement:
* - getName * - getName
* - либо getReturnType, либо getReturnTypeAndPrerequisites * - either getReturnType, or getReturnTypeAndPrerequisites
* - одну из перегрузок execute. * - one of the overloads of `execute`.
*/ */
/// Получить основное имя функции. /// Get the main function name.
virtual String getName() const = 0; virtual String getName() const = 0;
/// Override and return true if function could take different number of arguments. /// Override and return true if function could take different number of arguments.
@ -97,8 +97,8 @@ public:
*/ */
virtual bool isDeterministicInScopeOfQuery() { return true; } virtual bool isDeterministicInScopeOfQuery() { return true; }
/// Получить тип результата по типам аргументов. Если функция неприменима для данных аргументов - кинуть исключение. /// Get the result type by argument type. If the function does not apply to these arguments, throw an exception.
/// Перегрузка для тех, кому не нужны prerequisites и значения константных аргументов. Снаружи не вызывается. /// Overloading for those who do not need prerequisites and values of constant arguments. Not called from outside.
DataTypePtr getReturnType(const DataTypes & arguments) const; DataTypePtr getReturnType(const DataTypes & arguments) const;
virtual DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const virtual DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const
@ -106,11 +106,11 @@ public:
throw Exception("getReturnType is not implemented for " + getName(), ErrorCodes::NOT_IMPLEMENTED); throw Exception("getReturnType is not implemented for " + getName(), ErrorCodes::NOT_IMPLEMENTED);
} }
/** Получить тип результата по типам аргументов и значениям константных аргументов. /** Get the result type by argument types and constant argument values.
* Если функция неприменима для данных аргументов - кинуть исключение. * If the function does not apply to these arguments, throw an exception.
* Еще можно вернуть описание дополнительных столбцов, которые требуются для выполнения функции. * You can also return a description of the additional columns that are required to perform the function.
* Для неконстантных столбцов arguments[i].column = nullptr. * For non-constant columns `arguments[i].column = nullptr`.
* Осмысленные типы элементов в out_prerequisites: APPLY_FUNCTION, ADD_COLUMN. * Meaningful element types in out_prerequisites: APPLY_FUNCTION, ADD_COLUMN.
*/ */
void getReturnTypeAndPrerequisites( void getReturnTypeAndPrerequisites(
const ColumnsWithTypeAndName & arguments, const ColumnsWithTypeAndName & arguments,
@ -138,12 +138,12 @@ public:
throw Exception("Function " + getName() + " can't have lambda-expressions as arguments", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); throw Exception("Function " + getName() + " can't have lambda-expressions as arguments", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
} }
/// Выполнить функцию над блоком. Замечание: может вызываться одновременно из нескольких потоков, для одного объекта. /// Execute the function on the block. Note: can be called simultaneously from several threads, for one object.
/// Перегрузка для тех, кому не нужны prerequisites. Снаружи не вызывается. /// Overloading for those who do not need `prerequisites`. Not called from outside.
void execute(Block & block, const ColumnNumbers & arguments, size_t result); void execute(Block & block, const ColumnNumbers & arguments, size_t result);
/// Выполнить функцию над блоком. Замечание: может вызываться одновременно из нескольких потоков, для одного объекта. /// Execute the function above the block. Note: can be called simultaneously from several threads, for one object.
/// prerequisites идут в том же порядке, что и out_prerequisites, полученные из getReturnTypeAndPrerequisites. /// `prerequisites` go in the same order as `out_prerequisites` obtained from getReturnTypeAndPrerequisites.
void execute(Block & block, const ColumnNumbers & arguments, const ColumnNumbers & prerequisites, size_t result); void execute(Block & block, const ColumnNumbers & arguments, const ColumnNumbers & prerequisites, size_t result);
virtual void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) virtual void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result)
@ -160,25 +160,25 @@ public:
/// that correspond to nullable columns and null columns. /// that correspond to nullable columns and null columns.
virtual bool hasSpecialSupportForNulls() const { return false; } virtual bool hasSpecialSupportForNulls() const { return false; }
/** Позволяет узнать, является ли функция монотонной в некотором диапазоне значений. /** Lets you know if the function is monotonic in a range of values.
* Это используется для работы с индексом в сортированном куске данных. * This is used to work with the index in a sorted chunk of data.
* И позволяет использовать индекс не только, когда написано, например date >= const, но и, например, toMonth(date) >= 11. * And allows to use the index not only when it is written, for example `date >= const`, but also, for example, `toMonth(date) >= 11`.
* Всё это рассматривается только для функций одного аргумента. * All this is considered only for functions of one argument.
*/ */
virtual bool hasInformationAboutMonotonicity() const { return false; } virtual bool hasInformationAboutMonotonicity() const { return false; }
/// Свойство монотонности на некотором диапазоне. /// The property of monotonicity for a certain range.
struct Monotonicity struct Monotonicity
{ {
bool is_monotonic = false; /// Является ли функция монотонной (неубывающей или невозрастающей). bool is_monotonic = false; /// Is the function monotonous (nondecreasing or nonincreasing).
bool is_positive = true; /// true, если функция неубывающая, false, если невозрастающая. Если is_monotonic = false, то не важно. bool is_positive = true; /// true if the function is nondecreasing, false, if notincreasing. If is_monotonic = false, then it does not matter.
Monotonicity(bool is_monotonic_ = false, bool is_positive_ = true) Monotonicity(bool is_monotonic_ = false, bool is_positive_ = true)
: is_monotonic(is_monotonic_), is_positive(is_positive_) {} : is_monotonic(is_monotonic_), is_positive(is_positive_) {}
}; };
/** Получить информацию о монотонности на отрезке значений. Вызывайте только если hasInformationAboutMonotonicity. /** Get information about monotonicity on a range of values. Call only if hasInformationAboutMonotonicity.
* В качестве одного из аргументов может быть передан NULL. Это значит, что соответствующий диапазон неограничен слева или справа. * NULL can be passed as one of the arguments. This means that the corresponding range is unlimited on the left or on the right.
*/ */
virtual Monotonicity getMonotonicityForRange(const IDataType & type, const Field & left, const Field & right) const virtual Monotonicity getMonotonicityForRange(const IDataType & type, const Field & left, const Field & right) const
{ {

View File

@ -18,8 +18,8 @@
namespace DB namespace DB
{ {
/** Позволяет получить тип результата применения функций +, -, *, /, %, div (целочисленное деление). /** Allows get the result type of the functions +, -, *, /, %, div (integer division).
* Правила отличаются от используемых в C++. * The rules are different from those used in C++.
*/ */
namespace NumberTraits namespace NumberTraits
@ -162,11 +162,11 @@ struct UpdateNullity
>::Type; >::Type;
}; };
/** Результат сложения или умножения вычисляется по следующим правилам: /** The result of addition or multiplication is calculated according to the following rules:
* - если один из аргументов с плавающей запятой, то результат - с плавающей запятой, иначе - целый; * - if one of the arguments is floating-point, the result is a floating point, otherwise - the whole;
* - если одно из аргументов со знаком, то результат - со знаком, иначе - без знака; * - if one of the arguments is signed, the result is signed, otherwise it is unsigned;
* - результат содержит больше бит (не только значащих), чем максимум в аргументах * - the result contains more bits (not only meaningful) than the maximum in the arguments
* (например, UInt8 + Int32 = Int64). * (for example, UInt8 + Int32 = Int64).
*/ */
template <typename A, typename B> struct ResultOfAdditionMultiplication template <typename A, typename B> struct ResultOfAdditionMultiplication
{ {
@ -186,14 +186,14 @@ template <typename A, typename B> struct ResultOfSubtraction
typename boost::mpl::or_<typename Traits<A>::Nullity, typename Traits<B>::Nullity>::type>::Type Type; typename boost::mpl::or_<typename Traits<A>::Nullity, typename Traits<B>::Nullity>::type>::Type Type;
}; };
/** При делении всегда получается число с плавающей запятой. /** When dividing, you always get a floating-point number.
*/ */
template <typename A, typename B> struct ResultOfFloatingPointDivision template <typename A, typename B> struct ResultOfFloatingPointDivision
{ {
using Type = Float64; using Type = Float64;
}; };
/** При целочисленном делении получается число, битность которого равна делимому. /** For integer division, we get a number with the same number of bits as in divisible.
*/ */
template <typename A, typename B> struct ResultOfIntegerDivision template <typename A, typename B> struct ResultOfIntegerDivision
{ {
@ -204,7 +204,7 @@ template <typename A, typename B> struct ResultOfIntegerDivision
typename boost::mpl::or_<typename Traits<A>::Nullity, typename Traits<B>::Nullity>::type>::Type Type; typename boost::mpl::or_<typename Traits<A>::Nullity, typename Traits<B>::Nullity>::type>::Type Type;
}; };
/** При взятии остатка получается число, битность которого равна делителю. /** Division with remainder you get a number with the same number of bits as in divisor.
*/ */
template <typename A, typename B> struct ResultOfModulo template <typename A, typename B> struct ResultOfModulo
{ {
@ -236,7 +236,7 @@ template <typename A> struct ResultOfAbs
typename Traits<A>::Nullity>::Type Type; typename Traits<A>::Nullity>::Type Type;
}; };
/** При побитовых операциях получается целое число, битность которого равна максимальной из битностей аргументов. /** For bitwise operations, an integer is obtained with number of bits is equal to the maximum of the arguments.
*/ */
template <typename A, typename B> struct ResultOfBit template <typename A, typename B> struct ResultOfBit
{ {
@ -265,7 +265,7 @@ template <typename A> struct ResultOfBitNot
}; };
/** Приведение типов для функции if: /** Type casting for `if` function:
* 1) void, Type -> Type * 1) void, Type -> Type
* 2) UInt<x>, UInt<y> -> UInt<max(x,y)> * 2) UInt<x>, UInt<y> -> UInt<max(x,y)>
* 3) Int<x>, Int<y> -> Int<max(x,y)> * 3) Int<x>, Int<y> -> Int<max(x,y)>
@ -294,7 +294,7 @@ struct ResultOfIf
typename Construct< typename Construct<
Signed, Signed,
Floating, Floating,
typename boost::mpl::max< /// Этот максимум нужен только потому что if_ всегда вычисляет все аргументы. typename boost::mpl::max< /// This maximum is needed only because `if_` always evaluates all arguments.
typename boost::mpl::max< typename boost::mpl::max<
typename boost::mpl::if_< typename boost::mpl::if_<
typename Traits<A>::Floatness, typename Traits<A>::Floatness,
@ -334,7 +334,7 @@ struct ResultOfIf
>::Type>::type>::type>::type>::type Type; >::Type>::type>::type>::type>::type Type;
}; };
/** Перед применением оператора % и побитовых операций, операнды приводятся к целым числам. */ /** Before applying operator `%` and bitwise operations, operands are casted to whole numbers. */
template <typename A> struct ToInteger template <typename A> struct ToInteger
{ {
typedef typename Construct< typedef typename Construct<

View File

@ -12,17 +12,17 @@ namespace DB
{ {
/** Записывает данные асинхронно с помощью двойной буферизации. /** Writes data asynchronously using double buffering.
*/ */
class AsynchronousWriteBuffer : public WriteBuffer class AsynchronousWriteBuffer : public WriteBuffer
{ {
private: private:
WriteBuffer & out; /// Основной буфер, отвечает за запись данных. WriteBuffer & out; /// The main buffer, responsible for writing data.
std::vector<char> memory; /// Кусок памяти для дублирования буфера. std::vector <char> memory; /// A piece of memory for duplicating the buffer.
ThreadPool pool; /// Для асинхронной записи данных. ThreadPool pool; /// For asynchronous data writing.
bool started; /// Была ли запущена асинхронная запись данных. bool started; /// Has an asynchronous data write started?
/// Менять местами основной и дублирующий буферы. /// Swap the main and duplicate buffers.
void swapBuffers() void swapBuffers()
{ {
buffer().swap(out.buffer()); buffer().swap(out.buffer());
@ -41,14 +41,14 @@ private:
swapBuffers(); swapBuffers();
/// Данные будут записываться в отельном потоке. /// The data will be written in separate stream.
pool.schedule([this] { thread(); }); pool.schedule([this] { thread(); });
} }
public: public:
AsynchronousWriteBuffer(WriteBuffer & out_) : WriteBuffer(nullptr, 0), out(out_), memory(out.buffer().size()), pool(1), started(false) AsynchronousWriteBuffer(WriteBuffer & out_) : WriteBuffer(nullptr, 0), out(out_), memory(out.buffer().size()), pool(1), started(false)
{ {
/// Данные пишутся в дублирующий буфер. /// Data is written to the duplicate buffer.
set(memory.data(), memory.size()); set(memory.data(), memory.size());
} }
@ -68,7 +68,7 @@ public:
} }
} }
/// То, что выполняется в отдельном потоке /// That is executed in a separate thread
void thread() void thread()
{ {
out.next(); out.next();

View File

@ -8,30 +8,30 @@ namespace DB
{ {
/** Базовый класс для ReadBuffer и WriteBuffer. /** Base class for ReadBuffer and WriteBuffer.
* Содержит общие типы, переменные и функции. * Contains mutual types, variables, and functions.
* *
* ReadBuffer и WriteBuffer похожи на istream и ostream, соответственно. * ReadBuffer and WriteBuffer are similar to istream and ostream, respectively.
* Их приходится использовать, так как с использованием iostream-ов невозможно эффективно реализовать некоторые операции. * They have to be used, because using iostreams it is impossible to effectively implement some operations.
* Например, используя istream, невозможно быстро читать строковые значения из tab-separated файла, * For example, using istream, you can not quickly read string values from a tab-separated file,
* чтобы после чтения, позиция осталась сразу после считанного значения. * so that after reading, the position remains immediately after the read value.
* (Единственный вариант - вызывать функцию std::istream::get() на каждый байт, но это тормозит из-за нескольких виртуальных вызовов.) * (The only option is to call the std::istream::get() function on each byte, but this slows down due to several virtual calls.)
* *
* Read/WriteBuffer-ы предоставляют прямой доступ к внутреннему буферу, поэтому, необходимые операции реализуются эффективнее. * Read/WriteBuffers provide direct access to the internal buffer, so the necessary operations are implemented more efficiently.
* Используется только одна виртуальная функция nextImpl(), которая вызывается редко: * Only one virtual function nextImpl() is used, which is rarely called:
* - в случае ReadBuffer - заполнить буфер новыми данными из источика; * - in the case of ReadBuffer - fill in the buffer with new data from the source;
* - в случае WriteBuffer - записать данные из буфера в приёмник. * - in the case of WriteBuffer - write data from the buffer into the receiver.
* *
* Read/WriteBuffer-ы могут владеть или не владеть своим куском памяти. * Read/WriteBuffer can own or not own an own piece of memory.
* Во втором случае, можно эффективно читать из уже существующего куска памяти / std::string, не копируя его. * In the second case, you can effectively read from an already existing piece of memory / std::string without copying it.
*/ */
class BufferBase class BufferBase
{ {
public: public:
/** Курсор в буфере. Позиция записи или чтения. */ /** Cursor in the buffer. The position of write or read. */
using Position = char *; using Position = char *;
/** Ссылка на диапазон памяти. */ /** A reference to the range of memory. */
struct Buffer struct Buffer
{ {
Buffer(Position begin_pos_, Position end_pos_) : begin_pos(begin_pos_), end_pos(end_pos_) {} Buffer(Position begin_pos_, Position end_pos_) : begin_pos(begin_pos_), end_pos(end_pos_) {}
@ -49,11 +49,11 @@ public:
private: private:
Position begin_pos; Position begin_pos;
Position end_pos; /// на 1 байт после конца буфера Position end_pos; /// 1 byte after the end of the buffer
}; };
/** Конструктор принимает диапазон памяти, который следует использовать под буфер. /** The constructor takes a range of memory to use for the buffer.
* offset - начальное место курсора. ReadBuffer должен установить его в конец диапазона, а WriteBuffer - в начало. * offset - the starting point of the cursor. ReadBuffer must set it to the end of the range, and WriteBuffer - to the beginning.
*/ */
BufferBase(Position ptr, size_t size, size_t offset) BufferBase(Position ptr, size_t size, size_t offset)
: internal_buffer(ptr, ptr + size), working_buffer(ptr, ptr + size), pos(ptr + offset) {} : internal_buffer(ptr, ptr + size), working_buffer(ptr, ptr + size), pos(ptr + offset) {}
@ -65,19 +65,19 @@ public:
pos = ptr + offset; pos = ptr + offset;
} }
/// получить буфер /// get buffer
inline Buffer & internalBuffer() { return internal_buffer; } inline Buffer & internalBuffer() { return internal_buffer; }
/// получить часть буфера, из которого можно читать / в который можно писать данные /// get the part of the buffer from which you can read / write data
inline Buffer & buffer() { return working_buffer; } inline Buffer & buffer() { return working_buffer; }
/// получить (для чтения и изменения) позицию в буфере /// get (for reading and modifying) the position in the buffer
inline Position & position() { return pos; }; inline Position & position() { return pos; };
/// смещение в байтах курсора от начала буфера /// offset in bytes of the cursor from the beginning of the buffer
inline size_t offset() const { return pos - working_buffer.begin(); } inline size_t offset() const { return pos - working_buffer.begin(); }
/** Сколько байт было прочитано/записано, считая те, что ещё в буфере. */ /** How many bytes have been read/written, counting those that are still in the buffer. */
size_t count() const size_t count() const
{ {
return bytes + offset(); return bytes + offset();
@ -90,21 +90,21 @@ public:
} }
protected: protected:
/// Ссылка на кусок памяти для буфера. /// A reference to a piece of memory for the buffer.
Buffer internal_buffer; Buffer internal_buffer;
/** Часть куска памяти, которую можно использовать. /** A piece of memory that you can use.
* Например, если internal_buffer - 1MB, а из файла для чтения было загружено в буфер * For example, if internal_buffer is 1MB, and from a file for reading it was loaded into the buffer
* только 10 байт, то working_buffer будет иметь размер 10 байт * only 10 bytes, then working_buffer will be 10 bytes in size
* (working_buffer.end() будет указывать на позицию сразу после тех 10 байт, которых можно прочитать). * (working_buffer.end() will point to the position immediately after the 10 bytes that can be read).
*/ */
Buffer working_buffer; Buffer working_buffer;
/// Позиция чтения/записи. /// Read/write position.
Position pos; Position pos;
/** Сколько байт было прочитано/записано, не считая тех, что сейчас в буфере. /** How many bytes have been read/written, not counting those that are now in the buffer.
* (считая те, что были уже использованы и "удалены" из буфера) * (counting those that were already used and "removed" from the buffer)
*/ */
size_t bytes = 0; size_t bytes = 0;
}; };

View File

@ -12,11 +12,11 @@ namespace DB
{ {
/** Буфер для чтения из сжатого файла с использованием кэша разжатых блоков. /** A buffer for reading from a compressed file using the cache of decompressed blocks.
* Кэш внешний - передаётся в качестве аргумента в конструктор. * The external cache is passed as an argument to the constructor.
* Позволяет увеличить производительность в случае, когда часто читаются одни и те же блоки. * Allows you to increase performance in cases where the same blocks are often read.
* Недостатки: * Disadvantages:
* - в случае, если нужно читать много данных подряд, но из них только часть закэширована, приходится делать seek-и. * - in case you need to read a lot of data in a row, but of them only a part is cached, you have to do seek-and.
*/ */
class CachedCompressedReadBuffer : public CompressedReadBufferBase, public ReadBuffer class CachedCompressedReadBuffer : public CompressedReadBufferBase, public ReadBuffer
{ {
@ -30,13 +30,13 @@ private:
std::unique_ptr<ReadBufferFromFileBase> file_in; std::unique_ptr<ReadBufferFromFileBase> file_in;
size_t file_pos; size_t file_pos;
/// Кусок данных из кэша, или кусок считанных данных, который мы положим в кэш. /// A piece of data from the cache, or a piece of read data that we put into the cache.
UncompressedCache::MappedPtr owned_cell; UncompressedCache::MappedPtr owned_cell;
void initInput(); void initInput();
bool nextImpl() override; bool nextImpl() override;
/// Передаётся в file_in. /// Passed into file_in.
ReadBufferFromFileBase::ProfileCallback profile_callback; ReadBufferFromFileBase::ProfileCallback profile_callback;
clockid_t clock_type; clockid_t clock_type;

View File

@ -23,7 +23,7 @@ public:
size_t readBig(char * to, size_t n) override; size_t readBig(char * to, size_t n) override;
/// Сжатый размер текущего блока. /// The compressed size of the current block.
size_t getSizeCompressed() const size_t getSizeCompressed() const
{ {
return size_compressed; return size_compressed;

View File

@ -11,16 +11,16 @@ namespace DB
{ {
/// В отличие от CompressedReadBuffer, умеет делать seek. /// Unlike CompressedReadBuffer, it can do seek.
class CompressedReadBufferFromFile : public CompressedReadBufferBase, public BufferWithOwnMemory<ReadBuffer> class CompressedReadBufferFromFile : public CompressedReadBufferBase, public BufferWithOwnMemory<ReadBuffer>
{ {
private: private:
/** В любой момент выполняется одно из двух: /** At any time, one of two things is true:
* a) size_compressed = 0 * a) size_compressed = 0
* b) * b)
* - working_buffer содержит целиком один блок. * - `working_buffer` contains the entire block.
* - file_in смотрит в конец этого блока. * - `file_in` points to the end of this block.
* - size_compressed содержит сжатый размер этого блока. * - `size_compressed` contains the compressed size of this block.
*/ */
std::unique_ptr<ReadBufferFromFileBase> p_file_in; std::unique_ptr<ReadBufferFromFileBase> p_file_in;
ReadBufferFromFileBase & file_in; ReadBufferFromFileBase & file_in;

View File

@ -2,7 +2,7 @@
#include <cstdint> #include <cstdint>
/** Общие дефайны */ /** Common Defines */
#define DBMS_MAX_COMPRESSED_SIZE 0x40000000ULL /// 1GB #define DBMS_MAX_COMPRESSED_SIZE 0x40000000ULL /// 1GB
@ -13,42 +13,42 @@
namespace DB namespace DB
{ {
/** Метод сжатия */ /** Compression method */
enum class CompressionMethod enum class CompressionMethod
{ {
QuickLZ = 0, QuickLZ = 0,
LZ4 = 1, LZ4 = 1,
LZ4HC = 2, /// Формат такой же, как у LZ4. Разница только при сжатии. LZ4HC = 2, /// The format is the same as for LZ4. The difference is only in compression.
ZSTD = 3, /// Экспериментальный алгоритм: https://github.com/Cyan4973/zstd ZSTD = 3, /// Experimental algorithm: https://github.com/Cyan4973/zstd
}; };
/** Формат сжатого блока следующий: /** The compressed block format is as follows:
* *
* Первые 16 байт - чексумма от всех остальных байт блока. Сейчас используется только CityHash128. * The first 16 bytes are the checksum from all other bytes of the block. Now only CityHash128 is used.
* В дальнейшем можно предусмотреть другие чексуммы, хотя сделать их другого размера не получится. * In the future, you can provide other checksums, although it will not be possible to make them different in size.
* *
* Следующий байт определяет алгоритм сжатия. Далее всё зависит от алгоритма. * The next byte specifies the compression algorithm. Then everything depends on the algorithm.
* *
* Первые 4 варианта совместимы с QuickLZ level 1. * The first 4 options are compatible with QuickLZ level 1.
* То есть, если значение первого байта < 4, для разжатия достаточно использовать функцию qlz_level1_decompress. * That is, if the value of the first byte is < 4, it is enough to use qlz_level1_decompress function to decompress.
* *
* 0x00 - несжатые данные, маленький блок. Далее один байт - размер сжатых данных, с учётом заголовка; один байт - размер несжатых данных. * 0x00 - uncompressed data, small block. Next, one byte - compressed data size, including header; one byte - uncompressed data size.
* 0x01 - сжатые данные, QuickLZ level 1, маленький блок. Далее два байта аналогично. * 0x01 - compressed data, QuickLZ level 1, small block. Then two bytes are similar.
* 0x02 - несжатые данные, большой блок. Далее 4 байта - размер сжатых данных, с учётом заголовка; 4 байта - размер несжатых данных. * 0x02 - uncompressed data, large block. Then 4 bytes - compressed data size, including header; 4 bytes uncompressed data size.
* 0x03 - сжатые данные, QuickLZ level 1, большой блок. Далее 8 байт аналогично. * 0x03 - compressed data, QuickLZ level 1, large block. Then 8 bytes are similar.
* *
* 0x82 - LZ4 или LZ4HC (они имеют одинаковый формат). * 0x82 - LZ4 or LZ4HC (they have the same format).
* Далее 4 байта - размер сжатых данных, с учётом заголовка; 4 байта - размер несжатых данных. * Next 4 bytes - the size of the compressed data, taking into account the header; 4 bytes is the size of the uncompressed data.
* *
* NOTE: Почему 0x82? * NOTE: Why is 0x82?
* Изначально использовался только QuickLZ. Потом был добавлен LZ4. * Originally only QuickLZ was used. Then LZ4 was added.
* Старший бит выставлен, чтобы отличить от QuickLZ, а второй бит выставлен для совместимости, * The high bit is set to distinguish from QuickLZ, and the second bit is set for compatibility,
* чтобы работали функции qlz_size_compressed, qlz_size_decompressed. * for the functions qlz_size_compressed, qlz_size_decompressed to work.
* Хотя сейчас такая совместимость уже не актуальна. * Although now such compatibility is no longer relevant.
* *
* 0x90 - ZSTD * 0x90 - ZSTD
* *
* Все размеры - little endian. * All sizes are little endian.
*/ */
enum class CompressionMethodByte : uint8_t enum class CompressionMethodByte : uint8_t

View File

@ -29,7 +29,7 @@ private:
#else #else
/// ABI compatibility for USE_QUICKLZ /// ABI compatibility for USE_QUICKLZ
void * fixed_size_padding = nullptr; void * fixed_size_padding = nullptr;
/// Отменяет warning unused-private-field. /// Undoes warning unused-private-field.
void * fixed_size_padding_used() const { return fixed_size_padding; } void * fixed_size_padding_used() const { return fixed_size_padding; }
#endif #endif
@ -41,20 +41,20 @@ public:
CompressionMethod method_ = CompressionMethod::LZ4, CompressionMethod method_ = CompressionMethod::LZ4,
size_t buf_size = DBMS_DEFAULT_BUFFER_SIZE); size_t buf_size = DBMS_DEFAULT_BUFFER_SIZE);
/// Объём сжатых данных /// The amount of compressed data
size_t getCompressedBytes() size_t getCompressedBytes()
{ {
nextIfAtEnd(); nextIfAtEnd();
return out.count(); return out.count();
} }
/// Сколько несжатых байт было записано в буфер /// How many uncompressed bytes were written to the buffer
size_t getUncompressedBytes() size_t getUncompressedBytes()
{ {
return count(); return count();
} }
/// Сколько байт находится в буфере (ещё не сжато) /// How many bytes are in the buffer (not yet compressed)
size_t getRemainingBytes() size_t getRemainingBytes()
{ {
nextIfAtEnd(); nextIfAtEnd();

View File

@ -8,7 +8,7 @@
namespace DB namespace DB
{ {
/** Читает из конкатенации нескольких ReadBuffer-ов /** Reads from the concatenation of multiple ReadBuffers
*/ */
class ConcatReadBuffer : public ReadBuffer class ConcatReadBuffer : public ReadBuffer
{ {
@ -24,7 +24,7 @@ protected:
if (buffers.end() == current) if (buffers.end() == current)
return false; return false;
/// Первое чтение /// First reading
if (working_buffer.size() == 0 && (*current)->hasPendingData()) if (working_buffer.size() == 0 && (*current)->hasPendingData())
{ {
working_buffer = Buffer((*current)->position(), (*current)->buffer().end()); working_buffer = Buffer((*current)->position(), (*current)->buffer().end());
@ -37,7 +37,7 @@ protected:
if (buffers.end() == current) if (buffers.end() == current)
return false; return false;
/// Пропускаем закончившиеся буферы; если буфер не закончился, но курсор на конце, то прочитаем следующую порцию данных. /// We skip the filled up buffers; if the buffer is not filled in, but the cursor is at the end, then read the next piece of data.
while ((*current)->eof()) while ((*current)->eof())
{ {
++current; ++current;

View File

@ -6,8 +6,8 @@
namespace DB namespace DB
{ {
/* /*
* Считает хэш от прочитанных данных. При чтении данные читаются из вложенного ReadBuffer. * Calculates the hash from the read data. When reading, the data is read from the nested ReadBuffer.
* Мелкие кусочки копируются в собственную память. * Small pieces are copied into its own memory.
*/ */
class HashingReadBuffer : public IHashingBuffer<ReadBuffer> class HashingReadBuffer : public IHashingBuffer<ReadBuffer>
{ {
@ -18,7 +18,7 @@ public:
working_buffer = in.buffer(); working_buffer = in.buffer();
pos = in.position(); pos = in.position();
/// считаем хэш от уже прочитанных данных /// calculate hash from the data already read
if (working_buffer.size()) if (working_buffer.size())
{ {
calculateHash(pos, working_buffer.end() - pos); calculateHash(pos, working_buffer.end() - pos);

View File

@ -32,8 +32,8 @@ public:
state = CityHash128WithSeed(data, block_size, state); state = CityHash128WithSeed(data, block_size, state);
} }
/// вычисление хэша зависит от разбиения по блокам /// computation of the hash depends on the partitioning of blocks
/// поэтому нужно вычислить хэш от n полных кусочков и одного неполного /// so you need to compute a hash of n complete pieces and one incomplete
void calculateHash(DB::BufferBase::Position data, size_t len); void calculateHash(DB::BufferBase::Position data, size_t len);
protected: protected:
@ -42,8 +42,8 @@ protected:
uint128 state; uint128 state;
}; };
/** Вычисляет хеш от записываемых данных и передает их в указанный WriteBuffer. /** Computes the hash from the data to write and passes it to the specified WriteBuffer.
* В качестве основного буфера используется буфер вложенного WriteBuffer. * The buffer of the nested WriteBuffer is used as the main buffer.
*/ */
class HashingWriteBuffer : public IHashingBuffer<WriteBuffer> class HashingWriteBuffer : public IHashingBuffer<WriteBuffer>
{ {
@ -68,7 +68,7 @@ public:
size_t block_size_ = DBMS_DEFAULT_HASHING_BLOCK_SIZE) size_t block_size_ = DBMS_DEFAULT_HASHING_BLOCK_SIZE)
: IHashingBuffer<DB::WriteBuffer>(block_size_), out(out_) : IHashingBuffer<DB::WriteBuffer>(block_size_), out(out_)
{ {
out.next(); /// Если до нас в out что-то уже писали, не дадим остаткам этих данных повлиять на хеш. out.next(); /// If something has already been written to `out` before us, we will not let the remains of this data affect the hash.
working_buffer = out.buffer(); working_buffer = out.buffer();
pos = working_buffer.begin(); pos = working_buffer.begin();
state = uint128(0, 0); state = uint128(0, 0);

View File

@ -0,0 +1,35 @@
#include <Core/Types.h>
#include <Common/hex.h>
#include <Common/Exception.h>
#include <IO/HexWriteBuffer.h>
namespace DB
{
void HexWriteBuffer::nextImpl()
{
if (!offset())
return;
for (Position p = working_buffer.begin(); p != pos; ++p)
{
UInt8 byte = *p;
out.write(hexUppercase(byte / 16));
out.write(hexUppercase(byte % 16));
}
}
HexWriteBuffer::~HexWriteBuffer()
{
try
{
nextImpl();
}
catch (...)
{
tryLogCurrentException(__PRETTY_FUNCTION__);
}
}
}

View File

@ -1,51 +1,28 @@
#pragma once #pragma once
#include <IO/BufferWithOwnMemory.h>
#include <IO/WriteBuffer.h> #include <IO/WriteBuffer.h>
/// Так как HexWriteBuffer часто создаётся во внутреннем цикле, сделаем у него размер буфера маленьким. /// Since HexWriteBuffer is often created in the inner loop, we'll make its buffer size small.
#define DBMS_HEX_WRITE_BUFFER_SIZE 32 #define DBMS_HEX_WRITE_BUFFER_SIZE 32
namespace DB namespace DB
{ {
/** Всё что в него пишут, переводит в HEX (большими буквами) и пишет в другой WriteBuffer. /** Everything that is written into it, translates to HEX (in capital letters) and writes to another WriteBuffer.
*/ */
class HexWriteBuffer : public WriteBuffer class HexWriteBuffer final : public WriteBuffer
{ {
protected: protected:
char buf[DBMS_HEX_WRITE_BUFFER_SIZE]; char buf[DBMS_HEX_WRITE_BUFFER_SIZE];
WriteBuffer & out; WriteBuffer & out;
void nextImpl() override void nextImpl() override;
{
if (!offset())
return;
for (Position p = working_buffer.begin(); p != pos; ++p)
{
out.write("0123456789ABCDEF"[static_cast<unsigned char>(*p) >> 4]);
out.write("0123456789ABCDEF"[static_cast<unsigned char>(*p) & 0xF]);
}
}
public: public:
HexWriteBuffer(WriteBuffer & out_) : WriteBuffer(buf, sizeof(buf)), out(out_) {} HexWriteBuffer(WriteBuffer & out_) : WriteBuffer(buf, sizeof(buf)), out(out_) {}
~HexWriteBuffer() override;
~HexWriteBuffer() override
{
try
{
nextImpl();
}
catch (...)
{
tryLogCurrentException(__PRETTY_FUNCTION__);
}
}
}; };
} }

View File

@ -17,7 +17,7 @@ constexpr auto DEFAULT_REMOTE_WRITE_BUFFER_SEND_TIMEOUT = 1800;
} }
/** Позволяет писать файл на удалённый сервер. /** Allows you to write a file to a remote server.
*/ */
class InterserverWriteBuffer final : public WriteBuffer class InterserverWriteBuffer final : public WriteBuffer
{ {
@ -44,10 +44,10 @@ private:
std::string path; std::string path;
Poco::Net::HTTPClientSession session; Poco::Net::HTTPClientSession session;
std::ostream * ostr; /// этим владеет session std::ostream * ostr; /// this is owned by session
std::unique_ptr<WriteBuffer> impl; std::unique_ptr<WriteBuffer> impl;
/// Отправили все данные и переименовали файл /// Sent all the data and renamed the file
bool finalized = false; bool finalized = false;
}; };

View File

@ -6,7 +6,7 @@
namespace DB namespace DB
{ {
/** Позволяет считать из другого ReadBuffer не более указанного количества байт. /** Lets read from another ReadBuffer no more than the specified number of bytes.
*/ */
class LimitReadBuffer : public ReadBuffer class LimitReadBuffer : public ReadBuffer
{ {

View File

@ -60,7 +60,7 @@ namespace mysqlxx
namespace DB namespace DB
{ {
/// Вывести mysqlxx::Row в tab-separated виде /// Output mysqlxx::Row in tab-separated form
inline void writeEscapedRow(const mysqlxx::Row & row, WriteBuffer & buf) inline void writeEscapedRow(const mysqlxx::Row & row, WriteBuffer & buf)
{ {
for (size_t i = 0; i < row.size(); ++i) for (size_t i = 0; i < row.size(); ++i)

View File

@ -9,25 +9,25 @@
namespace DB namespace DB
{ {
/** Реализует возможность записывать и считывать данные в WriteBuffer/ReadBuffer /** Implements the ability to write and read data in/from WriteBuffer/ReadBuffer
* с помощью операторов << и >> а также манипуляторов, * with the help of << and >> operators and also manipulators,
* предоставляя способ использования, похожий на iostream-ы. * providing a way of using, similar to iostreams.
* *
* Не является ни подмножеством, ни расширением iostream-ов. * It is neither a subset nor an extension of iostreams.
* *
* Пример использования: * Example usage:
* *
* DB::WriteBufferFromFileDescriptor buf(STDOUT_FILENO); * DB::WriteBufferFromFileDescriptor buf(STDOUT_FILENO);
* buf << DB::double_quote << "Hello, world!" << '\n' << DB::flush; * buf << DB::double_quote << "Hello, world!" << '\n' << DB::flush;
* *
* Выводит тип char (как правило, он же Int8) как символ, а не как число. * Outputs `char` type (usually it's Int8) as a symbol, not as a number.
*/ */
/// Манипуляторы. /// Manipulators.
enum EscapeManip { escape }; /// Для строк - экранировать спец-символы. В остальном, как обычно. enum EscapeManip { escape }; /// For strings - escape special characters. In the rest, as usual.
enum QuoteManip { quote }; /// Для строк, дат, дат-с-временем - заключить в одинарные кавычки с экранированием. В остальном, как обычно. enum QuoteManip { quote }; /// For strings, dates, datetimes - enclose in single quotes with escaping. In the rest, as usual.
enum DoubleQuoteManip { double_quote }; /// Для строк, дат, дат-с-временем - заключить в двойные кавычки с экранированием. В остальном, как обычно. enum DoubleQuoteManip { double_quote }; /// For strings, dates, datetimes - enclose in double quotes with escaping. In the rest, as usual.
enum BinaryManip { binary }; /// Выводить в бинарном формате. enum BinaryManip { binary }; /// Output in binary format.
struct EscapeManipWriteBuffer : WriteBuffer {}; struct EscapeManipWriteBuffer : WriteBuffer {};
struct QuoteManipWriteBuffer : WriteBuffer {}; struct QuoteManipWriteBuffer : WriteBuffer {};
@ -41,7 +41,7 @@ struct BinaryManipReadBuffer : ReadBuffer {};
template <typename T> WriteBuffer & operator<< (WriteBuffer & buf, const T & x) { writeText(x, buf); return buf; } template <typename T> WriteBuffer & operator<< (WriteBuffer & buf, const T & x) { writeText(x, buf); return buf; }
/// Если не использовать манипуляторы, строка выводится без экранирования, как есть. /// If you do not use the manipulators, the string is displayed without an escape, as is.
template <> inline WriteBuffer & operator<< (WriteBuffer & buf, const String & x) { writeString(x, buf); return buf; } template <> inline WriteBuffer & operator<< (WriteBuffer & buf, const String & x) { writeString(x, buf); return buf; }
template <> inline WriteBuffer & operator<< (WriteBuffer & buf, const char & x) { writeChar(x, buf); return buf; } template <> inline WriteBuffer & operator<< (WriteBuffer & buf, const char & x) { writeChar(x, buf); return buf; }
@ -62,7 +62,7 @@ inline WriteBuffer & operator<< (QuoteManipWriteBuffer & buf, const char *
inline WriteBuffer & operator<< (DoubleQuoteManipWriteBuffer & buf, const char * x) { writeAnyQuotedString<'"'>(x, x + strlen(x), buf); return buf; } inline WriteBuffer & operator<< (DoubleQuoteManipWriteBuffer & buf, const char * x) { writeAnyQuotedString<'"'>(x, x + strlen(x), buf); return buf; }
inline WriteBuffer & operator<< (BinaryManipWriteBuffer & buf, const char * x) { writeStringBinary(x, buf); return buf; } inline WriteBuffer & operator<< (BinaryManipWriteBuffer & buf, const char * x) { writeStringBinary(x, buf); return buf; }
/// Манипулятор вызывает у WriteBuffer метод next - это делает сброс буфера. Для вложенных буферов, сброс не рекурсивный. /// The manipulator calls the WriteBuffer method `next` - this makes the buffer reset. For nested buffers, the reset is not recursive.
enum FlushManip { flush }; enum FlushManip { flush };
inline WriteBuffer & operator<< (WriteBuffer & buf, FlushManip x) { buf.next(); return buf; } inline WriteBuffer & operator<< (WriteBuffer & buf, FlushManip x) { buf.next(); return buf; }
@ -72,7 +72,7 @@ template <typename T> ReadBuffer & operator>> (ReadBuffer & buf, T & x)
template <> inline ReadBuffer & operator>> (ReadBuffer & buf, String & x) { readString(x, buf); return buf; } template <> inline ReadBuffer & operator>> (ReadBuffer & buf, String & x) { readString(x, buf); return buf; }
template <> inline ReadBuffer & operator>> (ReadBuffer & buf, char & x) { readChar(x, buf); return buf; } template <> inline ReadBuffer & operator>> (ReadBuffer & buf, char & x) { readChar(x, buf); return buf; }
/// Если указать для чтения строковый литерал, то это будет обозначать - убедиться в наличии последовательности байт и пропустить её. /// If you specify a string literal for reading, this will mean - make sure there is a sequence of bytes and skip it.
inline ReadBuffer & operator>> (ReadBuffer & buf, const char * x) { assertString(x, buf); return buf; } inline ReadBuffer & operator>> (ReadBuffer & buf, const char * x) { assertString(x, buf); return buf; }
inline EscapeManipReadBuffer & operator>> (ReadBuffer & buf, EscapeManip x) { return static_cast<EscapeManipReadBuffer &>(buf); } inline EscapeManipReadBuffer & operator>> (ReadBuffer & buf, EscapeManip x) { return static_cast<EscapeManipReadBuffer &>(buf); }

View File

@ -17,34 +17,34 @@ namespace ErrorCodes
extern const int CANNOT_READ_ALL_DATA; extern const int CANNOT_READ_ALL_DATA;
} }
/** Простой абстрактный класс для буферизованного чтения данных (последовательности char) откуда-нибудь. /** A simple abstract class for buffered data reading (char sequences) from somewhere.
* В отличие от std::istream, предоставляет доступ к внутреннему буферу, * Unlike std::istream, it provides access to the internal buffer,
* а также позволяет вручную управлять позицией внутри буфера. * and also allows you to manually manage the position inside the buffer.
* *
* Замечание! Используется char *, а не const char * * Note! `char *`, not `const char *` is used
* (для того, чтобы можно было вынести общий код в BufferBase, а также для того, чтобы можно было заполнять буфер новыми данными). * (so that you can take out the common code into BufferBase, and also so that you can fill the buffer in with new data).
* Это вызывает неудобства - например, при использовании ReadBuffer для чтения из куска памяти const char *, * This causes inconveniences - for example, when using ReadBuffer to read from a chunk of memory const char *,
* приходится использовать const_cast. * you have to use const_cast.
* *
* Наследники должны реализовать метод nextImpl(). * successors must implement the nextImpl() method.
*/ */
class ReadBuffer : public BufferBase class ReadBuffer : public BufferBase
{ {
public: public:
/** Создаёт буфер и устанавливает кусок доступных данных для чтения нулевого размера, /** Creates a buffer and sets a piece of available data to read to zero size,
* чтобы при первой попытке чтения вызвалась функция next() для загрузки в буфер новой порции данных. * so that the next() function is called to load the new data portion into the buffer at the first try.
*/ */
ReadBuffer(Position ptr, size_t size) : BufferBase(ptr, size, 0) { working_buffer.resize(0); } ReadBuffer(Position ptr, size_t size) : BufferBase(ptr, size, 0) { working_buffer.resize(0); }
/** Используется, если буфер уже заполнен данными, которые можно читать. /** Used when the buffer is already full of data that can be read.
* (в этом случае, передайте 0 в качестве offset) * (in this case, pass 0 as an offset)
*/ */
ReadBuffer(Position ptr, size_t size, size_t offset) : BufferBase(ptr, size, offset) {} ReadBuffer(Position ptr, size_t size, size_t offset) : BufferBase(ptr, size, offset) {}
void set(Position ptr, size_t size) { BufferBase::set(ptr, size, 0); working_buffer.resize(0); } void set(Position ptr, size_t size) { BufferBase::set(ptr, size, 0); working_buffer.resize(0); }
/** прочитать следующие данные и заполнить ими буфер; переместить позицию в начало; /** read next data and fill a buffer with it; set position to the beginning;
* вернуть false в случае конца, true иначе; кинуть исключение, если что-то не так * return `false` in case of end, `true` otherwise; throw an exception, if something is wrong
*/ */
bool next() bool next()
{ {
@ -68,12 +68,12 @@ public:
virtual ~ReadBuffer() {} virtual ~ReadBuffer() {}
/** В отличие от std::istream, возвращает true, если все данные были прочитаны /** Unlike std::istream, it returns true if all data was read
* (а не в случае, если была попытка чтения после конца). * (and not in case there was an attempt to read after the end).
* Если на данный момент позиция находится на конце буфера, то вызывает метод next(). * If at the moment the position is at the end of the buffer, it calls the next() method.
* То есть, имеет побочный эффект - если буфер закончился, то обновляет его и переносит позицию в начало. * That is, it has a side effect - if the buffer is over, then it updates it and set the position to the beginning.
* *
* При попытке чтения после конца, следует кидать исключение. * Try to read after the end should throw an exception.
*/ */
bool ALWAYS_INLINE eof() bool ALWAYS_INLINE eof()
{ {
@ -101,7 +101,7 @@ public:
throw Exception("Attempt to read after eof", ErrorCodes::ATTEMPT_TO_READ_AFTER_EOF); throw Exception("Attempt to read after eof", ErrorCodes::ATTEMPT_TO_READ_AFTER_EOF);
} }
/// Можно было бы назвать этот метод ignore, а ignore назвать ignoreStrict. /// You could call this method `ignore`, and `ignore` call `ignoreStrict`.
size_t tryIgnore(size_t n) size_t tryIgnore(size_t n)
{ {
size_t bytes_ignored = 0; size_t bytes_ignored = 0;
@ -116,7 +116,7 @@ public:
return bytes_ignored; return bytes_ignored;
} }
/** Читает столько, сколько есть, не больше n байт. */ /** Reads as many as there are, no more than n bytes. */
size_t read(char * to, size_t n) size_t read(char * to, size_t n)
{ {
size_t bytes_copied = 0; size_t bytes_copied = 0;
@ -132,18 +132,18 @@ public:
return bytes_copied; return bytes_copied;
} }
/** Читает n байт, если есть меньше - кидает исключение. */ /** Reads n bytes, if there are less - throws an exception. */
void readStrict(char * to, size_t n) void readStrict(char * to, size_t n)
{ {
if (n != read(to, n)) if (n != read(to, n))
throw Exception("Cannot read all data", ErrorCodes::CANNOT_READ_ALL_DATA); throw Exception("Cannot read all data", ErrorCodes::CANNOT_READ_ALL_DATA);
} }
/** Метод, который может быть более эффективно реализован в наследниках, в случае чтения достаточно больших блоков. /** A method that can be more efficiently implemented in successors, in the case of reading large enough blocks.
* Реализация может читать данные сразу в to, без лишнего копирования, если в to есть достаточно места для работы. * The implementation can read data directly into `to`, without superfluous copying, if in `to` there is enough space for work.
* Например, CompressedReadBuffer может разжимать данные сразу в to, если весь разжатый блок туда помещается. * For example, a CompressedReadBuffer can decompress the data directly into `to`, if the entire decompressed block fits there.
* По-умолчанию - то же, что и read. * By default - the same as read.
* Для маленьких чтений использовать не нужно. * Don't use for small reads.
*/ */
virtual size_t readBig(char * to, size_t n) virtual size_t readBig(char * to, size_t n)
{ {
@ -151,13 +151,13 @@ public:
} }
protected: protected:
/// Количество игнорируемых байт с начальной позиции буфера working_buffer. /// The number of bytes to ignore from the initial position of `working_buffer` buffer.
size_t working_buffer_offset = 0; size_t working_buffer_offset = 0;
private: private:
/** Прочитать следующие данные и заполнить ими буфер. /** Read the next data and fill a buffer with it.
* Вернуть false в случае конца, true иначе. * Return `false` in case of the end, `true` otherwise.
* Кинуть исключение, если что-то не так. * Throw an exception if something is wrong.
*/ */
virtual bool nextImpl() { return false; }; virtual bool nextImpl() { return false; };
}; };

View File

@ -21,7 +21,7 @@ namespace CurrentMetrics
namespace DB namespace DB
{ {
/** Класс для асинхронного чтения данных. /** Class for asynchronous data reading.
*/ */
class ReadBufferAIO : public ReadBufferFromFileBase class ReadBufferAIO : public ReadBufferFromFileBase
{ {
@ -43,64 +43,64 @@ private:
bool nextImpl() override; bool nextImpl() override;
/// ///
off_t doSeek(off_t off, int whence) override; off_t doSeek(off_t off, int whence) override;
/// Синхронно читать данные. /// Synchronously read the data.
void synchronousRead(); void synchronousRead();
/// Получить данные от асинхронного запроса. /// Get data from an asynchronous request.
void receive(); void receive();
/// Игнорировать данные от асинхронного запроса. /// Ignore data from an asynchronous request.
void skip(); void skip();
/// Ждать окончания текущей асинхронной задачи. /// Wait for the end of the current asynchronous task.
bool waitForAIOCompletion(); bool waitForAIOCompletion();
/// Подготовить запрос. /// Prepare the request.
void prepare(); void prepare();
/// Подготовить к чтению дублирующий буфер содержащий данные от /// Prepare for reading a duplicate buffer containing data from
/// последнего запроса. /// of the last request.
void finalize(); void finalize();
private: private:
/// Буфер для асинхронных операций чтения данных. /// Buffer for asynchronous data read operations.
BufferWithOwnMemory<ReadBuffer> fill_buffer; BufferWithOwnMemory<ReadBuffer> fill_buffer;
/// Описание асинхронного запроса на чтение. /// Description of the asynchronous read request.
iocb request{}; iocb request{};
std::future<ssize_t> future_bytes_read; std::future<ssize_t> future_bytes_read;
const std::string filename; const std::string filename;
/// Максимальное количество байтов, которое можно прочитать. /// The maximum number of bytes that can be read.
size_t max_bytes_read = std::numeric_limits<size_t>::max(); size_t max_bytes_read = std::numeric_limits<size_t>::max();
/// Количество запрашиваемых байтов. /// Number of bytes requested.
size_t requested_byte_count = 0; size_t requested_byte_count = 0;
/// Количество прочитанных байт при последнем запросе. /// The number of bytes read at the last request.
ssize_t bytes_read = 0; ssize_t bytes_read = 0;
/// Итоговое количество прочитанных байтов. /// The total number of bytes read.
size_t total_bytes_read = 0; size_t total_bytes_read = 0;
/// Позиция первого непрочитанного байта в файле. /// The position of the first unread byte in the file.
off_t first_unread_pos_in_file = 0; off_t first_unread_pos_in_file = 0;
/// Начальная позиция выровненного региона диска, из которого читаются данные. /// The starting position of the aligned region of the disk from which the data is read.
off_t region_aligned_begin = 0; off_t region_aligned_begin = 0;
/// Левое смещение для выравнения региона диска. /// Left offset to align the region of the disk.
size_t region_left_padding = 0; size_t region_left_padding = 0;
/// Размер выровненного региона диска. /// The size of the aligned region of the disk.
size_t region_aligned_size = 0; size_t region_aligned_size = 0;
/// Файловый дескриптор для чтения. /// The file descriptor for read.
int fd = -1; int fd = -1;
/// Буфер, в который пишутся полученные данные. /// The buffer to which the received data is written.
Position buffer_begin = nullptr; Position buffer_begin = nullptr;
/// Асинхронная операция чтения ещё не завершилась. /// The asynchronous read operation is not yet completed.
bool is_pending_read = false; bool is_pending_read = false;
/// Конец файла достигнут. /// The end of the file is reached.
bool is_eof = false; bool is_eof = false;
/// Был отправлен хоть один запрос на чтение. /// At least one read request was sent.
bool is_started = false; bool is_started = false;
/// Является ли операция асинхронной? /// Is the operation asynchronous?
bool is_aio = false; bool is_aio = false;
/// Асинхронная операция завершилась неудачно? /// Did the asynchronous operation fail?
bool aio_failed = false; bool aio_failed = false;
CurrentMetrics::Increment metric_increment{CurrentMetrics::OpenFileForRead}; CurrentMetrics::Increment metric_increment{CurrentMetrics::OpenFileForRead};

View File

@ -24,7 +24,7 @@ public:
virtual std::string getFileName() const = 0; virtual std::string getFileName() const = 0;
virtual int getFD() const = 0; virtual int getFD() const = 0;
/// Есть возможность получать информацию о времени каждого чтения. /// It is possible to get information about the time of each reading.
struct ProfileInfo struct ProfileInfo
{ {
size_t bytes_requested; size_t bytes_requested;
@ -34,7 +34,7 @@ public:
using ProfileCallback = std::function<void(ProfileInfo)>; using ProfileCallback = std::function<void(ProfileInfo)>;
/// CLOCK_MONOTONIC_COARSE более чем достаточно для отслеживания долгих чтений - например, залипаний на секунды. /// CLOCK_MONOTONIC_COARSE is more than enough to track long reads - for example, hanging for a second.
void setProfileCallback(const ProfileCallback & profile_callback_, clockid_t clock_type_ = CLOCK_MONOTONIC_COARSE) void setProfileCallback(const ProfileCallback & profile_callback_, clockid_t clock_type_ = CLOCK_MONOTONIC_COARSE)
{ {
profile_callback = profile_callback_; profile_callback = profile_callback_;

View File

@ -9,16 +9,16 @@
namespace DB namespace DB
{ {
/** Работает с готовым Poco::Net::Socket. Операции блокирующие. /** Works with the ready Poco::Net::Socket. Blocking operations.
*/ */
class ReadBufferFromPocoSocket : public BufferWithOwnMemory<ReadBuffer> class ReadBufferFromPocoSocket : public BufferWithOwnMemory<ReadBuffer>
{ {
protected: protected:
Poco::Net::Socket & socket; Poco::Net::Socket & socket;
/** Для сообщений об ошибках. Нужно получать этот адрес заранее, так как, /** For error messages. It is necessary to receive this address in advance, because,
* например, если соединение разорвано, то адрес уже будет получить нельзя * for example, if the connection is broken, the address will not be received anymore
* (getpeername вернёт ошибку). * (getpeername will return an error).
*/ */
Poco::Net::SocketAddress peer_address; Poco::Net::SocketAddress peer_address;

View File

@ -1,4 +1,5 @@
#include <Core/Defines.h> #include <Core/Defines.h>
#include <Common/hex.h>
#include <Common/PODArray.h> #include <Common/PODArray.h>
#include <Common/StringUtils.h> #include <Common/StringUtils.h>
#include <IO/WriteHelpers.h> #include <IO/WriteHelpers.h>

View File

@ -64,21 +64,6 @@ inline char parseEscapeSequence(char c)
} }
} }
inline char unhex(char c)
{
switch (c)
{
case '0' ... '9':
return c - '0';
case 'a' ... 'f':
return c - 'a' + 10;
case 'A' ... 'F':
return c - 'A' + 10;
default:
return 0;
}
}
/// These functions are located in VarInt.h /// These functions are located in VarInt.h
/// inline void throwReadAfterEOF() /// inline void throwReadAfterEOF()

View File

@ -10,7 +10,7 @@
namespace DB namespace DB
{ {
/** Позволяет читать файл с удалённого сервера через riod. /** Allows you to read a file from a remote server via riod.
*/ */
class RemoteReadBuffer : public ReadBuffer class RemoteReadBuffer : public ReadBuffer
{ {
@ -51,7 +51,7 @@ public:
return true; return true;
} }
/// Вернуть список имен файлов в директории. /// Return the list of file names in the directory.
static std::vector<std::string> listFiles( static std::vector<std::string> listFiles(
const std::string & host, const std::string & host,
int port, int port,

View File

@ -27,7 +27,7 @@ namespace ErrorCodes
extern const int RECEIVED_ERROR_FROM_REMOTE_IO_SERVER; extern const int RECEIVED_ERROR_FROM_REMOTE_IO_SERVER;
} }
/** Позволяет писать файл на удалённый сервер. /** Allows you to write a file to a remote server.
*/ */
class RemoteWriteBuffer : public WriteBuffer class RemoteWriteBuffer : public WriteBuffer
{ {
@ -45,15 +45,15 @@ private:
std::string uri_str; std::string uri_str;
Poco::Net::HTTPClientSession session; Poco::Net::HTTPClientSession session;
std::ostream * ostr; /// этим владеет session std::ostream * ostr; /// this is owned by session
std::unique_ptr<WriteBuffer> impl; std::unique_ptr<WriteBuffer> impl;
/// Отправили все данные и переименовали файл /// Have sent all the data and renamed the file
bool finalized; bool finalized;
public: public:
/** Если tmp_path не пустой, то записывает сначала временный файл, а затем переименовывает, /** If tmp_path is not empty, it writes first the temporary file, and then renames it,
* удаляя существующие файлы, если есть. * deleting existing files, if any.
* Иначе используется параметр if_exists. * Otherwise, if_exists parameter is used.
*/ */
RemoteWriteBuffer(const std::string & host_, int port_, const std::string & path_, RemoteWriteBuffer(const std::string & host_, int port_, const std::string & path_,
const std::string & tmp_path_ = "", const std::string & if_exists_ = "remove", const std::string & tmp_path_ = "", const std::string & if_exists_ = "remove",
@ -83,7 +83,7 @@ public:
session.setPort(port); session.setPort(port);
session.setKeepAlive(true); session.setKeepAlive(true);
/// устанавливаем таймаут /// set the timeout
#if POCO_CLICKHOUSE_PATCH || POCO_VERSION >= 0x02000000 #if POCO_CLICKHOUSE_PATCH || POCO_VERSION >= 0x02000000
session.setTimeout(connection_timeout, send_timeout, receive_timeout); session.setTimeout(connection_timeout, send_timeout, receive_timeout);
#else #else
@ -134,7 +134,7 @@ public:
if (!offset() || finalized) if (!offset() || finalized)
return; return;
/// Для корректной работы с AsynchronousWriteBuffer, который подменяет буферы. /// For correct work with AsynchronousWriteBuffer, which replaces buffers.
impl->set(buffer().begin(), buffer().size()); impl->set(buffer().begin(), buffer().size());
impl->position() = pos; impl->position() = pos;
@ -146,7 +146,7 @@ public:
catch (const Exception & e) catch (const Exception & e)
{ {
if (e.code() == ErrorCodes::CANNOT_WRITE_TO_OSTREAM) if (e.code() == ErrorCodes::CANNOT_WRITE_TO_OSTREAM)
checkStatus(); /// Меняем сообщение об ошибке на более ясное. checkStatus(); /// Change the error message to a clearer one.
throw; throw;
} }
} }
@ -159,7 +159,7 @@ public:
next(); next();
checkStatus(); checkStatus();
/// Переименовываем файл, если нужно. /// Rename the file if necessary.
if (!tmp_path.empty()) if (!tmp_path.empty())
rename(); rename();
@ -246,7 +246,7 @@ private:
} }
catch (const Exception & e) catch (const Exception & e)
{ {
/// Если в прошлую попытку от сервера не пришло ответа, но файл всё же был переименован. /// If in the last attempt we did not receive a response from the server, but the file was renamed already.
if (i != 0 && e.code() == ErrorCodes::RECEIVED_ERROR_FROM_REMOTE_IO_SERVER if (i != 0 && e.code() == ErrorCodes::RECEIVED_ERROR_FROM_REMOTE_IO_SERVER
&& nullptr != strstr(e.displayText().data(), "File not found")) && nullptr != strstr(e.displayText().data(), "File not found"))
{ {

View File

@ -10,26 +10,26 @@ namespace DB
{ {
/** Записать UInt64 в формате переменной длины (base128) NOTE Only up to 2^63 - 1 are supported.*/ /** Write UInt64 in variable length format (base128) NOTE Only up to 2^63 - 1 are supported. */
void writeVarUInt(UInt64 x, std::ostream & ostr); void writeVarUInt(UInt64 x, std::ostream & ostr);
void writeVarUInt(UInt64 x, WriteBuffer & ostr); void writeVarUInt(UInt64 x, WriteBuffer & ostr);
char * writeVarUInt(UInt64 x, char * ostr); char * writeVarUInt(UInt64 x, char * ostr);
/** Прочитать UInt64, записанный в формате переменной длины (base128) */ /** Read UInt64, written in variable length format (base128) */
void readVarUInt(UInt64 & x, std::istream & istr); void readVarUInt(UInt64 & x, std::istream & istr);
void readVarUInt(UInt64 & x, ReadBuffer & istr); void readVarUInt(UInt64 & x, ReadBuffer & istr);
const char * readVarUInt(UInt64 & x, const char * istr, size_t size); const char * readVarUInt(UInt64 & x, const char * istr, size_t size);
/** Получить длину UInt64 в формате VarUInt */ /** Get the length of UInt64 in VarUInt format */
size_t getLengthOfVarUInt(UInt64 x); size_t getLengthOfVarUInt(UInt64 x);
/** Получить длину Int64 в формате VarInt */ /** Get the Int64 length in VarInt format */
size_t getLengthOfVarInt(Int64 x); size_t getLengthOfVarInt(Int64 x);
/** Записать Int64 в формате переменной длины (base128) */ /** Write Int64 in variable length format (base128) */
template <typename OUT> template <typename OUT>
inline void writeVarInt(Int64 x, OUT & ostr) inline void writeVarInt(Int64 x, OUT & ostr)
{ {
@ -42,7 +42,7 @@ inline char * writeVarInt(Int64 x, char * ostr)
} }
/** Прочитать Int64, записанный в формате переменной длины (base128) */ /** Read Int64, written in variable length format (base128) */
template <typename IN> template <typename IN>
inline void readVarInt(Int64 & x, IN & istr) inline void readVarInt(Int64 & x, IN & istr)
{ {
@ -73,7 +73,7 @@ inline const char * readVarT(UInt64 & x, const char * istr, size_t size) { retur
inline const char * readVarT(Int64 & x, const char * istr, size_t size) { return readVarInt(x, istr, size); } inline const char * readVarT(Int64 & x, const char * istr, size_t size) { return readVarInt(x, istr, size); }
/// Для [U]Int32, [U]Int16. /// For [U]Int32, [U]Int16.
inline void readVarUInt(UInt32 & x, ReadBuffer & istr) inline void readVarUInt(UInt32 & x, ReadBuffer & istr)
{ {

View File

@ -18,11 +18,11 @@ namespace ErrorCodes
} }
/** Простой абстрактный класс для буферизованной записи данных (последовательности char) куда-нибудь. /** A simple abstract class for buffered data writing (char sequences) somewhere.
* В отличие от std::ostream, предоставляет доступ к внутреннему буферу, * Unlike std::ostream, it provides access to the internal buffer,
* а также позволяет вручную управлять позицией внутри буфера. * and also allows you to manually manage the position inside the buffer.
* *
* Наследники должны реализовать метод nextImpl(). * The successors must implement the nextImpl() method.
*/ */
class WriteBuffer : public BufferBase class WriteBuffer : public BufferBase
{ {
@ -30,8 +30,8 @@ public:
WriteBuffer(Position ptr, size_t size) : BufferBase(ptr, size, 0) {} WriteBuffer(Position ptr, size_t size) : BufferBase(ptr, size, 0) {}
void set(Position ptr, size_t size) { BufferBase::set(ptr, size, 0); } void set(Position ptr, size_t size) { BufferBase::set(ptr, size, 0); }
/** записать данные, находящиеся в буфере (от начала буфера до текущей позиции); /** write the data in the buffer (from the beginning of the buffer to the current position);
* переместить позицию в начало; кинуть исключение, если что-то не так * set the position to the beginning; throw an exception, if something is wrong
*/ */
inline void next() inline void next()
{ {
@ -45,8 +45,8 @@ public:
} }
catch (...) catch (...)
{ {
/** Если вызов nextImpl() был неудачным, то переместим курсор в начало, /** If the nextImpl() call was unsuccessful, move the cursor to the beginning,
* чтобы потом (например, при развёртке стека) не было второй попытки записать данные. * so that later (for example, when the stack was expanded) there was no second attempt to write data.
*/ */
pos = working_buffer.begin(); pos = working_buffer.begin();
throw; throw;
@ -55,8 +55,8 @@ public:
pos = working_buffer.begin(); pos = working_buffer.begin();
} }
/** желательно в наследниках поместить в деструктор вызов next(), /** it is desirable in the successors to place the next() call in the destructor,
* чтобы последние данные записались * so that the last data is written
*/ */
virtual ~WriteBuffer() {} virtual ~WriteBuffer() {}
@ -91,8 +91,8 @@ public:
} }
private: private:
/** Записать данные, находящиеся в буфере (от начала буфера до текущей позиции). /** Write the data in the buffer (from the beginning of the buffer to the current position).
* Кинуть исключение, если что-то не так. * Throw an exception if something is wrong.
*/ */
virtual void nextImpl() { throw Exception("Cannot write after end of buffer.", ErrorCodes::CANNOT_WRITE_AFTER_END_OF_BUFFER); }; virtual void nextImpl() { throw Exception("Cannot write after end of buffer.", ErrorCodes::CANNOT_WRITE_AFTER_END_OF_BUFFER); };
}; };

View File

@ -20,7 +20,7 @@ namespace CurrentMetrics
namespace DB namespace DB
{ {
/** Класс для асинхронной записи данных. /** Class for asynchronous data writing.
*/ */
class WriteBufferAIO : public WriteBufferFromFileBase class WriteBufferAIO : public WriteBufferFromFileBase
{ {
@ -42,20 +42,20 @@ private:
off_t doSeek(off_t off, int whence) override; off_t doSeek(off_t off, int whence) override;
void doTruncate(off_t length) override; void doTruncate(off_t length) override;
/// Если в буфере ещё остались данные - запишем их. /// If there's still data in the buffer, we'll write them.
void flush(); void flush();
/// Ждать окончания текущей асинхронной задачи. /// Wait for the end of the current asynchronous task.
bool waitForAIOCompletion(); bool waitForAIOCompletion();
/// Подготовить асинхронный запрос. /// Prepare an asynchronous request.
void prepare(); void prepare();
/// ///
void finalize(); void finalize();
private: private:
/// Буфер для асинхронных операций записи данных. /// Buffer for asynchronous data writes.
BufferWithOwnMemory<WriteBuffer> flush_buffer; BufferWithOwnMemory<WriteBuffer> flush_buffer;
/// Описание асинхронного запроса на запись. /// Description of the asynchronous write request.
iocb request = { 0 }; iocb request = { 0 };
std::vector<iocb *> request_ptrs{&request}; std::vector<iocb *> request_ptrs{&request};
std::vector<io_event> events{1}; std::vector<io_event> events{1};
@ -64,33 +64,33 @@ private:
const std::string filename; const std::string filename;
/// Количество байтов, которые будут записаны на диск. /// The number of bytes to be written to the disk.
off_t bytes_to_write = 0; off_t bytes_to_write = 0;
/// Количество записанных байт при последнем запросе. /// Number of bytes written with the last request.
off_t bytes_written = 0; off_t bytes_written = 0;
/// Количество нулевых байтов, которые надо отрезать c конца файла /// The number of zero bytes to be cut from the end of the file
/// после завершения операции записи данных. /// after the data write operation completes.
off_t truncation_count = 0; off_t truncation_count = 0;
/// Текущая позиция в файле. /// The current position in the file.
off_t pos_in_file = 0; off_t pos_in_file = 0;
/// Максимальная достигнутая позиция в файле. /// The maximum position reached in the file.
off_t max_pos_in_file = 0; off_t max_pos_in_file = 0;
/// Начальная позиция выровненного региона диска, в который записываются данные. /// The starting position of the aligned region of the disk to which the data is written.
off_t region_aligned_begin = 0; off_t region_aligned_begin = 0;
/// Размер выровненного региона диска. /// The size of the aligned region of the disk.
size_t region_aligned_size = 0; size_t region_aligned_size = 0;
/// Файловый дескриптор для записи. /// The file descriptor for writing.
int fd = -1; int fd = -1;
/// Буфер данных, которые хотим записать на диск. /// The data buffer that we want to write to the disk.
Position buffer_begin = nullptr; Position buffer_begin = nullptr;
/// Асинхронная операция записи ещё не завершилась? /// Is the asynchronous write operation still in progress?
bool is_pending_write = false; bool is_pending_write = false;
/// Асинхронная операция завершилась неудачно? /// Did the asynchronous operation fail?
bool aio_failed = false; bool aio_failed = false;
CurrentMetrics::Increment metric_increment{CurrentMetrics::OpenFileForWrite}; CurrentMetrics::Increment metric_increment{CurrentMetrics::OpenFileForWrite};

View File

@ -9,16 +9,16 @@
namespace DB namespace DB
{ {
/** Работает с готовым Poco::Net::Socket. Операции блокирующие. /** Works with the ready Poco::Net::Socket. Blocking operations.
*/ */
class WriteBufferFromPocoSocket : public BufferWithOwnMemory<WriteBuffer> class WriteBufferFromPocoSocket : public BufferWithOwnMemory<WriteBuffer>
{ {
protected: protected:
Poco::Net::Socket & socket; Poco::Net::Socket & socket;
/** Для сообщений об ошибках. Нужно получать этот адрес заранее, так как, /** For error messages. It is necessary to receive this address in advance, because,
* например, если соединение разорвано, то адрес уже будет получить нельзя * for example, if the connection is broken, the address will not be received anymore
* (getpeername вернёт ошибку). * (getpeername will return an error).
*/ */
Poco::Net::SocketAddress peer_address; Poco::Net::SocketAddress peer_address;

View File

@ -9,8 +9,8 @@
namespace DB namespace DB
{ {
/** Пишет данные в строку. /** Writes the data to a string.
* Замечение: перед использованием полученной строки, уничтожте этот объект. * Note: before using the resulting string, destroy this object.
*/ */
class WriteBufferFromString : public WriteBuffer class WriteBufferFromString : public WriteBuffer
{ {

View File

@ -11,8 +11,8 @@
namespace DB namespace DB
{ {
/** Инициализируется вектором. Пишет данные в него. Когда вектор закончится - увеличивает его размер в два раза. /** Initialized by vector. Writes data to it. When the vector is finished, it doubles its size.
* CharType - char или unsigned char. * CharType - char or unsigned char.
*/ */
template <typename VectorType = std::vector<char> > template <typename VectorType = std::vector<char> >
class WriteBufferFromVector : public WriteBuffer class WriteBufferFromVector : public WriteBuffer

View File

@ -7,16 +7,16 @@
namespace DB namespace DB
{ {
/** Пишет данные в другой буфер, заменяя невалидные UTF-8 последовательности на указанную последовательность. /** Writes the data to another buffer, replacing the invalid UTF-8 sequences with the specified sequence.
* Если записывается уже валидный UTF-8, работает быстрее. * If the valid UTF-8 is already written, it works faster.
* Замечение: перед использованием полученной строки, уничтожте этот объект. * Note: before using the resulting string, destroy this object.
*/ */
class WriteBufferValidUTF8 : public BufferWithOwnMemory<WriteBuffer> class WriteBufferValidUTF8 : public BufferWithOwnMemory<WriteBuffer>
{ {
private: private:
WriteBuffer & output_buffer; WriteBuffer & output_buffer;
bool group_replacements; bool group_replacements;
/// Последний записанный символ был replacement. /// The last recorded character was `replacement`.
bool just_put_replacement = false; bool just_put_replacement = false;
std::string replacement; std::string replacement;

View File

@ -139,19 +139,19 @@ inline void writeString(const StringRef & ref, WriteBuffer & buf)
} }
/** Пишет С-строку без создания временного объекта. Если строка - литерал, то strlen выполняется на этапе компиляции. /** Writes a C-string without creating a temporary object. If the string is a literal, then `strlen` is executed at the compilation stage.
* Используйте, когда строка - литерал. * Use when the string is a literal.
*/ */
#define writeCString(s, buf) \ #define writeCString(s, buf) \
(buf).write((s), strlen(s)) (buf).write((s), strlen(s))
/** Пишет строку для использования в формате JSON: /** Writes a string for use in the JSON format:
* - строка выводится в двойных кавычках * - the string is outputted in double quotes
* - эскейпится символ прямого слеша '/' * - forward slash character '/' is escaped
* - байты из диапазона 0x00-0x1F кроме '\b', '\f', '\n', '\r', '\t' эскейпятся как \u00XX * - bytes from the range 0x00-0x1F except `\b', '\f', '\n', '\r', '\t' are escaped as \u00XX
* - кодовые точки U+2028 и U+2029 (последовательности байт в UTF-8: e2 80 a8, e2 80 a9) эскейпятся как \u2028 и \u2029 * - code points U+2028 and U+2029 (byte sequences in UTF-8: e2 80 a8, e2 80 a9) are escaped as \u2028 and \u2029
* - предполагается, что строка в кодировке UTF-8, невалидный UTF-8 не обрабатывается * - it is assumed that string is the UTF-8 encoded, the invalid UTF-8 is not processed
* - не-ASCII символы остаются как есть * - non-ASCII characters remain as is
*/ */
inline void writeJSONString(const char * begin, const char * end, WriteBuffer & buf) inline void writeJSONString(const char * begin, const char * end, WriteBuffer & buf)
{ {
@ -227,7 +227,7 @@ void writeAnyEscapedString(const char * begin, const char * end, WriteBuffer & b
const char * pos = begin; const char * pos = begin;
while (true) while (true)
{ {
/// Специально будем эскейпить больше символов, чем минимально необходимо. /// On purpose we will escape more characters than minimally necessary.
const char * next_pos = find_first_symbols<'\b', '\f', '\n', '\r', '\t', '\0', '\\', c>(pos, end); const char * next_pos = find_first_symbols<'\b', '\f', '\n', '\r', '\t', '\0', '\\', c>(pos, end);
if (next_pos == end) if (next_pos == end)
@ -359,13 +359,13 @@ inline void writeDoubleQuotedString(const String & s, WriteBuffer & buf)
writeAnyQuotedString<'"'>(s, buf); writeAnyQuotedString<'"'>(s, buf);
} }
/// Выводит строку в обратных кавычках, как идентификатор в MySQL. /// Outputs a string in backquotes, as an identifier in MySQL.
inline void writeBackQuotedString(const String & s, WriteBuffer & buf) inline void writeBackQuotedString(const String & s, WriteBuffer & buf)
{ {
writeAnyQuotedString<'`'>(s, buf); writeAnyQuotedString<'`'>(s, buf);
} }
/// То же самое, но обратные кавычки применяются только при наличии символов, не подходящих для идентификатора без обратных кавычек. /// The same, but backquotes apply only if there are characters that do not match the identifier without backquotes.
inline void writeProbablyBackQuotedString(const String & s, WriteBuffer & buf) inline void writeProbablyBackQuotedString(const String & s, WriteBuffer & buf)
{ {
if (s.empty() || !isValidIdentifierBegin(s[0])) if (s.empty() || !isValidIdentifierBegin(s[0]))
@ -385,10 +385,10 @@ inline void writeProbablyBackQuotedString(const String & s, WriteBuffer & buf)
} }
/** Выводит строку в для формата CSV. /** Outputs the string in for the CSV format.
* Правила: * Rules:
* - строка выводится в кавычках; * - the string is outputted in quotation marks;
* - кавычка внутри строки выводится как две кавычки подряд. * - the quotation mark inside the string is outputted as two quotation marks in sequence.
*/ */
template <char quote = '"'> template <char quote = '"'>
void writeCSVString(const char * begin, const char * end, WriteBuffer & buf) void writeCSVString(const char * begin, const char * end, WriteBuffer & buf)
@ -405,7 +405,7 @@ void writeCSVString(const char * begin, const char * end, WriteBuffer & buf)
buf.write(pos, end - pos); buf.write(pos, end - pos);
break; break;
} }
else /// Кавычка. else /// Quotation.
{ {
++next_pos; ++next_pos;
buf.write(pos, next_pos - pos); buf.write(pos, next_pos - pos);
@ -431,13 +431,13 @@ void writeCSVString(const StringRef & s, WriteBuffer & buf)
} }
/// Запись строки в текстовый узел в XML (не в атрибут - иначе нужно больше эскейпинга). /// Writing a string to a text node in XML (not into an attribute - otherwise you need more escaping).
inline void writeXMLString(const char * begin, const char * end, WriteBuffer & buf) inline void writeXMLString(const char * begin, const char * end, WriteBuffer & buf)
{ {
const char * pos = begin; const char * pos = begin;
while (true) while (true)
{ {
/// NOTE Возможно, для некоторых парсеров XML нужно ещё эскейпить нулевой байт и некоторые control characters. /// NOTE Perhaps for some XML parsers, you need to escape the zero byte and some control characters.
const char * next_pos = find_first_symbols<'<', '&'>(pos, end); const char * next_pos = find_first_symbols<'<', '&'>(pos, end);
if (next_pos == end) if (next_pos == end)
@ -473,7 +473,7 @@ inline void writeXMLString(const StringRef & s, WriteBuffer & buf)
} }
/// в формате YYYY-MM-DD /// in YYYY-MM-DD format
inline void writeDateText(DayNum_t date, WriteBuffer & buf) inline void writeDateText(DayNum_t date, WriteBuffer & buf)
{ {
char s[10] = {'0', '0', '0', '0', '-', '0', '0', '-', '0', '0'}; char s[10] = {'0', '0', '0', '0', '-', '0', '0', '-', '0', '0'};
@ -515,7 +515,7 @@ inline void writeDateText(LocalDate date, WriteBuffer & buf)
} }
/// в формате YYYY-MM-DD HH:MM:SS, согласно текущему часовому поясу /// in the format YYYY-MM-DD HH:MM:SS, according to the current time zone
template <char date_delimeter = '-', char time_delimeter = ':'> template <char date_delimeter = '-', char time_delimeter = ':'>
inline void writeDateTimeText(time_t datetime, WriteBuffer & buf, const DateLUTImpl & date_lut = DateLUT::instance()) inline void writeDateTimeText(time_t datetime, WriteBuffer & buf, const DateLUTImpl & date_lut = DateLUT::instance())
{ {
@ -577,7 +577,7 @@ inline void writeDateTimeText(LocalDateTime datetime, WriteBuffer & buf)
} }
/// Методы вывода в бинарном виде /// Methods of output in binary form
template <typename T> template <typename T>
inline typename std::enable_if<std::is_arithmetic<T>::value, void>::type inline typename std::enable_if<std::is_arithmetic<T>::value, void>::type
writeBinary(const T & x, WriteBuffer & buf) { writePODBinary(x, buf); } writeBinary(const T & x, WriteBuffer & buf) { writePODBinary(x, buf); }
@ -589,7 +589,7 @@ inline void writeBinary(const LocalDate & x, WriteBuffer & buf) { writePO
inline void writeBinary(const LocalDateTime & x, WriteBuffer & buf) { writePODBinary(x, buf); } inline void writeBinary(const LocalDateTime & x, WriteBuffer & buf) { writePODBinary(x, buf); }
/// Методы для вывода значения в текстовом виде для tab-separated формата. /// Methods for outputting the value in text form for a tab-separated format.
template <typename T> template <typename T>
inline typename std::enable_if<std::is_integral<T>::value, void>::type inline typename std::enable_if<std::is_integral<T>::value, void>::type
writeText(const T & x, WriteBuffer & buf) { writeIntText(x, buf); } writeText(const T & x, WriteBuffer & buf) { writeIntText(x, buf); }
@ -603,15 +603,15 @@ inline void writeText(const String & x, WriteBuffer & buf) { writeEscaped
/// Implemented as template specialization (not function overload) to avoid preference over templates on arithmetic types above. /// Implemented as template specialization (not function overload) to avoid preference over templates on arithmetic types above.
template <> inline void writeText<bool>(const bool & x, WriteBuffer & buf) { writeBoolText(x, buf); } template <> inline void writeText<bool>(const bool & x, WriteBuffer & buf) { writeBoolText(x, buf); }
/// в отличие от метода для std::string /// unlike the method for std::string
/// здесь предполагается, что x null-terminated строка. /// assumes here that `x` is a null-terminated string.
inline void writeText(const char * x, WriteBuffer & buf) { writeEscapedString(x, strlen(x), buf); } inline void writeText(const char * x, WriteBuffer & buf) { writeEscapedString(x, strlen(x), buf); }
inline void writeText(const char * x, size_t size, WriteBuffer & buf) { writeEscapedString(x, size, buf); } inline void writeText(const char * x, size_t size, WriteBuffer & buf) { writeEscapedString(x, size, buf); }
inline void writeText(const LocalDate & x, WriteBuffer & buf) { writeDateText(x, buf); } inline void writeText(const LocalDate & x, WriteBuffer & buf) { writeDateText(x, buf); }
inline void writeText(const LocalDateTime & x, WriteBuffer & buf) { writeDateTimeText(x, buf); } inline void writeText(const LocalDateTime & x, WriteBuffer & buf) { writeDateTimeText(x, buf); }
/// Строки, даты, даты-с-временем - в одинарных кавычках с C-style эскейпингом. Числа - без. /// String, date, datetime are in single quotes with C-style escaping. Numbers - without.
template <typename T> template <typename T>
inline typename std::enable_if<std::is_arithmetic<T>::value, void>::type inline typename std::enable_if<std::is_arithmetic<T>::value, void>::type
writeQuoted(const T & x, WriteBuffer & buf) { writeText(x, buf); } writeQuoted(const T & x, WriteBuffer & buf) { writeText(x, buf); }
@ -633,7 +633,7 @@ inline void writeQuoted(const LocalDateTime & x, WriteBuffer & buf)
} }
/// Строки, даты, даты-с-временем - в двойных кавычках с C-style эскейпингом. Числа - без. /// String, date, datetime are in double quotes with C-style escaping. Numbers - without.
template <typename T> template <typename T>
inline typename std::enable_if<std::is_arithmetic<T>::value, void>::type inline typename std::enable_if<std::is_arithmetic<T>::value, void>::type
writeDoubleQuoted(const T & x, WriteBuffer & buf) { writeText(x, buf); } writeDoubleQuoted(const T & x, WriteBuffer & buf) { writeText(x, buf); }
@ -655,7 +655,7 @@ inline void writeDoubleQuoted(const LocalDateTime & x, WriteBuffer & buf)
} }
/// Строки - в двойных кавычках и с CSV-эскейпингом; даты, даты-с-временем - в двойных кавычках. Числа - без. /// String - in double quotes and with CSV-escaping; date, datetime - in double quotes. Numbers - without.
template <typename T> template <typename T>
inline typename std::enable_if<std::is_arithmetic<T>::value, void>::type inline typename std::enable_if<std::is_arithmetic<T>::value, void>::type
writeCSV(const T & x, WriteBuffer & buf) { writeText(x, buf); } writeCSV(const T & x, WriteBuffer & buf) { writeText(x, buf); }
@ -708,11 +708,11 @@ void writeText(const std::vector<T> & x, WriteBuffer & buf)
/// Сериализация эксепшена (чтобы его можно было передать по сети) /// Serialize exception (so that it can be transferred over the network)
void writeException(const Exception & e, WriteBuffer & buf); void writeException(const Exception & e, WriteBuffer & buf);
/// Простой для использования метод преобразования чего-либо в строку в текстовом виде. /// An easy-to-use method for converting something to a string in text form.
template <typename T> template <typename T>
inline String toString(const T & x) inline String toString(const T & x)
{ {

View File

@ -8,7 +8,7 @@
#include <Core/Types.h> #include <Core/Types.h>
#include <IO/WriteBuffer.h> #include <IO/WriteBuffer.h>
/// 20 цифр или 19 цифр и знак /// 20 digits or 19 digits and a sign
#define WRITE_HELPERS_MAX_INT_WIDTH 20U #define WRITE_HELPERS_MAX_INT_WIDTH 20U
@ -17,14 +17,14 @@ namespace DB
namespace detail namespace detail
{ {
/** Смотрите: /** See:
* https://github.com/localvoid/cxx-benchmark-itoa * https://github.com/localvoid/cxx-benchmark-itoa
* http://www.slideshare.net/andreialexandrescu1/three-optimization-tips-for-c-15708507 * http://www.slideshare.net/andreialexandrescu1/three-optimization-tips-for-c-15708507
* http://vimeo.com/55639112 * http://vimeo.com/55639112
*/ */
/// Обычный способ, если в буфере не хватает места, чтобы там поместилось любое число. /// The usual way, if there is not enough space in the buffer for any number to fit there.
template <typename T> template <typename T>
void writeUIntTextFallback(T x, WriteBuffer & buf) void writeUIntTextFallback(T x, WriteBuffer & buf)
{ {
@ -52,9 +52,9 @@ namespace detail
} }
/** Подсчёт количества десятичных цифр в числе. /** Count the number of decimal digits in the number.
* Хорошо работает для неравномерного распределения чисел, которое обычно бывает. * Works well for nonuniform distribution of numbers, which usually happens.
* Если большинство чисел длинные, то лучше работал бы branchless код с инструкцией bsr и хитрым преобразованием. * If most of the numbers are long, then a "branchless" code with a `bsr` instruction and a smart conversion would work better.
*/ */
template <typename T> template <typename T>
UInt32 digits10(T x) UInt32 digits10(T x)
@ -91,10 +91,10 @@ namespace detail
} }
/** Преобразует по две цифры за итерацию. /** Converts two digits per iteration.
* Хорошо работает для неравномерного распределения чисел, которое обычно бывает. * Works well for the nonuniform distribution of numbers, which usually happens.
* Если большинство чисел длинные, и если не жалко кэш, то лучше работал бы вариант * If most of the numbers are long, and if you do care about the cache, then the variant
* с большой таблицей и четырьмя цифрами за итерацию. * with a large table and four digits per iteration.
*/ */
template <typename T> template <typename T>
UInt32 writeUIntText(T x, char * dst) UInt32 writeUIntText(T x, char * dst)
@ -138,7 +138,7 @@ namespace detail
} }
/** Если в буфере есть достаточно места - вызывает оптимизированный вариант, иначе - обычный вариант. /** If there is enough space in the buffer - calls an optimized version, otherwise - the normal version.
*/ */
template <typename T> template <typename T>
void writeUIntText(T x, WriteBuffer & buf) void writeUIntText(T x, WriteBuffer & buf)
@ -150,12 +150,12 @@ namespace detail
} }
/** Обёртка для знаковых чисел. /** Wrapper for signed numbers.
*/ */
template <typename T> template <typename T>
void writeSIntText(T x, WriteBuffer & buf) void writeSIntText(T x, WriteBuffer & buf)
{ {
/// Особый случай для самого маленького отрицательного числа /// A special case for the smallest negative number
if (unlikely(x == std::numeric_limits<T>::min())) if (unlikely(x == std::numeric_limits<T>::min()))
{ {
if (sizeof(x) == 1) if (sizeof(x) == 1)

View File

@ -11,15 +11,15 @@ class ReadBuffer;
class WriteBuffer; class WriteBuffer;
/** Копирует данные из ReadBuffer в WriteBuffer, все что есть. /** Copies data from ReadBuffer to WriteBuffer, all that is.
*/ */
void copyData(ReadBuffer & from, WriteBuffer & to); void copyData(ReadBuffer & from, WriteBuffer & to);
/** Копирует bytes байт из ReadBuffer в WriteBuffer. Если нет bytes байт, то кидает исключение. /** Copies `bytes` bytes from ReadBuffer to WriteBuffer. If there are no `bytes` bytes, then throws an exception.
*/ */
void copyData(ReadBuffer & from, WriteBuffer & to, size_t bytes); void copyData(ReadBuffer & from, WriteBuffer & to, size_t bytes);
/** То же самое, с условием на остановку. /** The same, with the condition to cancel.
*/ */
void copyData(ReadBuffer & from, WriteBuffer & to, std::atomic<bool> & is_cancelled); void copyData(ReadBuffer & from, WriteBuffer & to, std::atomic<bool> & is_cancelled);
void copyData(ReadBuffer & from, WriteBuffer & to, size_t bytes, std::atomic<bool> & is_cancelled); void copyData(ReadBuffer & from, WriteBuffer & to, size_t bytes, std::atomic<bool> & is_cancelled);

View File

@ -8,12 +8,12 @@
namespace DB namespace DB
{ {
/** Создать объект для чтения данных из файла. /** Create an object to read data from a file.
* estimated_size - количество байтов, которые надо читать * estimated_size - the number of bytes to read
* aio_threshold - минимальное количество байт для асинхронных операций чтения * aio_threshold - the minimum number of bytes for asynchronous reads
* *
* Если aio_threshold = 0 или estimated_size < aio_threshold, операции чтения выполняются синхронно. * If aio_threshold = 0 or estimated_size < aio_threshold, read operations are executed synchronously.
* В противном случае операции чтения выполняются асинхронно. * Otherwise, the read operations are performed asynchronously.
*/ */
std::unique_ptr<ReadBufferFromFileBase> createReadBufferFromFileBase(const std::string & filename_, std::unique_ptr<ReadBufferFromFileBase> createReadBufferFromFileBase(const std::string & filename_,
size_t estimated_size, size_t estimated_size,

View File

@ -6,12 +6,12 @@
namespace DB namespace DB
{ {
/** Создать объект для записи данных в файл. /** Create an object to write data to a file.
* estimated_size - количество байтов, которые надо записать * estimated_size - number of bytes to write
* aio_threshold - минимальное количество байт для асинхронных операций записи * aio_threshold - the minimum number of bytes for asynchronous writes
* *
* Если aio_threshold = 0 или estimated_size < aio_threshold, операции записи выполняются синхронно. * If aio_threshold = 0 or estimated_size < aio_threshold, the write operations are executed synchronously.
* В противном случае операции записи выполняются асинхронно. * Otherwise, write operations are performed asynchronously.
*/ */
WriteBufferFromFileBase * createWriteBufferFromFileBase(const std::string & filename_, WriteBufferFromFileBase * createWriteBufferFromFileBase(const std::string & filename_,
size_t estimated_size, size_t estimated_size,

View File

@ -6,7 +6,7 @@
namespace DB namespace DB
{ {
/** ALTER запрос /** ALTER query
* ALTER TABLE [db.]name_type * ALTER TABLE [db.]name_type
* ADD COLUMN col_name type [AFTER col_after], * ADD COLUMN col_name type [AFTER col_after],
* DROP COLUMN col_drop [FROM PARTITION partition], * DROP COLUMN col_drop [FROM PARTITION partition],
@ -43,35 +43,35 @@ public:
int type = NO_TYPE; int type = NO_TYPE;
/** В запросе ADD COLUMN здесь хранится имя и тип добавляемого столбца /** The ADD COLUMN query stores the name and type of the column to add
* В запросе DROP это поле не используется * This field is not used in the DROP query
* В запросе MODIFY здесь хранится имя столбца и новый тип * In MODIFY query, the column name and the new type are stored here
*/ */
ASTPtr col_decl; ASTPtr col_decl;
/** В запросе ADD COLUMN здесь опционально хранится имя столбца, следующее после AFTER /** The ADD COLUMN query here optionally stores the name of the column following AFTER
* В запросе DROP здесь хранится имя столбца для удаления * The DROP query stores the column name for deletion here
*/ */
ASTPtr column; ASTPtr column;
/** Для MODIFY PRIMARY KEY /** For MODIFY PRIMARY KEY
*/ */
ASTPtr primary_key; ASTPtr primary_key;
/** В запросах DROP PARTITION и RESHARD PARTITION здесь хранится имя partition'а. /** In DROP PARTITION and RESHARD PARTITION queries, the name of the partition is stored here.
*/ */
ASTPtr partition; ASTPtr partition;
bool detach = false; /// true для DETACH PARTITION. bool detach = false; /// true for DETACH PARTITION.
bool part = false; /// true для ATTACH PART bool part = false; /// true for ATTACH PART
bool do_copy = false; /// для RESHARD PARTITION. bool do_copy = false; /// for RESHARD PARTITION.
/** Для FETCH PARTITION - путь в ZK к шарду, с которого скачивать партицию. /** For FETCH PARTITION - the path in ZK to the shard, from which to download the partition.
*/ */
String from; String from;
/** Для RESHARD PARTITION. /** For RESHARD PARTITION.
*/ */
ASTPtr last_partition; ASTPtr last_partition;
ASTPtr weighted_zookeeper_paths; ASTPtr weighted_zookeeper_paths;
@ -96,7 +96,7 @@ public:
ASTAlterQuery(StringRange range_ = StringRange()); ASTAlterQuery(StringRange range_ = StringRange());
/** Получить текст, который идентифицирует этот элемент. */ /** Get the text that identifies this element. */
String getID() const override; String getID() const override;
ASTPtr clone() const override; ASTPtr clone() const override;

View File

@ -9,7 +9,7 @@ struct ASTCheckQuery : public ASTQueryWithOutput
{ {
ASTCheckQuery(StringRange range_ = StringRange()) : ASTQueryWithOutput(range_) {}; ASTCheckQuery(StringRange range_ = StringRange()) : ASTQueryWithOutput(range_) {};
/** Получить текст, который идентифицирует этот элемент. */ /** Get the text that identifies this element. */
String getID() const override { return ("CheckQuery_" + database + "_" + table); }; String getID() const override { return ("CheckQuery_" + database + "_" + table); };
ASTPtr clone() const override ASTPtr clone() const override

View File

@ -8,12 +8,12 @@ namespace DB
{ {
/** CREATE TABLE или ATTACH TABLE запрос /** CREATE TABLE or ATTACH TABLE query
*/ */
class ASTCreateQuery : public IAST class ASTCreateQuery : public IAST
{ {
public: public:
bool attach{false}; /// Запрос ATTACH TABLE, а не CREATE TABLE. bool attach{false}; /// Query ATTACH TABLE, not CREATE TABLE.
bool if_not_exists{false}; bool if_not_exists{false};
bool is_view{false}; bool is_view{false};
bool is_materialized_view{false}; bool is_materialized_view{false};
@ -23,7 +23,7 @@ public:
String table; String table;
ASTPtr columns; ASTPtr columns;
ASTPtr storage; ASTPtr storage;
ASTPtr inner_storage; /// Внутренний engine для запроса CREATE MATERIALIZED VIEW ASTPtr inner_storage; /// Internal engine for the CREATE MATERIALIZED VIEW query
String as_database; String as_database;
String as_table; String as_table;
ASTPtr select; ASTPtr select;
@ -31,7 +31,7 @@ public:
ASTCreateQuery() = default; ASTCreateQuery() = default;
ASTCreateQuery(const StringRange range_) : IAST(range_) {} ASTCreateQuery(const StringRange range_) : IAST(range_) {}
/** Получить текст, который идентифицирует этот элемент. */ /** Get the text that identifies this element. */
String getID() const override { return (attach ? "AttachQuery_" : "CreateQuery_") + database + "_" + table; }; String getID() const override { return (attach ? "AttachQuery_" : "CreateQuery_") + database + "_" + table; };
ASTPtr clone() const override ASTPtr clone() const override

View File

@ -7,12 +7,12 @@ namespace DB
{ {
/** DROP запрос /** DROP query
*/ */
class ASTDropQuery : public IAST class ASTDropQuery : public IAST
{ {
public: public:
bool detach{false}; /// Запрос DETACH, а не DROP. bool detach{false}; /// DETACH query, not DROP.
bool if_exists{false}; bool if_exists{false};
String database; String database;
String table; String table;
@ -20,7 +20,7 @@ public:
ASTDropQuery() = default; ASTDropQuery() = default;
ASTDropQuery(const StringRange range_) : IAST(range_) {} ASTDropQuery(const StringRange range_) : IAST(range_) {}
/** Получить текст, который идентифицирует этот элемент. */ /** Get the text that identifies this element. */
String getID() const override { return (detach ? "DetachQuery_" : "DropQuery_") + database + "_" + table; }; String getID() const override { return (detach ? "DetachQuery_" : "DropQuery_") + database + "_" + table; };
ASTPtr clone() const override { return std::make_shared<ASTDropQuery>(*this); } ASTPtr clone() const override { return std::make_shared<ASTDropQuery>(*this); }

View File

@ -38,7 +38,7 @@ public:
} }
} }
/** Вывести список выражений в секциях запроса SELECT - по одному выражению на строку. /** Output a list of expressions in the SELECT query sections - one expression per line.
*/ */
void formatImplMultiline(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const void formatImplMultiline(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const
{ {

View File

@ -6,7 +6,7 @@
namespace DB namespace DB
{ {
/** Идентификатор (столбца или алиас) /** Identifier (column or alias)
*/ */
class ASTIdentifier : public ASTWithAlias class ASTIdentifier : public ASTWithAlias
{ {
@ -19,10 +19,10 @@ public:
Format, Format,
}; };
/// имя. У составного идентификатора здесь будет конкатенированное имя (вида a.b.c), а отдельные составляюшие будут доступны внутри children. /// name. The composite identifier here will have a concatenated name (of the form a.b.c), and individual components will be available inside the children.
String name; String name;
/// чего идентифицирует этот идентификатор /// what this identifier identifies
Kind kind; Kind kind;
ASTIdentifier() = default; ASTIdentifier() = default;
@ -31,7 +31,7 @@ public:
String getColumnName() const override { return name; } String getColumnName() const override { return name; }
/** Получить текст, который идентифицирует этот элемент. */ /** Get the text that identifies this element. */
String getID() const override { return "Identifier_" + name; } String getID() const override { return "Identifier_" + name; }
ASTPtr clone() const override { return std::make_shared<ASTIdentifier>(*this); } ASTPtr clone() const override { return std::make_shared<ASTIdentifier>(*this); }

View File

@ -7,7 +7,7 @@ namespace DB
{ {
/** INSERT запрос /** INSERT query
*/ */
class ASTInsertQuery : public IAST class ASTInsertQuery : public IAST
{ {
@ -17,16 +17,16 @@ public:
ASTPtr columns; ASTPtr columns;
String format; String format;
ASTPtr select; ASTPtr select;
/// Идентификатор запроса INSERT. Используется при репликации. /// INSERT query identifier. Used for replication.
String insert_id; String insert_id;
/// Данные для вставки /// Data to insert
const char * data = nullptr; const char * data = nullptr;
const char * end = nullptr; const char * end = nullptr;
ASTInsertQuery() = default; ASTInsertQuery() = default;
ASTInsertQuery(const StringRange range_) : IAST(range_) {} ASTInsertQuery(const StringRange range_) : IAST(range_) {}
/** Получить текст, который идентифицирует этот элемент. */ /** Get the text that identifies this element. */
String getID() const override { return "InsertQuery_" + database + "_" + table; }; String getID() const override { return "InsertQuery_" + database + "_" + table; };
ASTPtr clone() const override ASTPtr clone() const override

View File

@ -8,7 +8,7 @@
namespace DB namespace DB
{ {
/** Литерал (атомарный) - число, строка, NULL /** Literal (atomic) - number, string, NULL
*/ */
class ASTLiteral : public ASTWithAlias class ASTLiteral : public ASTWithAlias
{ {
@ -20,7 +20,7 @@ public:
String getColumnName() const override; String getColumnName() const override;
/** Получить текст, который идентифицирует этот элемент. */ /** Get the text that identifies this element. */
String getID() const override { return "Literal_" + applyVisitor(FieldVisitorDump(), value); } String getID() const override { return "Literal_" + applyVisitor(FieldVisitorDump(), value); }
ASTPtr clone() const override { return std::make_shared<ASTLiteral>(*this); } ASTPtr clone() const override { return std::make_shared<ASTLiteral>(*this); }

View File

@ -6,20 +6,20 @@
namespace DB namespace DB
{ {
/** Пара из имени и типа. Например, browser FixedString(2). /** A pair of the name and type. For example, browser FixedString(2).
*/ */
class ASTNameTypePair : public IAST class ASTNameTypePair : public IAST
{ {
public: public:
/// имя /// name
String name; String name;
/// тип /// type
ASTPtr type; ASTPtr type;
ASTNameTypePair() = default; ASTNameTypePair() = default;
ASTNameTypePair(const StringRange range_) : IAST(range_) {} ASTNameTypePair(const StringRange range_) : IAST(range_) {}
/** Получить текст, который идентифицирует этот элемент. */ /** Get the text that identifies this element. */
String getID() const override { return "NameTypePair_" + name; } String getID() const override { return "NameTypePair_" + name; }
ASTPtr clone() const override ASTPtr clone() const override

View File

@ -7,7 +7,7 @@ namespace DB
{ {
/** OPTIMIZE запрос /** OPTIMIZE query
*/ */
class ASTOptimizeQuery : public IAST class ASTOptimizeQuery : public IAST
{ {
@ -15,9 +15,9 @@ public:
String database; String database;
String table; String table;
/// Может быть указана партиция, в которой производить оптимизацию. /// The partition to optimize can be specified.
String partition; String partition;
/// Может быть указан флаг - производить оптимизацию "до конца" вместо одного шага. /// A flag can be specified - perform optimization "to the end" instead of one step.
bool final; bool final;
/// Do deduplicate (default: false) /// Do deduplicate (default: false)
bool deduplicate; bool deduplicate;
@ -25,7 +25,7 @@ public:
ASTOptimizeQuery() = default; ASTOptimizeQuery() = default;
ASTOptimizeQuery(const StringRange range_) : IAST(range_) {} ASTOptimizeQuery(const StringRange range_) : IAST(range_) {}
/** Получить текст, который идентифицирует этот элемент. */ /** Get the text that identifies this element. */
String getID() const override { return "OptimizeQuery_" + database + "_" + table + "_" + partition + (final ? "_final" : "") + (deduplicate ? "_deduplicate" : ""); }; String getID() const override { return "OptimizeQuery_" + database + "_" + table + "_" + partition + (final ? "_final" : "") + (deduplicate ? "_deduplicate" : ""); };
ASTPtr clone() const override { return std::make_shared<ASTOptimizeQuery>(*this); } ASTPtr clone() const override { return std::make_shared<ASTOptimizeQuery>(*this); }

View File

@ -28,7 +28,7 @@ protected:
}; };
/// Объявляет класс-наследник ASTQueryWithOutput с реализованными методами getID и clone. /// Declares the class-successor of ASTQueryWithOutput with implemented methods getID and clone.
#define DEFINE_AST_QUERY_WITH_OUTPUT(Name, ID, Query) \ #define DEFINE_AST_QUERY_WITH_OUTPUT(Name, ID, Query) \
class Name : public ASTQueryWithOutput \ class Name : public ASTQueryWithOutput \
{ \ { \

View File

@ -8,7 +8,7 @@ namespace DB
{ {
/** Запрос с указанием названия таблицы и, возможно, БД и секцией FORMAT. /** Query specifying table name and, possibly, the database and the FORMAT section.
*/ */
class ASTQueryWithTableAndOutput : public ASTQueryWithOutput class ASTQueryWithTableAndOutput : public ASTQueryWithOutput
{ {
@ -28,7 +28,7 @@ protected:
}; };
/// Объявляет класс-наследник ASTQueryWithTableAndOutput с реализованными методами getID и clone. /// Declares the inheritance class of ASTQueryWithTableAndOutput with the implementation of methods getID and clone.
#define DEFINE_AST_QUERY_WITH_TABLE_AND_OUTPUT(Name, ID, Query) \ #define DEFINE_AST_QUERY_WITH_TABLE_AND_OUTPUT(Name, ID, Query) \
class Name : public ASTQueryWithTableAndOutput \ class Name : public ASTQueryWithTableAndOutput \
{ \ { \

View File

@ -7,7 +7,7 @@ namespace DB
{ {
/** RENAME запрос /** RENAME query
*/ */
class ASTRenameQuery : public IAST class ASTRenameQuery : public IAST
{ {
@ -30,7 +30,7 @@ public:
ASTRenameQuery() = default; ASTRenameQuery() = default;
ASTRenameQuery(const StringRange range_) : IAST(range_) {} ASTRenameQuery(const StringRange range_) : IAST(range_) {}
/** Получить текст, который идентифицирует этот элемент. */ /** Get the text that identifies this element. */
String getID() const override { return "Rename"; }; String getID() const override { return "Rename"; };
ASTPtr clone() const override { return std::make_shared<ASTRenameQuery>(*this); } ASTPtr clone() const override { return std::make_shared<ASTRenameQuery>(*this); }

View File

@ -6,13 +6,13 @@
namespace DB namespace DB
{ {
/** Коэффициент сэмплирования вида 0.1 или 1/10. /** Sampling factor in the form 0.1 or 1/10.
* Важно сохранять его как рациональное число без преобразования в IEEE-754. * It's important to save it as a rational number without converting it to IEEE-754.
*/ */
class ASTSampleRatio : public IAST class ASTSampleRatio : public IAST
{ {
public: public:
using BigNum = __uint128_t; /// Должен вмещать в себя результат перемножения двух UInt64. using BigNum = __uint128_t; /// Must contain the result of multiplying two UInt64.
struct Rational struct Rational
{ {

View File

@ -19,26 +19,26 @@ public:
ASTSelectQuery() = default; ASTSelectQuery() = default;
ASTSelectQuery(const StringRange range_); ASTSelectQuery(const StringRange range_);
/** Получить текст, который идентифицирует этот элемент. */ /** Get the text that identifies this element. */
String getID() const override { return "SelectQuery"; }; String getID() const override { return "SelectQuery"; };
/// Проверить наличие функции arrayJoin. (Не большого ARRAY JOIN.) /// Check for the presence of the `arrayJoin` function. (Not capital `ARRAY JOIN`.)
static bool hasArrayJoin(const ASTPtr & ast); static bool hasArrayJoin(const ASTPtr & ast);
/// Содержит ли запрос астериск? /// Does the query contain an asterisk?
bool hasAsterisk() const; bool hasAsterisk() const;
/// Переименовать столбцы запроса в такие же имена, как в исходном запросе. /// Rename the query columns to the same names as in the original query.
void renameColumns(const ASTSelectQuery & source); void renameColumns(const ASTSelectQuery & source);
/// Переписывает select_expression_list, чтобы вернуть только необходимые столбцы в правильном порядке. /// Rewrites select_expression_list to return only the required columns in the correct order.
void rewriteSelectExpressionList(const Names & required_column_names); void rewriteSelectExpressionList(const Names & required_column_names);
bool isUnionAllHead() const { return (prev_union_all == nullptr) && next_union_all != nullptr; } bool isUnionAllHead() const { return (prev_union_all == nullptr) && next_union_all != nullptr; }
ASTPtr clone() const override; ASTPtr clone() const override;
/// Получить глубокую копию дерева первого запроса SELECT. /// Get a deep copy of the first SELECT query tree.
ASTPtr cloneFirstSelect() const; ASTPtr cloneFirstSelect() const;
private: private:
@ -72,13 +72,13 @@ public:
void setDatabaseIfNeeded(const String & database_name); void setDatabaseIfNeeded(const String & database_name);
void replaceDatabaseAndTable(const String & database_name, const String & table_name); void replaceDatabaseAndTable(const String & database_name, const String & table_name);
/// Двусвязный список запросов SELECT внутри запроса UNION ALL. /// A double-linked list of SELECT queries inside a UNION ALL query.
/// Следующий запрос SELECT в цепочке UNION ALL, если такой есть /// The next SELECT query in the UNION ALL chain, if there is one
ASTPtr next_union_all; ASTPtr next_union_all;
/// Предыдущий запрос SELECT в цепочке UNION ALL (не вставляется в children и не клонируется) /// Previous SELECT query in the UNION ALL chain (not inserted into children and not cloned)
/// Указатель голый по следующим причинам: /// The pointer is null for the following reasons:
/// 1. чтобы предотвратить появление циклических зависимостей и, значит, утечки памяти; /// 1. to prevent the occurrence of cyclic dependencies and, hence, memory leaks;
IAST * prev_union_all = nullptr; IAST * prev_union_all = nullptr;
protected: protected:

View File

@ -8,8 +8,8 @@ namespace DB
class Set; class Set;
/** Множество. В процессе вычисления, на множество заменяется выражение в секции IN /** The set. During the calculation, the expression in the IN section is replaced by the set
* - подзапрос или явное перечисление значений. * - a subquery or an explicit enumeration of values.
*/ */
class ASTSet : public IAST class ASTSet : public IAST
{ {
@ -27,8 +27,8 @@ public:
protected: protected:
void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override
{ {
/** Подготовленное множество. В пользовательских запросах такого не бывает, но такое бывает после промежуточных преобразований запроса. /** Prepared set. In user requests, this does not happen, but this happens after the intermediate query transformation.
* Выведем его не по-настоящему (это не будет корректным запросом, но покажет, что здесь было множество). * Output it for not real (this will not be a valid query, but it will show that there was a set).
*/ */
settings.ostr << (settings.hilite ? hilite_keyword : "") settings.ostr << (settings.hilite ? hilite_keyword : "")
<< "(...)" << "(...)"

View File

@ -9,7 +9,7 @@ namespace DB
{ {
/** SET запрос /** SET query
*/ */
class ASTSetQuery : public IAST class ASTSetQuery : public IAST
{ {
@ -23,12 +23,12 @@ public:
using Changes = std::vector<Change>; using Changes = std::vector<Change>;
Changes changes; Changes changes;
bool global; /// Если запрос SET GLOBAL. bool global; /// If the query is SET GLOBAL.
ASTSetQuery() = default; ASTSetQuery() = default;
ASTSetQuery(const StringRange range_) : IAST(range_) {} ASTSetQuery(const StringRange range_) : IAST(range_) {}
/** Получить текст, который идентифицирует этот элемент. */ /** Get the text that identifies this element. */
String getID() const override { return "Set"; }; String getID() const override { return "Set"; };
ASTPtr clone() const override { return std::make_shared<ASTSetQuery>(*this); } ASTPtr clone() const override { return std::make_shared<ASTSetQuery>(*this); }

View File

@ -9,7 +9,7 @@ namespace DB
{ {
/** Запрос SHOW TABLES или SHOW DATABASES /** Query SHOW TABLES or SHOW DATABASES
*/ */
class ASTShowTablesQuery : public ASTQueryWithOutput class ASTShowTablesQuery : public ASTQueryWithOutput
{ {
@ -22,7 +22,7 @@ public:
ASTShowTablesQuery() = default; ASTShowTablesQuery() = default;
ASTShowTablesQuery(const StringRange range_) : ASTQueryWithOutput(range_) {} ASTShowTablesQuery(const StringRange range_) : ASTQueryWithOutput(range_) {}
/** Получить текст, который идентифицирует этот элемент. */ /** Get the text that identifies this element. */
String getID() const override { return "ShowTables"; }; String getID() const override { return "ShowTables"; };
ASTPtr clone() const override ASTPtr clone() const override

View File

@ -7,7 +7,7 @@ namespace DB
{ {
/** Подзарос SELECT /** SELECT subquery
*/ */
class ASTSubquery : public ASTWithAlias class ASTSubquery : public ASTWithAlias
{ {
@ -15,7 +15,7 @@ public:
ASTSubquery() = default; ASTSubquery() = default;
ASTSubquery(const StringRange range_) : ASTWithAlias(range_) {} ASTSubquery(const StringRange range_) : ASTWithAlias(range_) {}
/** Получить текст, который идентифицирует этот элемент. */ /** Get the text that identifies this element. */
String getID() const override { return "Subquery"; } String getID() const override { return "Subquery"; }
ASTPtr clone() const override ASTPtr clone() const override

View File

@ -7,7 +7,7 @@ namespace DB
{ {
/** USE запрос /** USE query
*/ */
class ASTUseQuery : public IAST class ASTUseQuery : public IAST
{ {
@ -17,7 +17,7 @@ public:
ASTUseQuery() = default; ASTUseQuery() = default;
ASTUseQuery(const StringRange range_) : IAST(range_) {} ASTUseQuery(const StringRange range_) : IAST(range_) {}
/** Получить текст, который идентифицирует этот элемент. */ /** Get the text that identifies this element. */
String getID() const override { return "UseQuery_" + database; }; String getID() const override { return "UseQuery_" + database; };
ASTPtr clone() const override { return std::make_shared<ASTUseQuery>(*this); } ASTPtr clone() const override { return std::make_shared<ASTUseQuery>(*this); }

View File

@ -7,12 +7,12 @@ namespace DB
{ {
/** Базовый класс для AST, которые могут содержать алиас (идентификаторы, литералы, функции). /** Base class for AST, which can contain an alias (identifiers, literals, functions).
*/ */
class ASTWithAlias : public IAST class ASTWithAlias : public IAST
{ {
public: public:
/// Алиас, если есть, или пустая строка. /// The alias, if any, or an empty string.
String alias; String alias;
using IAST::IAST; using IAST::IAST;
@ -21,7 +21,7 @@ public:
String tryGetAlias() const override { return alias; } String tryGetAlias() const override { return alias; }
void setAlias(const String & to) override { alias = to; } void setAlias(const String & to) override { alias = to; }
/// Вызывает formatImplWithoutAlias, а также выводит алиас. Если надо - заключает всё выражение в скобки. /// Calls formatImplWithoutAlias, and also outputs an alias. If necessary, encloses the entire expression in brackets.
void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override final; void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override final;
virtual void formatImplWithoutAlias(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const = 0; virtual void formatImplWithoutAlias(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const = 0;

View File

@ -5,9 +5,9 @@
namespace DB namespace DB
{ {
/** Если прямо сейчас не s, то ошибка. /** If right now is not `s`, then an error.
* Если word_boundary установлен в true, и последний символ строки - словарный (\w), * If word_boundary is set to true, and the last character of the string - word (\w),
* то проверяется, что последующий символ строки не словарный. * then it is checked that the next character in the string is not a word character.
*/ */
class ParserString : public IParserBase class ParserString : public IParserBase
{ {
@ -27,7 +27,7 @@ protected:
}; };
/** пробельные символы /** whitespace characters
*/ */
class ParserWhiteSpace : public IParserBase class ParserWhiteSpace : public IParserBase
{ {
@ -61,7 +61,7 @@ protected:
}; };
/** комментарии '--' или c-style /** comments '--' or c-style
*/ */
class ParserComment : public IParserBase class ParserComment : public IParserBase
{ {

View File

@ -15,9 +15,9 @@ protected:
}; };
/** Если в скобках выражение из одного элемента - возвращает в node этот элемент; /** If in parenthesis an expression from one element - returns this element in `node`;
* или если в скобках - подзапрос SELECT - то возвращает в node этот подзапрос; * or if there is a SELECT subquery in parenthesis, then this subquery returned in `node`;
* иначе возвращает функцию tuple от содержимого скобок. * otherwise returns `tuple` function from the contents of brackets.
*/ */
class ParserParenthesisExpression : public IParserBase class ParserParenthesisExpression : public IParserBase
{ {
@ -27,7 +27,7 @@ protected:
}; };
/** Подзапрос SELECT в скобках. /** The SELECT subquery is in parenthesis.
*/ */
class ParserSubquery : public IParserBase class ParserSubquery : public IParserBase
{ {
@ -37,7 +37,7 @@ protected:
}; };
/** Идентификатор, например, x_yz123 или `something special` /** An identifier, for example, x_yz123 or `something special`
*/ */
class ParserIdentifier : public IParserBase class ParserIdentifier : public IParserBase
{ {
@ -47,7 +47,7 @@ protected:
}; };
/** Идентификатор, возможно, содержащий точку, например, x_yz123 или `something special` или Hits.EventTime /** An identifier, possibly containing a dot, for example, x_yz123 or `something special` or Hits.EventTime
*/ */
class ParserCompoundIdentifier : public IParserBase class ParserCompoundIdentifier : public IParserBase
{ {
@ -76,11 +76,11 @@ protected:
}; };
/** Функция, например, f(x, y + 1, g(z)). /** A function, for example, f(x, y + 1, g(z)).
* Или агрегатная функция: sum(x + f(y)), corr(x, y). По синтаксису - такая же, как обычная функция. * Or an aggregate function: sum(x + f(y)), corr(x, y). The syntax is the same as the usual function.
* Или параметрическая агрегатная функция: quantile(0.9)(x + y). * Or a parametric aggregate function: quantile(0.9)(x + y).
* Синтаксис - две пары круглых скобок вместо одной. Первая - для параметров, вторая - для аргументов. * Syntax - two pairs of parentheses instead of one. The first is for parameters, the second for arguments.
* Для функций может быть указан модификатор DISTINCT, например count(DISTINCT x, y). * For functions, the DISTINCT modifier can be specified, for example, count(DISTINCT x, y).
*/ */
class ParserFunction : public IParserBase class ParserFunction : public IParserBase
{ {
@ -139,11 +139,11 @@ protected:
}; };
/** Массив литералов. /** An array of literals.
* Массивы могут распарситься и как применение оператора []. * Arrays can also be parsed as an application of [] operator.
* Но парсинг всего массива как целой константы серьёзно ускоряет анализ выражений в случае очень больших массивов. * But parsing the whole array as a whole constant seriously speeds up the analysis of expressions in the case of very large arrays.
* Мы пробуем распарсить массив как массив литералов сначала (fast path), * We try to parse the array as an array of literals first (fast path),
* а если не получилось (когда массив состоит из сложных выражений) - парсим как применение оператора [] (slow path). * and if it did not work out (when the array consists of complex expressions) - parse as an application of [] operator (slow path).
*/ */
class ParserArrayOfLiterals : public IParserBase class ParserArrayOfLiterals : public IParserBase
{ {
@ -153,7 +153,7 @@ protected:
}; };
/** Литерал - одно из: NULL, UInt64, Int64, Float64, String. /** The literal is one of: NULL, UInt64, Int64, Float64, String.
*/ */
class ParserLiteral : public IParserBase class ParserLiteral : public IParserBase
{ {
@ -163,7 +163,7 @@ protected:
}; };
/** Алиас - идентификатор, перед которым идёт AS. Например: AS x_yz123. /** The alias is the identifier before which `AS` comes. For example: AS x_yz123.
*/ */
struct ParserAliasBase struct ParserAliasBase
{ {
@ -193,7 +193,7 @@ using ParserAlias = ParserAliasImpl<ParserIdentifier>;
using ParserCastExpressionAlias = ParserAliasImpl<ParserTypeInCastExpression>; using ParserCastExpressionAlias = ParserAliasImpl<ParserTypeInCastExpression>;
/** Элемент выражения - одно из: выражение в круглых скобках, массив, литерал, функция, идентификатор, звёздочка. /** The expression element is one of: an expression in parentheses, an array, a literal, a function, an identifier, an asterisk.
*/ */
class ParserExpressionElement : public IParserBase class ParserExpressionElement : public IParserBase
{ {
@ -203,7 +203,7 @@ protected:
}; };
/** Элемент выражения, возможно, с алиасом, если уместно. /** An expression element, possibly with an alias, if appropriate.
*/ */
template <typename ParserAlias> template <typename ParserAlias>
class ParserWithOptionalAliasImpl : public IParserBase class ParserWithOptionalAliasImpl : public IParserBase
@ -237,7 +237,7 @@ protected:
bool parseImpl(Pos & pos, Pos end, ASTPtr & node, Pos & max_parsed_pos, Expected & expected); bool parseImpl(Pos & pos, Pos end, ASTPtr & node, Pos & max_parsed_pos, Expected & expected);
}; };
/** Путь шарда в ZooKeeper вместе с весом. /** The path of the shard in ZooKeeper along with the weight.
*/ */
class ParserWeightedZooKeeperPath : public IParserBase class ParserWeightedZooKeeperPath : public IParserBase
{ {

View File

@ -9,13 +9,13 @@
namespace DB namespace DB
{ {
/** Идущие подряд пары строк: оператор и соответствующая ему функция. Например, "+" -> "plus". /** Consequent pairs of rows: the operator and the corresponding function. For example, "+" -> "plus".
* Порядок парсинга операторов имеет значение. * The parsing order of the operators is significant.
*/ */
using Operators_t = const char **; using Operators_t = const char **;
/** Список элементов, разделённых чем-либо. */ /** List of elements separated by something. */
class ParserList : public IParserBase class ParserList : public IParserBase
{ {
public: public:
@ -33,8 +33,8 @@ private:
}; };
/** Выражение с инфиксным бинарным лево-ассоциативным оператором. /** An expression with an infix binary left-associative operator.
* Например, a + b - c + d. * For example, a + b - c + d.
*/ */
class ParserLeftAssociativeBinaryOperatorList : public IParserBase class ParserLeftAssociativeBinaryOperatorList : public IParserBase
{ {
@ -44,7 +44,7 @@ private:
ParserPtr remaining_elem_parser; ParserPtr remaining_elem_parser;
public: public:
/** operators_ - допустимые операторы и соответствующие им функции /** `operators_` - allowed operators and their corresponding functions
*/ */
ParserLeftAssociativeBinaryOperatorList(Operators_t operators_, ParserPtr && first_elem_parser_) ParserLeftAssociativeBinaryOperatorList(Operators_t operators_, ParserPtr && first_elem_parser_)
: operators(operators_), first_elem_parser(std::move(first_elem_parser_)) : operators(operators_), first_elem_parser(std::move(first_elem_parser_))
@ -65,8 +65,8 @@ protected:
}; };
/** Выражение с инфиксным оператором произвольной арности. /** Expression with an infix operator of arbitrary arity.
* Например, a AND b AND c AND d. * For example, a AND b AND c AND d.
*/ */
class ParserVariableArityOperatorList : public IParserBase class ParserVariableArityOperatorList : public IParserBase
{ {
@ -88,8 +88,8 @@ protected:
}; };
/** Выражение с префиксным унарным оператором. /** An expression with a prefix unary operator.
* Например, NOT x. * Example, NOT x.
*/ */
class ParserPrefixUnaryOperatorExpression : public IParserBase class ParserPrefixUnaryOperatorExpression : public IParserBase
{ {
@ -98,7 +98,7 @@ private:
ParserPtr elem_parser; ParserPtr elem_parser;
public: public:
/** operators_ - допустимые операторы и соответствующие им функции /** `operators_` - allowed operators and their corresponding functions
*/ */
ParserPrefixUnaryOperatorExpression(Operators_t operators_, ParserPtr && elem_parser_) ParserPrefixUnaryOperatorExpression(Operators_t operators_, ParserPtr && elem_parser_)
: operators(operators_), elem_parser(std::move(elem_parser_)) : operators(operators_), elem_parser(std::move(elem_parser_))
@ -336,7 +336,7 @@ protected:
}; };
/** Список выражений, разделённых запятыми, возможно пустой. */ /** A comma-separated list of expressions, probably empty. */
class ParserExpressionList : public IParserBase class ParserExpressionList : public IParserBase
{ {
public: public:

View File

@ -31,7 +31,7 @@ using ASTs = std::vector<ASTPtr>;
class WriteBuffer; class WriteBuffer;
/** Элемент синтаксического дерева (в дальнейшем - направленного ациклического графа с элементами семантики) /** Element of the syntax tree (hereinafter - directed acyclic graph with elements of semantics)
*/ */
class IAST class IAST
{ {
@ -39,8 +39,8 @@ public:
ASTs children; ASTs children;
StringRange range; StringRange range;
/** Строка с полным запросом. /** A string with a full query.
* Этот указатель не дает ее удалить, пока range в нее ссылается. * This pointer does not allow it to be deleted while the range refers to it.
*/ */
StringPtr query_string; StringPtr query_string;
@ -48,25 +48,25 @@ public:
IAST(const StringRange range_) : range(range_) {} IAST(const StringRange range_) : range(range_) {}
virtual ~IAST() = default; virtual ~IAST() = default;
/** Получить каноническое имя столбца, если элемент является столбцом */ /** Get the canonical name of the column if the element is a column */
virtual String getColumnName() const { throw Exception("Trying to get name of not a column: " + getID(), ErrorCodes::NOT_A_COLUMN); } virtual String getColumnName() const { throw Exception("Trying to get name of not a column: " + getID(), ErrorCodes::NOT_A_COLUMN); }
/** Получить алиас, если он есть, или каноническое имя столбца, если его нет. */ /** Get the alias, if any, or the canonical name of the column, if it is not. */
virtual String getAliasOrColumnName() const { return getColumnName(); } virtual String getAliasOrColumnName() const { return getColumnName(); }
/** Получить алиас, если он есть, или пустую строку, если его нет, или если элемент не поддерживает алиасы. */ /** Get the alias, if any, or an empty string if it does not exist, or if the element does not support aliases. */
virtual String tryGetAlias() const { return String(); } virtual String tryGetAlias() const { return String(); }
/** Установить алиас. */ /** Set the alias. */
virtual void setAlias(const String & to) virtual void setAlias(const String & to)
{ {
throw Exception("Can't set alias of " + getColumnName(), ErrorCodes::UNKNOWN_TYPE_OF_AST_NODE); throw Exception("Can't set alias of " + getColumnName(), ErrorCodes::UNKNOWN_TYPE_OF_AST_NODE);
} }
/** Получить текст, который идентифицирует этот элемент. */ /** Get the text that identifies this element. */
virtual String getID() const = 0; virtual String getID() const = 0;
/** Получить глубокую копию дерева. */ /** Get a deep copy of the tree. */
virtual ASTPtr clone() const = 0; virtual ASTPtr clone() const = 0;
/** Get text, describing and identifying this element and its subtree. /** Get text, describing and identifying this element and its subtree.
@ -89,20 +89,20 @@ public:
child->dumpTree(ostr, indent + 1); child->dumpTree(ostr, indent + 1);
} }
/** Проверить глубину дерева. /** Check the depth of the tree.
* Если задано max_depth и глубина больше - кинуть исключение. * If max_depth is specified and the depth is greater - throw an exception.
* Возвращает глубину дерева. * Returns the depth of the tree.
*/ */
size_t checkDepth(size_t max_depth) const size_t checkDepth(size_t max_depth) const
{ {
return checkDepthImpl(max_depth, 0); return checkDepthImpl(max_depth, 0);
} }
/** То же самое для общего количества элементов дерева. /** Same for the total number of tree elements.
*/ */
size_t checkSize(size_t max_size) const; size_t checkSize(size_t max_size) const;
/** Получить set из имен индентификаторов /** Get `set` from the names of the identifiers
*/ */
virtual void collectIdentifierNames(IdentifierNameSet & set) const virtual void collectIdentifierNames(IdentifierNameSet & set) const
{ {
@ -111,9 +111,9 @@ public:
} }
/// Преобразовать в строку. /// Convert to a string.
/// Настройки формата. /// Format settings.
struct FormatSettings struct FormatSettings
{ {
std::ostream & ostr; std::ostream & ostr;
@ -129,16 +129,16 @@ public:
} }
}; };
/// Состояние. Например, может запоминаться множество узлов, которых мы уже обошли. /// State. For example, a set of nodes can be remembered, which we already walk through.
struct FormatState struct FormatState
{ {
/** Запрос SELECT, в котором найден алиас; идентификатор узла с таким алиасом. /** The SELECT query in which the alias was found; identifier of a node with such an alias.
* Нужно, чтобы когда узел встретился повторно, выводить только алиас. * It is necessary that when the node has met again, output only the alias.
*/ */
std::set<std::pair<const IAST *, std::string>> printed_asts_with_alias; std::set<std::pair<const IAST *, std::string>> printed_asts_with_alias;
}; };
/// Состояние, которое копируется при форматировании каждого узла. Например, уровень вложенности. /// The state that is copied when each node is formatted. For example, nesting level.
struct FormatStateStacked struct FormatStateStacked
{ {
UInt8 indent = 0; UInt8 indent = 0;
@ -164,7 +164,7 @@ public:
void writeAlias(const String & name, std::ostream & s, bool hilite) const; void writeAlias(const String & name, std::ostream & s, bool hilite) const;
protected: protected:
/// Для подсветки синтаксиса. /// For syntax highlighting.
static const char * hilite_keyword; static const char * hilite_keyword;
static const char * hilite_identifier; static const char * hilite_identifier;
static const char * hilite_function; static const char * hilite_function;
@ -177,7 +177,7 @@ private:
}; };
/// Квотировать идентификатор обратными кавычками, если это требуется. /// Quota the identifier with backquotes, if required.
String backQuoteIfNeed(const String & x); String backQuoteIfNeed(const String & x);

View File

@ -14,23 +14,23 @@ namespace DB
using Expected = const char *; using Expected = const char *;
/** Интерфейс для классов-парсеров /** Interface for parser classes
*/ */
class IParser class IParser
{ {
public: public:
using Pos = const char *; using Pos = const char *;
/** Получить текст о том, что парсит этот парсер. */ /** Get the text of this parser parses. */
virtual const char * getName() const = 0; virtual const char * getName() const = 0;
/** Распарсить кусок текста с позиции pos, но не дальше конца строки (end - позиция после конца строки), /** Parse piece of text from position `pos`, but not beyond end of line (`end` - position after end of line),
* переместить указатель pos на максимальное место, до которого удалось распарсить, * move pointer `pos` to the maximum position to which it was possible to parse,
* вернуть в случае успеха true и результат в node, если он нужен, иначе false, * in case of success return `true` and the result in `node` if it is needed, otherwise false,
* в expected записать, что ожидалось в максимальной позиции, * in `expected` write what was expected in the maximum position,
* до которой удалось распарсить, если парсинг был неуспешным, * to which it was possible to parse if parsing was unsuccessful,
* или что парсит этот парсер, если парсинг был успешным. * or what this parser parse if parsing was successful.
* Строка, в которую входит диапазон [begin, end) может быть не 0-terminated. * The string to which the [begin, end) range is included may be not 0-terminated.
*/ */
virtual bool parse(Pos & pos, Pos end, ASTPtr & node, Pos & max_parsed_pos, Expected & expected) = 0; virtual bool parse(Pos & pos, Pos end, ASTPtr & node, Pos & max_parsed_pos, Expected & expected) = 0;
@ -47,7 +47,7 @@ public:
return ignore(pos, end, max_parsed_pos, expected); return ignore(pos, end, max_parsed_pos, expected);
} }
/** То же самое, но не двигать позицию и не записывать результат в node. /** The same, but do not move the position and do not write the result to node.
*/ */
bool check(Pos & pos, Pos end, Pos & max_parsed_pos, Expected & expected) bool check(Pos & pos, Pos end, Pos & max_parsed_pos, Expected & expected)
{ {

View File

@ -6,7 +6,7 @@
namespace DB namespace DB
{ {
/** Базовый класс для большинства парсеров /** Base class for most parsers
*/ */
class IParserBase : public IParser class IParserBase : public IParser
{ {

View File

@ -6,7 +6,7 @@
namespace DB namespace DB
{ {
/** Запрос типа такого: /** Query like this:
* ALTER TABLE [db.]name * ALTER TABLE [db.]name
* [ADD COLUMN col_name type [AFTER col_after],] * [ADD COLUMN col_name type [AFTER col_after],]
* [DROP COLUMN col_drop, ...] * [DROP COLUMN col_drop, ...]

View File

@ -4,7 +4,7 @@
namespace DB namespace DB
{ {
/** Запрос вида /** Query of form
* CHECK [TABLE] [database.]table * CHECK [TABLE] [database.]table
*/ */
class ParserCheckQuery : public IParserBase class ParserCheckQuery : public IParserBase

View File

@ -14,7 +14,7 @@
namespace DB namespace DB
{ {
/** Вложенная таблица. Например, Nested(UInt32 CounterID, FixedString(2) UserAgentMajor) /** A nested table. For example, Nested(UInt32 CounterID, FixedString(2) UserAgentMajor)
*/ */
class ParserNestedTable : public IParserBase class ParserNestedTable : public IParserBase
{ {
@ -24,12 +24,12 @@ protected:
}; };
/** Параметрический тип или Storage. Например: /** Parametric type or Storage. For example:
* FixedString(10) или * FixedString(10) or
* Partitioned(Log, ChunkID) или * Partitioned(Log, ChunkID) or
* Nested(UInt32 CounterID, FixedString(2) UserAgentMajor) * Nested(UInt32 CounterID, FixedString(2) UserAgentMajor)
* Результат парсинга - ASTFunction с параметрами или без. * Result of parsing - ASTFunction with or without parameters.
*/ */
class ParserIdentifierWithParameters : public IParserBase class ParserIdentifierWithParameters : public IParserBase
{ {
protected: protected:
@ -64,9 +64,9 @@ protected:
bool parseImpl(Pos & pos, Pos end, ASTPtr & node, Pos & max_parsed_pos, Expected & expected); bool parseImpl(Pos & pos, Pos end, ASTPtr & node, Pos & max_parsed_pos, Expected & expected);
}; };
/** Имя и тип через пробел. Например, URL String. */ /** The name and type are separated by a space. For example, URL String. */
using ParserNameTypePair = IParserNameTypePair<ParserIdentifier>; using ParserNameTypePair = IParserNameTypePair<ParserIdentifier>;
/** Имя и тип через пробел. Имя может содержать точку. Например, Hits.URL String. */ /** Name and type separated by a space. The name can contain a dot. For example, Hits.URL String. */
using ParserCompoundNameTypePair = IParserNameTypePair<ParserCompoundIdentifier>; using ParserCompoundNameTypePair = IParserNameTypePair<ParserCompoundIdentifier>;
template <class NameParser> template <class NameParser>
@ -94,7 +94,7 @@ bool IParserNameTypePair<NameParser>::parseImpl(Pos & pos, Pos end, ASTPtr & nod
return false; return false;
} }
/** Список столбцов. */ /** List of columns. */
class ParserNameTypePairList : public IParserBase class ParserNameTypePairList : public IParserBase
{ {
protected: protected:
@ -204,7 +204,7 @@ protected:
}; };
/** Запрос типа такого: /** Query like this:
* CREATE|ATTACH TABLE [IF NOT EXISTS] [db.]name * CREATE|ATTACH TABLE [IF NOT EXISTS] [db.]name
* ( * (
* name1 type1, * name1 type1,
@ -212,16 +212,16 @@ protected:
* ... * ...
* ) ENGINE = engine * ) ENGINE = engine
* *
* Или: * Or:
* CREATE|ATTACH TABLE [IF NOT EXISTS] [db.]name AS [db2.]name2 [ENGINE = engine] * CREATE|ATTACH TABLE [IF NOT EXISTS] [db.]name AS [db2.]name2 [ENGINE = engine]
* *
* Или: * Or:
* CREATE|ATTACH TABLE [IF NOT EXISTS] [db.]name AS ENGINE = engine SELECT ... * CREATE|ATTACH TABLE [IF NOT EXISTS] [db.]name AS ENGINE = engine SELECT ...
* *
* Или: * Or:
* CREATE|ATTACH DATABASE db [ENGINE = engine] * CREATE|ATTACH DATABASE db [ENGINE = engine]
* *
* Или: * Or:
* CREATE|ATTACH [MATERIALIZED] VIEW [IF NOT EXISTS] [db.]name [ENGINE = engine] [POPULATE] AS SELECT ... * CREATE|ATTACH [MATERIALIZED] VIEW [IF NOT EXISTS] [db.]name [ENGINE = engine] [POPULATE] AS SELECT ...
*/ */
class ParserCreateQuery : public IParserBase class ParserCreateQuery : public IParserBase

View File

@ -7,10 +7,10 @@
namespace DB namespace DB
{ {
/** Запрос типа такого: /** Query like this:
* DROP|DETACH TABLE [IF EXISTS] [db.]name * DROP|DETACH TABLE [IF EXISTS] [db.]name
* *
* Или: * Or:
* DROP DATABASE [IF EXISTS] db * DROP DATABASE [IF EXISTS] db
*/ */
class ParserDropQuery : public IParserBase class ParserDropQuery : public IParserBase

View File

@ -7,18 +7,18 @@ namespace DB
{ {
/** Варианты: /** Cases:
* *
* Обычный вариант: * Normal case:
* INSERT INTO [db.]table (c1, c2, c3) VALUES (v11, v12, v13), (v21, v22, v23), ... * INSERT INTO [db.]table (c1, c2, c3) VALUES (v11, v12, v13), (v21, v22, v23), ...
* INSERT INTO [db.]table VALUES (v11, v12, v13), (v21, v22, v23), ... * INSERT INTO [db.]table VALUES (v11, v12, v13), (v21, v22, v23), ...
* *
* Вставка данных в произвольном формате. * Insert of data in an arbitrary format.
* Сами данные идут после перевода строки, если он есть, или после всех пробельных символов, иначе. * The data itself comes after LF(line feed), if it exists, or after all the whitespace characters, otherwise.
* INSERT INTO [db.]table (c1, c2, c3) FORMAT format \n ... * INSERT INTO [db.]table (c1, c2, c3) FORMAT format \n ...
* INSERT INTO [db.]table FORMAT format \n ... * INSERT INTO [db.]table FORMAT format \n ...
* *
* Вставка результата выполнения SELECT запроса. * Insert the result of the SELECT query.
* INSERT INTO [db.]table (c1, c2, c3) SELECT ... * INSERT INTO [db.]table (c1, c2, c3) SELECT ...
* INSERT INTO [db.]table SELECT ... * INSERT INTO [db.]table SELECT ...
*/ */

View File

@ -7,7 +7,7 @@
namespace DB namespace DB
{ {
/** Запрос OPTIMIZE TABLE [db.]name [PARTITION partition] [FINAL] [DEDUPLICATE] /** Query OPTIMIZE TABLE [db.]name [PARTITION partition] [FINAL] [DEDUPLICATE]
*/ */
class ParserOptimizeQuery : public IParserBase class ParserOptimizeQuery : public IParserBase
{ {

View File

@ -7,9 +7,9 @@
namespace DB namespace DB
{ {
/** Запрос типа такого: /** Query like this:
* RENAME TABLE [db.]name TO [db.]name, [db.]name TO [db.]name, ... * RENAME TABLE [db.]name TO [db.]name, [db.]name TO [db.]name, ...
* (Переименовываться может произвольное количество таблиц.) * (An arbitrary number of tables can be renamed.)
*/ */
class ParserRenameQuery : public IParserBase class ParserRenameQuery : public IParserBase
{ {

Some files were not shown because too many files have changed in this diff Show More