1#include <cmath>
2
3#include <IO/WriteHelpers.h>
4#include <IO/WriteBufferFromString.h>
5#include <Processors/Formats/Impl/VerticalRowOutputFormat.h>
6#include <Formats/FormatFactory.h>
7#include <Common/UTF8Helpers.h>
8
9
10namespace DB
11{
12
13VerticalRowOutputFormat::VerticalRowOutputFormat(
14 WriteBuffer & out_, const Block & header_, FormatFactory::WriteCallback callback, const FormatSettings & format_settings_)
15 : IRowOutputFormat(header_, out_, callback), format_settings(format_settings_)
16{
17 auto & sample = getPort(PortKind::Main).getHeader();
18 size_t columns = sample.columns();
19
20 using Widths = std::vector<size_t>;
21 Widths name_widths(columns);
22 size_t max_name_width = 0;
23
24 String serialized_value;
25
26 for (size_t i = 0; i < columns; ++i)
27 {
28 /// Note that number of code points is just a rough approximation of visible string width.
29 const String & name = sample.getByPosition(i).name;
30
31 name_widths[i] = UTF8::computeWidth(reinterpret_cast<const UInt8 *>(name.data()), name.size());
32
33 if (name_widths[i] > max_name_width)
34 max_name_width = name_widths[i];
35 }
36
37 names_and_paddings.resize(columns);
38 for (size_t i = 0; i < columns; ++i)
39 {
40 WriteBufferFromString buf(names_and_paddings[i]);
41 writeString(sample.getByPosition(i).name, buf);
42 writeCString(": ", buf);
43 }
44
45 for (size_t i = 0; i < columns; ++i)
46 {
47 size_t new_size = max_name_width - name_widths[i] + names_and_paddings[i].size();
48 names_and_paddings[i].resize(new_size, ' ');
49 }
50}
51
52
53void VerticalRowOutputFormat::writeField(const IColumn & column, const IDataType & type, size_t row_num)
54{
55 if (row_number > format_settings.pretty.max_rows)
56 return;
57
58 writeString(names_and_paddings[field_number], out);
59 writeValue(column, type, row_num);
60 writeChar('\n', out);
61
62 ++field_number;
63}
64
65
66void VerticalRowOutputFormat::writeValue(const IColumn & column, const IDataType & type, size_t row_num) const
67{
68 type.serializeAsText(column, row_num, out, format_settings);
69}
70
71
72void VerticalRowOutputFormat::writeRowStartDelimiter()
73{
74 ++row_number;
75
76 if (row_number > format_settings.pretty.max_rows)
77 return;
78
79 writeCString("Row ", out);
80 writeIntText(row_number, out);
81 writeCString(":\n", out);
82
83 size_t width = log10(row_number + 1) + 1 + strlen("Row :");
84 for (size_t i = 0; i < width; ++i)
85 writeCString("─", out);
86 writeChar('\n', out);
87}
88
89
90void VerticalRowOutputFormat::writeRowBetweenDelimiter()
91{
92 if (row_number > format_settings.pretty.max_rows)
93 return;
94
95 writeCString("\n", out);
96 field_number = 0;
97}
98
99
100void VerticalRowOutputFormat::writeSuffix()
101{
102 if (row_number > format_settings.pretty.max_rows)
103 {
104 writeCString("Showed first ", out);
105 writeIntText(format_settings.pretty.max_rows, out);
106 writeCString(".\n", out);
107 }
108}
109
110void VerticalRowOutputFormat::writeBeforeTotals()
111{
112 writeCString("\n", out);
113 writeCString("\n", out);
114}
115
116void VerticalRowOutputFormat::writeBeforeExtremes()
117{
118 if (!was_totals_written)
119 writeCString("\n", out);
120
121 writeCString("\n", out);
122}
123
124void VerticalRowOutputFormat::writeMinExtreme(const Columns & columns, size_t row_num)
125{
126 writeSpecialRow(columns, row_num, PortKind::Totals, "Min");
127}
128
129void VerticalRowOutputFormat::writeMaxExtreme(const Columns & columns, size_t row_num)
130{
131 writeSpecialRow(columns, row_num, PortKind::Totals, "Max");
132}
133
134void VerticalRowOutputFormat::writeTotals(const Columns & columns, size_t row_num)
135{
136 writeSpecialRow(columns, row_num, PortKind::Totals, "Totals");
137 was_totals_written = true;
138}
139
140void VerticalRowOutputFormat::writeSpecialRow(const Columns & columns, size_t row_num, PortKind port_kind, const char * title)
141{
142 row_number = 0;
143 field_number = 0;
144
145 auto & header = getPort(port_kind).getHeader();
146 size_t num_columns = columns.size();
147
148 writeCString(title, out);
149 writeCString(":\n", out);
150
151 size_t width = strlen(title) + 1;
152 for (size_t i = 0; i < width; ++i)
153 writeCString("─", out);
154 writeChar('\n', out);
155
156 for (size_t i = 0; i < num_columns; ++i)
157 {
158 if (i != 0)
159 writeFieldDelimiter();
160
161 auto & col = header.getByPosition(i);
162 writeField(*columns[i], *col.type, row_num);
163 }
164}
165
166void registerOutputFormatProcessorVertical(FormatFactory & factory)
167{
168 factory.registerOutputFormatProcessor("Vertical", [](
169 WriteBuffer & buf,
170 const Block & sample,
171 FormatFactory::WriteCallback callback,
172 const FormatSettings & settings)
173 {
174 return std::make_shared<VerticalRowOutputFormat>(buf, sample, callback, settings);
175 });
176}
177
178}
179