]>
Commit | Line | Data |
---|---|---|
1 | // Licensed to the Apache Software Foundation (ASF) under one | |
2 | // or more contributor license agreements. See the NOTICE file | |
3 | // distributed with this work for additional information | |
4 | // regarding copyright ownership. The ASF licenses this file | |
5 | // to you under the Apache License, Version 2.0 (the | |
6 | // "License"); you may not use this file except in compliance | |
7 | // with the License. You may obtain a copy of the License at | |
8 | // | |
9 | // http://www.apache.org/licenses/LICENSE-2.0 | |
10 | // | |
11 | // Unless required by applicable law or agreed to in writing, | |
12 | // software distributed under the License is distributed on an | |
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
14 | // KIND, either express or implied. See the License for the | |
15 | // specific language governing permissions and limitations | |
16 | // under the License. | |
17 | ||
18 | #include "arrow/dbi/hiveserver2/util.h" | |
19 | ||
20 | #include <algorithm> | |
21 | #include <memory> | |
22 | #include <sstream> | |
23 | #include <vector> | |
24 | ||
25 | #include "arrow/dbi/hiveserver2/columnar_row_set.h" | |
26 | #include "arrow/dbi/hiveserver2/thrift_internal.h" | |
27 | ||
28 | #include "arrow/dbi/hiveserver2/TCLIService.h" | |
29 | #include "arrow/dbi/hiveserver2/TCLIService_types.h" | |
30 | ||
31 | #include "arrow/status.h" | |
32 | ||
33 | namespace hs2 = apache::hive::service::cli::thrift; | |
34 | using std::unique_ptr; | |
35 | ||
36 | namespace arrow { | |
37 | namespace hiveserver2 { | |
38 | ||
39 | // PrintResults | |
40 | namespace { | |
41 | ||
42 | const char kNullSymbol[] = "NULL"; | |
43 | const char kTrueSymbol[] = "true"; | |
44 | const char kFalseSymbol[] = "false"; | |
45 | ||
46 | struct PrintInfo { | |
47 | // The PrintInfo takes ownership of the Column ptr. | |
48 | PrintInfo(Column* c, size_t m) : column(c), max_size(m) {} | |
49 | ||
50 | unique_ptr<Column> column; | |
51 | size_t max_size; | |
52 | }; | |
53 | ||
54 | // Adds a horizontal line of '-'s, with '+'s at the column breaks. | |
55 | static void AddTableBreak(std::ostream& out, std::vector<PrintInfo>* columns) { | |
56 | for (size_t i = 0; i < columns->size(); ++i) { | |
57 | out << "+"; | |
58 | for (size_t j = 0; j < (*columns)[i].max_size + 2; ++j) { | |
59 | out << "-"; | |
60 | } | |
61 | } | |
62 | out << "+\n"; | |
63 | } | |
64 | ||
65 | // Returns the number of spaces needed to display n, i.e. the number of digits n has, | |
66 | // plus 1 if n is negative. | |
67 | static size_t NumSpaces(int64_t n) { | |
68 | if (n < 0) { | |
69 | return 1 + NumSpaces(-n); | |
70 | } else if (n < 10) { | |
71 | return 1; | |
72 | } else { | |
73 | return 1 + NumSpaces(n / 10); | |
74 | } | |
75 | } | |
76 | ||
77 | // Returns the max size needed to display a column of integer type. | |
78 | template <typename T> | |
79 | static size_t GetIntMaxSize(T* column, const std::string& column_name) { | |
80 | size_t max_size = column_name.size(); | |
81 | for (int i = 0; i < column->length(); ++i) { | |
82 | if (!column->IsNull(i)) { | |
83 | max_size = std::max(max_size, NumSpaces(column->data()[i])); | |
84 | } else { | |
85 | max_size = std::max(max_size, sizeof(kNullSymbol)); | |
86 | } | |
87 | } | |
88 | return max_size; | |
89 | } | |
90 | ||
91 | } // namespace | |
92 | ||
93 | void Util::PrintResults(const Operation* op, std::ostream& out) { | |
94 | unique_ptr<ColumnarRowSet> results; | |
95 | bool has_more_rows = true; | |
96 | while (has_more_rows) { | |
97 | Status s = op->Fetch(&results, &has_more_rows); | |
98 | if (!s.ok()) { | |
99 | out << s.ToString(); | |
100 | return; | |
101 | } | |
102 | ||
103 | std::vector<ColumnDesc> column_descs; | |
104 | s = op->GetResultSetMetadata(&column_descs); | |
105 | ||
106 | if (!s.ok()) { | |
107 | out << s.ToString(); | |
108 | return; | |
109 | } else if (column_descs.size() == 0) { | |
110 | out << "No result set to print.\n"; | |
111 | return; | |
112 | } | |
113 | ||
114 | std::vector<PrintInfo> columns; | |
115 | for (int i = 0; i < static_cast<int>(column_descs.size()); i++) { | |
116 | const std::string column_name = column_descs[i].column_name(); | |
117 | switch (column_descs[i].type()->type_id()) { | |
118 | case ColumnType::TypeId::BOOLEAN: { | |
119 | BoolColumn* bool_col = results->GetBoolCol(i).release(); | |
120 | ||
121 | // The largest symbol is length 4 unless there is a FALSE, then is it | |
122 | // kFalseSymbol.size() = 5. | |
123 | size_t max_size = std::max(column_name.size(), sizeof(kTrueSymbol)); | |
124 | for (int j = 0; j < bool_col->length(); ++j) { | |
125 | if (!bool_col->IsNull(j) && !bool_col->data()[j]) { | |
126 | max_size = std::max(max_size, sizeof(kFalseSymbol)); | |
127 | break; | |
128 | } | |
129 | } | |
130 | ||
131 | columns.emplace_back(bool_col, max_size); | |
132 | break; | |
133 | } | |
134 | case ColumnType::TypeId::TINYINT: { | |
135 | ByteColumn* byte_col = results->GetByteCol(i).release(); | |
136 | columns.emplace_back(byte_col, GetIntMaxSize(byte_col, column_name)); | |
137 | break; | |
138 | } | |
139 | case ColumnType::TypeId::SMALLINT: { | |
140 | Int16Column* int16_col = results->GetInt16Col(i).release(); | |
141 | columns.emplace_back(int16_col, GetIntMaxSize(int16_col, column_name)); | |
142 | break; | |
143 | } | |
144 | case ColumnType::TypeId::INT: { | |
145 | Int32Column* int32_col = results->GetInt32Col(i).release(); | |
146 | columns.emplace_back(int32_col, GetIntMaxSize(int32_col, column_name)); | |
147 | break; | |
148 | } | |
149 | case ColumnType::TypeId::BIGINT: { | |
150 | Int64Column* int64_col = results->GetInt64Col(i).release(); | |
151 | columns.emplace_back(int64_col, GetIntMaxSize(int64_col, column_name)); | |
152 | break; | |
153 | } | |
154 | case ColumnType::TypeId::STRING: { | |
155 | unique_ptr<StringColumn> string_col = results->GetStringCol(i); | |
156 | ||
157 | size_t max_size = column_name.size(); | |
158 | for (int j = 0; j < string_col->length(); ++j) { | |
159 | if (!string_col->IsNull(j)) { | |
160 | max_size = std::max(max_size, string_col->data()[j].size()); | |
161 | } else { | |
162 | max_size = std::max(max_size, sizeof(kNullSymbol)); | |
163 | } | |
164 | } | |
165 | ||
166 | columns.emplace_back(string_col.release(), max_size); | |
167 | break; | |
168 | } | |
169 | case ColumnType::TypeId::BINARY: | |
170 | columns.emplace_back(results->GetBinaryCol(i).release(), column_name.size()); | |
171 | break; | |
172 | default: { | |
173 | out << "Unrecognized ColumnType = " << column_descs[i].type()->ToString(); | |
174 | } | |
175 | } | |
176 | } | |
177 | ||
178 | AddTableBreak(out, &columns); | |
179 | for (size_t i = 0; i < columns.size(); ++i) { | |
180 | out << "| " << column_descs[i].column_name() << " "; | |
181 | ||
182 | int padding = | |
183 | static_cast<int>(columns[i].max_size - column_descs[i].column_name().size()); | |
184 | while (padding > 0) { | |
185 | out << " "; | |
186 | --padding; | |
187 | } | |
188 | } | |
189 | out << "|\n"; | |
190 | AddTableBreak(out, &columns); | |
191 | ||
192 | for (int i = 0; i < columns[0].column->length(); ++i) { | |
193 | for (size_t j = 0; j < columns.size(); ++j) { | |
194 | std::stringstream value; | |
195 | ||
196 | if (columns[j].column->IsNull(i)) { | |
197 | value << kNullSymbol; | |
198 | } else { | |
199 | switch (column_descs[j].type()->type_id()) { | |
200 | case ColumnType::TypeId::BOOLEAN: | |
201 | if (reinterpret_cast<BoolColumn*>(columns[j].column.get())->data()[i]) { | |
202 | value << kTrueSymbol; | |
203 | } else { | |
204 | value << kFalseSymbol; | |
205 | } | |
206 | break; | |
207 | case ColumnType::TypeId::TINYINT: | |
208 | // The cast prevents us from printing this as a char. | |
209 | value << static_cast<int16_t>( | |
210 | reinterpret_cast<ByteColumn*>(columns[j].column.get())->data()[i]); | |
211 | break; | |
212 | case ColumnType::TypeId::SMALLINT: | |
213 | value << reinterpret_cast<Int16Column*>(columns[j].column.get())->data()[i]; | |
214 | break; | |
215 | case ColumnType::TypeId::INT: | |
216 | value << reinterpret_cast<Int32Column*>(columns[j].column.get())->data()[i]; | |
217 | break; | |
218 | case ColumnType::TypeId::BIGINT: | |
219 | value << reinterpret_cast<Int64Column*>(columns[j].column.get())->data()[i]; | |
220 | break; | |
221 | case ColumnType::TypeId::STRING: | |
222 | value | |
223 | << reinterpret_cast<StringColumn*>(columns[j].column.get())->data()[i]; | |
224 | break; | |
225 | case ColumnType::TypeId::BINARY: | |
226 | value | |
227 | << reinterpret_cast<BinaryColumn*>(columns[j].column.get())->data()[i]; | |
228 | break; | |
229 | default: | |
230 | value << "unrecognized type"; | |
231 | break; | |
232 | } | |
233 | } | |
234 | ||
235 | std::string value_str = value.str(); | |
236 | out << "| " << value_str << " "; | |
237 | int padding = static_cast<int>(columns[j].max_size - value_str.size()); | |
238 | while (padding > 0) { | |
239 | out << " "; | |
240 | --padding; | |
241 | } | |
242 | } | |
243 | out << "|\n"; | |
244 | } | |
245 | AddTableBreak(out, &columns); | |
246 | } | |
247 | } | |
248 | ||
249 | } // namespace hiveserver2 | |
250 | } // namespace arrow |