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 | |
10 | namespace DB |
11 | { |
12 | |
13 | VerticalRowOutputFormat::VerticalRowOutputFormat( |
14 | WriteBuffer & out_, const Block & , 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 | |
53 | void 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 | |
66 | void 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 | |
72 | void 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 | |
90 | void 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 | |
100 | void 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 | |
110 | void VerticalRowOutputFormat::writeBeforeTotals() |
111 | { |
112 | writeCString("\n" , out); |
113 | writeCString("\n" , out); |
114 | } |
115 | |
116 | void VerticalRowOutputFormat::writeBeforeExtremes() |
117 | { |
118 | if (!was_totals_written) |
119 | writeCString("\n" , out); |
120 | |
121 | writeCString("\n" , out); |
122 | } |
123 | |
124 | void VerticalRowOutputFormat::writeMinExtreme(const Columns & columns, size_t row_num) |
125 | { |
126 | writeSpecialRow(columns, row_num, PortKind::Totals, "Min" ); |
127 | } |
128 | |
129 | void VerticalRowOutputFormat::writeMaxExtreme(const Columns & columns, size_t row_num) |
130 | { |
131 | writeSpecialRow(columns, row_num, PortKind::Totals, "Max" ); |
132 | } |
133 | |
134 | void 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 | |
140 | void 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 & = 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 | |
166 | void 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 | |