2011-11-07 04:51:37 +00:00
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
2011-11-07 01:15:37 +00:00
|
|
|
|
#include <DB/Functions/FunctionsMiscellaneous.h>
|
|
|
|
|
|
|
|
|
|
#include <DB/DataStreams/PrettyBlockOutputStream.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
|
2012-06-25 05:07:34 +00:00
|
|
|
|
PrettyBlockOutputStream::PrettyBlockOutputStream(WriteBuffer & ostr_, bool no_escapes_, size_t max_rows_)
|
|
|
|
|
: ostr(ostr_), max_rows(max_rows_), total_rows(0), terminal_width(0), no_escapes(no_escapes_)
|
2011-11-07 04:51:37 +00:00
|
|
|
|
{
|
|
|
|
|
struct winsize w;
|
2011-11-28 04:05:53 +00:00
|
|
|
|
if (0 == ioctl(STDOUT_FILENO, TIOCGWINSZ, &w))
|
2011-11-07 04:51:37 +00:00
|
|
|
|
terminal_width = w.ws_col;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-11-28 04:05:53 +00:00
|
|
|
|
void PrettyBlockOutputStream::calculateWidths(Block & block, Widths_t & max_widths, Widths_t & name_widths)
|
2011-11-07 01:15:37 +00:00
|
|
|
|
{
|
|
|
|
|
size_t rows = block.rows();
|
|
|
|
|
size_t columns = block.columns();
|
2014-06-26 00:58:14 +00:00
|
|
|
|
|
2011-11-28 04:05:53 +00:00
|
|
|
|
max_widths.resize(columns);
|
|
|
|
|
name_widths.resize(columns);
|
2011-11-07 01:15:37 +00:00
|
|
|
|
|
|
|
|
|
FunctionVisibleWidth visible_width_func;
|
2016-05-28 07:48:40 +00:00
|
|
|
|
DataTypePtr visible_width_type = std::make_shared<DataTypeUInt64>();
|
2011-11-07 01:15:37 +00:00
|
|
|
|
|
2011-11-28 04:05:53 +00:00
|
|
|
|
/// Вычислим ширину всех значений
|
2011-11-07 01:15:37 +00:00
|
|
|
|
for (size_t i = 0; i < columns; ++i)
|
|
|
|
|
{
|
2015-07-17 01:27:35 +00:00
|
|
|
|
ColumnWithTypeAndName column;
|
2011-11-07 01:15:37 +00:00
|
|
|
|
column.type = visible_width_type;
|
|
|
|
|
column.name = "visibleWidth(" + block.getByPosition(i).name + ")";
|
|
|
|
|
|
|
|
|
|
size_t result_number = block.columns();
|
|
|
|
|
block.insert(column);
|
|
|
|
|
|
|
|
|
|
ColumnNumbers arguments;
|
|
|
|
|
arguments.push_back(i);
|
|
|
|
|
|
|
|
|
|
visible_width_func.execute(block, arguments, result_number);
|
|
|
|
|
|
|
|
|
|
column.column = block.getByPosition(i + columns).column;
|
|
|
|
|
|
2014-06-26 00:58:14 +00:00
|
|
|
|
if (const ColumnUInt64 * col = typeid_cast<const ColumnUInt64 *>(&*column.column))
|
2011-11-07 01:15:37 +00:00
|
|
|
|
{
|
2013-01-21 05:22:07 +00:00
|
|
|
|
const ColumnUInt64::Container_t & res = col->getData();
|
2011-11-07 01:15:37 +00:00
|
|
|
|
for (size_t j = 0; j < rows; ++j)
|
|
|
|
|
if (res[j] > max_widths[i])
|
|
|
|
|
max_widths[i] = res[j];
|
|
|
|
|
}
|
2014-06-26 00:58:14 +00:00
|
|
|
|
else if (const ColumnConstUInt64 * col = typeid_cast<const ColumnConstUInt64 *>(&*column.column))
|
2011-11-07 01:15:37 +00:00
|
|
|
|
{
|
|
|
|
|
UInt64 res = col->getData();
|
|
|
|
|
max_widths[i] = res;
|
|
|
|
|
}
|
|
|
|
|
else
|
2011-11-28 04:05:53 +00:00
|
|
|
|
throw Exception("Illegal column " + column.column->getName()
|
2011-11-07 01:15:37 +00:00
|
|
|
|
+ " of result of function " + visible_width_func.getName(),
|
|
|
|
|
ErrorCodes::ILLEGAL_COLUMN);
|
|
|
|
|
|
|
|
|
|
/// И не только значений, но и их имён
|
|
|
|
|
stringWidthConstant(block.getByPosition(i).name, name_widths[i]);
|
|
|
|
|
if (name_widths[i] > max_widths[i])
|
|
|
|
|
max_widths[i] = name_widths[i];
|
|
|
|
|
}
|
2011-11-28 04:05:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void PrettyBlockOutputStream::write(const Block & block_)
|
|
|
|
|
{
|
|
|
|
|
if (total_rows >= max_rows)
|
2012-05-08 11:19:00 +00:00
|
|
|
|
{
|
|
|
|
|
total_rows += block_.rows();
|
2011-11-28 04:05:53 +00:00
|
|
|
|
return;
|
2012-05-08 11:19:00 +00:00
|
|
|
|
}
|
2014-06-26 00:58:14 +00:00
|
|
|
|
|
2011-11-28 04:05:53 +00:00
|
|
|
|
/// Будем вставлять суда столбцы с вычисленными значениями видимых длин.
|
|
|
|
|
Block block = block_;
|
2014-06-26 00:58:14 +00:00
|
|
|
|
|
2011-11-28 04:05:53 +00:00
|
|
|
|
size_t rows = block.rows();
|
|
|
|
|
size_t columns = block.columns();
|
|
|
|
|
|
|
|
|
|
Widths_t max_widths;
|
|
|
|
|
Widths_t name_widths;
|
|
|
|
|
calculateWidths(block, max_widths, name_widths);
|
2011-11-07 01:15:37 +00:00
|
|
|
|
|
|
|
|
|
/// Создадим разделители
|
|
|
|
|
std::stringstream top_separator;
|
|
|
|
|
std::stringstream middle_names_separator;
|
|
|
|
|
std::stringstream middle_values_separator;
|
|
|
|
|
std::stringstream bottom_separator;
|
|
|
|
|
|
|
|
|
|
top_separator << "┏";
|
|
|
|
|
middle_names_separator << "┡";
|
|
|
|
|
middle_values_separator << "├";
|
|
|
|
|
bottom_separator << "└";
|
|
|
|
|
for (size_t i = 0; i < columns; ++i)
|
|
|
|
|
{
|
|
|
|
|
if (i != 0)
|
|
|
|
|
{
|
|
|
|
|
top_separator << "┳";
|
|
|
|
|
middle_names_separator << "╇";
|
|
|
|
|
middle_values_separator << "┼";
|
|
|
|
|
bottom_separator << "┴";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (size_t j = 0; j < max_widths[i] + 2; ++j)
|
|
|
|
|
{
|
|
|
|
|
top_separator << "━";
|
|
|
|
|
middle_names_separator << "━";
|
|
|
|
|
middle_values_separator << "─";
|
|
|
|
|
bottom_separator << "─";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
top_separator << "┓\n";
|
|
|
|
|
middle_names_separator << "┩\n";
|
|
|
|
|
middle_values_separator << "┤\n";
|
|
|
|
|
bottom_separator << "┘\n";
|
|
|
|
|
|
|
|
|
|
std::string top_separator_s = top_separator.str();
|
|
|
|
|
std::string middle_names_separator_s = middle_names_separator.str();
|
|
|
|
|
std::string middle_values_separator_s = middle_values_separator.str();
|
|
|
|
|
std::string bottom_separator_s = bottom_separator.str();
|
|
|
|
|
|
|
|
|
|
/// Выведем блок
|
|
|
|
|
writeString(top_separator_s, ostr);
|
|
|
|
|
|
|
|
|
|
/// Имена
|
2013-05-15 22:58:57 +00:00
|
|
|
|
writeCString("┃ ", ostr);
|
2011-11-07 01:15:37 +00:00
|
|
|
|
for (size_t i = 0; i < columns; ++i)
|
|
|
|
|
{
|
|
|
|
|
if (i != 0)
|
2013-05-15 22:58:57 +00:00
|
|
|
|
writeCString(" ┃ ", ostr);
|
2011-11-07 01:15:37 +00:00
|
|
|
|
|
2015-07-17 01:27:35 +00:00
|
|
|
|
const ColumnWithTypeAndName & col = block.getByPosition(i);
|
2011-11-07 01:15:37 +00:00
|
|
|
|
|
2012-06-25 05:07:34 +00:00
|
|
|
|
if (!no_escapes)
|
2014-08-15 00:08:15 +00:00
|
|
|
|
writeCString("\033[1m", ostr);
|
2014-06-26 00:58:14 +00:00
|
|
|
|
|
2011-11-07 01:15:37 +00:00
|
|
|
|
if (col.type->isNumeric())
|
|
|
|
|
{
|
|
|
|
|
for (size_t k = 0; k < max_widths[i] - name_widths[i]; ++k)
|
|
|
|
|
writeChar(' ', ostr);
|
|
|
|
|
|
|
|
|
|
writeEscapedString(col.name, ostr);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
writeEscapedString(col.name, ostr);
|
|
|
|
|
|
|
|
|
|
for (size_t k = 0; k < max_widths[i] - name_widths[i]; ++k)
|
|
|
|
|
writeChar(' ', ostr);
|
|
|
|
|
}
|
2012-06-25 05:07:34 +00:00
|
|
|
|
|
|
|
|
|
if (!no_escapes)
|
2013-05-15 22:58:57 +00:00
|
|
|
|
writeCString("\033[0m", ostr);
|
2011-11-07 01:15:37 +00:00
|
|
|
|
}
|
2013-05-15 22:58:57 +00:00
|
|
|
|
writeCString(" ┃\n", ostr);
|
2011-11-07 01:15:37 +00:00
|
|
|
|
|
|
|
|
|
writeString(middle_names_separator_s, ostr);
|
|
|
|
|
|
2011-11-07 04:51:37 +00:00
|
|
|
|
for (size_t i = 0; i < rows && total_rows + i < max_rows; ++i)
|
2011-11-07 01:15:37 +00:00
|
|
|
|
{
|
|
|
|
|
if (i != 0)
|
|
|
|
|
writeString(middle_values_separator_s, ostr);
|
|
|
|
|
|
2013-05-15 22:58:57 +00:00
|
|
|
|
writeCString("│ ", ostr);
|
2011-11-07 01:15:37 +00:00
|
|
|
|
|
|
|
|
|
for (size_t j = 0; j < columns; ++j)
|
|
|
|
|
{
|
|
|
|
|
if (j != 0)
|
2013-05-15 22:58:57 +00:00
|
|
|
|
writeCString(" │ ", ostr);
|
2011-11-07 01:15:37 +00:00
|
|
|
|
|
2015-07-17 01:27:35 +00:00
|
|
|
|
const ColumnWithTypeAndName & col = block.getByPosition(j);
|
2011-11-07 01:15:37 +00:00
|
|
|
|
|
|
|
|
|
if (col.type->isNumeric())
|
|
|
|
|
{
|
2013-01-05 20:03:19 +00:00
|
|
|
|
size_t width = get<UInt64>((*block.getByPosition(columns + j).column)[i]);
|
2011-11-07 01:15:37 +00:00
|
|
|
|
for (size_t k = 0; k < max_widths[j] - width; ++k)
|
|
|
|
|
writeChar(' ', ostr);
|
2014-06-26 00:58:14 +00:00
|
|
|
|
|
2016-02-16 16:39:39 +00:00
|
|
|
|
col.type->serializeTextEscaped(*col.column.get(), i, ostr);
|
2011-11-07 01:15:37 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-02-16 16:39:39 +00:00
|
|
|
|
col.type->serializeTextEscaped(*col.column.get(), i, ostr);
|
2011-11-07 01:15:37 +00:00
|
|
|
|
|
2013-01-05 20:03:19 +00:00
|
|
|
|
size_t width = get<UInt64>((*block.getByPosition(columns + j).column)[i]);
|
2011-11-07 01:15:37 +00:00
|
|
|
|
for (size_t k = 0; k < max_widths[j] - width; ++k)
|
|
|
|
|
writeChar(' ', ostr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-15 22:58:57 +00:00
|
|
|
|
writeCString(" │\n", ostr);
|
2011-11-07 01:15:37 +00:00
|
|
|
|
}
|
2014-06-26 00:58:14 +00:00
|
|
|
|
|
2011-11-07 01:15:37 +00:00
|
|
|
|
writeString(bottom_separator_s, ostr);
|
|
|
|
|
|
2011-11-07 04:51:37 +00:00
|
|
|
|
total_rows += rows;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void PrettyBlockOutputStream::writeSuffix()
|
|
|
|
|
{
|
|
|
|
|
if (total_rows >= max_rows)
|
|
|
|
|
{
|
2013-05-15 22:58:57 +00:00
|
|
|
|
writeCString(" Showed first ", ostr);
|
2011-11-07 04:51:37 +00:00
|
|
|
|
writeIntText(max_rows, ostr);
|
2013-05-15 22:58:57 +00:00
|
|
|
|
writeCString(".\n", ostr);
|
2011-11-07 04:51:37 +00:00
|
|
|
|
}
|
2014-03-02 19:16:45 +00:00
|
|
|
|
|
|
|
|
|
total_rows = 0;
|
|
|
|
|
writeTotals();
|
|
|
|
|
writeExtremes();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void PrettyBlockOutputStream::writeTotals()
|
|
|
|
|
{
|
|
|
|
|
if (totals)
|
|
|
|
|
{
|
|
|
|
|
writeCString("\nTotals:\n", ostr);
|
|
|
|
|
write(totals);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void PrettyBlockOutputStream::writeExtremes()
|
|
|
|
|
{
|
|
|
|
|
if (extremes)
|
|
|
|
|
{
|
|
|
|
|
writeCString("\nExtremes:\n", ostr);
|
|
|
|
|
write(extremes);
|
|
|
|
|
}
|
2011-11-07 01:15:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-11-07 04:51:37 +00:00
|
|
|
|
|
2011-11-07 01:15:37 +00:00
|
|
|
|
}
|