ClickHouse/dbms/src/DataStreams/PrettyBlockOutputStream.cpp

220 lines
5.4 KiB
C++
Raw Normal View History

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();
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;
DataTypePtr visible_width_type = new DataTypeUInt64;
2011-11-28 04:05:53 +00:00
/// Вычислим ширину всех значений
2011-11-07 01:15:37 +00:00
for (size_t i = 0; i < columns; ++i)
{
ColumnWithNameAndType column;
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;
if (const ColumnUInt64 * col = dynamic_cast<const ColumnUInt64 *>(&*column.column))
{
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];
}
else if (const ColumnConstUInt64 * col = dynamic_cast<const ColumnConstUInt64 *>(&*column.column))
{
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
}
2011-11-28 04:05:53 +00:00
/// Будем вставлять суда столбцы с вычисленными значениями видимых длин.
Block block = block_;
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);
/// Имена
writeString("", ostr);
for (size_t i = 0; i < columns; ++i)
{
if (i != 0)
writeString("", ostr);
const ColumnWithNameAndType & col = block.getByPosition(i);
2012-06-25 05:07:34 +00:00
if (!no_escapes)
writeString("\033[1;37m", ostr);
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)
writeString("\033[0m", ostr);
2011-11-07 01:15:37 +00:00
}
writeString("\n", ostr);
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);
writeString("", ostr);
for (size_t j = 0; j < columns; ++j)
{
if (j != 0)
writeString("", ostr);
const ColumnWithNameAndType & col = block.getByPosition(j);
if (col.type->isNumeric())
{
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);
col.type->serializeTextEscaped((*col.column)[i], ostr);
}
else
{
col.type->serializeTextEscaped((*col.column)[i], ostr);
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);
}
}
writeString("\n", ostr);
}
writeString(bottom_separator_s, ostr);
2011-11-07 04:51:37 +00:00
total_rows += rows;
}
void PrettyBlockOutputStream::writeSuffix()
{
if (total_rows >= max_rows)
{
2012-05-08 11:19:00 +00:00
writeString(" Showed first ", ostr);
2011-11-07 04:51:37 +00:00
writeIntText(max_rows, ostr);
2012-05-08 11:19:00 +00:00
writeString(".\n", ostr);
2011-11-07 04:51:37 +00:00
}
2011-11-07 01:15:37 +00:00
}
2011-11-07 04:51:37 +00:00
2011-11-07 01:15:37 +00:00
}