#pragma once #include #include #include #include #include #include #include #include #include #include #include #include namespace DB { /** Вспомогательные функции: * * visibleWidth(x) - вычисляет приблизительную ширину при выводе значения в текстовом (tab-separated) виде на консоль. */ template static void numWidthVector(const std::vector & a, std::vector & c) { size_t size = a.size(); for (size_t i = 0; i < size; ++i) if (a[i] >= 0) c[i] = a[i] ? 1 + log10(a[i]) : 1; else c[i] = 2 + log10(-a[i]); } template static void numWidthConstant(T a, UInt64 & c) { if (a >= 0) c = a ? 1 + log10(a) : 1; else c = 2 + log10(-a); } static inline UInt64 stringWidth(const UInt8 * pos, const UInt8 * end) { UInt64 res = 0; for (; pos < end; ++pos) { if (*pos == '\b' || *pos == '\f' || *pos == '\n' || *pos == '\r' || *pos == '\t' || *pos == '\0' || *pos == '\'' || *pos == '\\') ++res; if (*pos <= 0x7F || *pos >= 0xC0) ++res; } return res; } static inline void stringWidthVector(const std::vector & data, const std::vector & offsets, std::vector & res) { size_t size = offsets.size(); size_t prev_offset = 0; for (size_t i = 0; i < size; ++i) { res[i] = stringWidth(&data[prev_offset], &data[offsets[i] - 1]); prev_offset = offsets[i]; } } static inline void stringWidthFixedVector(const std::vector & data, size_t n, std::vector & res) { size_t size = data.size() / n; for (size_t i = 0; i < size; ++i) res[i] = stringWidth(&data[i * n], &data[(i + 1) * n]); } inline void stringWidthConstant(const String & data, UInt64 & res) { res = stringWidth(reinterpret_cast(data.data()), reinterpret_cast(data.data()) + data.size()); } class FunctionVisibleWidth : public IFunction { private: template bool executeConstNumber(Block & block, const ColumnPtr & column, size_t result) { if (const ColumnConst * col = dynamic_cast *>(&*column)) { UInt64 res = 0; numWidthConstant(col->getData(), res); block.getByPosition(result).column = new ColumnConstUInt64(column->size(), res); return true; } else return false; } template bool executeNumber(Block & block, const ColumnPtr & column, size_t result) { if (const ColumnVector * col = dynamic_cast *>(&*column)) { ColumnUInt64 * res = new ColumnUInt64(column->size()); numWidthVector(col->getData(), res->getData()); block.getByPosition(result).column = res; return true; } else return false; } public: /// Получить имя функции. String getName() const { return "visibleWidth"; } /// Получить тип результата по типам аргументов. Если функция неприменима для данных аргументов - кинуть исключение. DataTypePtr getReturnType(const DataTypes & arguments) const { if (arguments.size() != 1) throw Exception("Number of arguments for function " + getName() + " doesn't match: passed " + Poco::NumberFormatter::format(arguments.size()) + ", should be 1.", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); return new DataTypeUInt64; } /// Выполнить функцию над блоком. void execute(Block & block, const ColumnNumbers & arguments, size_t result) { const ColumnPtr column = block.getByPosition(arguments[0]).column; const DataTypePtr type = block.getByPosition(arguments[0]).type; size_t rows = column->size(); if (dynamic_cast(&*type)) { block.getByPosition(result).column = new ColumnConstUInt64(rows, strlen("0000-00-00")); } else if (dynamic_cast(&*type)) { block.getByPosition(result).column = new ColumnConstUInt64(rows, strlen("0000-00-00 00:00:00")); } else if (executeConstNumber(block, column, result) || executeConstNumber(block, column, result) || executeConstNumber(block, column, result) || executeConstNumber(block, column, result) || executeConstNumber(block, column, result) || executeConstNumber(block, column, result) || executeConstNumber(block, column, result) || executeConstNumber(block, column, result) || executeConstNumber(block, column, result) /// TODO: правильная работа с float || executeConstNumber(block, column, result) || executeNumber(block, column, result) || executeNumber(block, column, result) || executeNumber(block, column, result) || executeNumber(block, column, result) || executeNumber(block, column, result) || executeNumber(block, column, result) || executeNumber(block, column, result) || executeNumber(block, column, result) || executeNumber(block, column, result) || executeNumber(block, column, result)) { } else if (const ColumnString * col = dynamic_cast(&*column)) { ColumnUInt64 * res = new ColumnUInt64(rows); stringWidthVector(dynamic_cast(col->getData()).getData(), col->getOffsets(), res->getData()); block.getByPosition(result).column = res; } else if (const ColumnFixedString * col = dynamic_cast(&*column)) { ColumnUInt64 * res = new ColumnUInt64(rows); stringWidthFixedVector(dynamic_cast(col->getData()).getData(), col->getN(), res->getData()); block.getByPosition(result).column = res; } else if (const ColumnConstString * col = dynamic_cast(&*column)) { UInt64 res = 0; stringWidthConstant(col->getData(), res); block.getByPosition(result).column = new ColumnConstUInt64(rows, res); } else throw Exception("Illegal column " + block.getByPosition(arguments[0]).column->getName() + " of argument of function " + getName(), ErrorCodes::ILLEGAL_COLUMN); } }; }