1 | /** |
2 | * Licensed to the Apache Software Foundation (ASF) under one |
3 | * or more contributor license agreements. See the NOTICE file |
4 | * distributed with this work for additional information |
5 | * regarding copyright ownership. The ASF licenses this file |
6 | * to you under the Apache License, Version 2.0 (the |
7 | * "License"); you may not use this file except in compliance |
8 | * with the License. You may obtain a copy of the License at |
9 | * |
10 | * http://www.apache.org/licenses/LICENSE-2.0 |
11 | * |
12 | * Unless required by applicable law or agreed to in writing, software |
13 | * distributed under the License is distributed on an "AS IS" BASIS, |
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
15 | * See the License for the specific language governing permissions and |
16 | * limitations under the License. |
17 | */ |
18 | |
19 | #include "orc/ColumnPrinter.hh" |
20 | #include "orc/orc-config.hh" |
21 | |
22 | #include "Adaptor.hh" |
23 | |
24 | #include <limits> |
25 | #include <sstream> |
26 | #include <stdexcept> |
27 | #include <time.h> |
28 | #include <typeinfo> |
29 | |
30 | #ifdef __clang__ |
31 | #pragma clang diagnostic ignored "-Wformat-security" |
32 | #endif |
33 | |
34 | namespace orc { |
35 | |
36 | class VoidColumnPrinter: public ColumnPrinter { |
37 | public: |
38 | VoidColumnPrinter(std::string&); |
39 | ~VoidColumnPrinter() override {} |
40 | void printRow(uint64_t rowId) override; |
41 | void reset(const ColumnVectorBatch& batch) override; |
42 | }; |
43 | |
44 | class BooleanColumnPrinter: public ColumnPrinter { |
45 | private: |
46 | const int64_t* data; |
47 | public: |
48 | BooleanColumnPrinter(std::string&); |
49 | ~BooleanColumnPrinter() override {} |
50 | void printRow(uint64_t rowId) override; |
51 | void reset(const ColumnVectorBatch& batch) override; |
52 | }; |
53 | |
54 | class LongColumnPrinter: public ColumnPrinter { |
55 | private: |
56 | const int64_t* data; |
57 | public: |
58 | LongColumnPrinter(std::string&); |
59 | ~LongColumnPrinter() override {} |
60 | void printRow(uint64_t rowId) override; |
61 | void reset(const ColumnVectorBatch& batch) override; |
62 | }; |
63 | |
64 | class DoubleColumnPrinter: public ColumnPrinter { |
65 | private: |
66 | const double* data; |
67 | const bool isFloat; |
68 | |
69 | public: |
70 | DoubleColumnPrinter(std::string&, const Type& type); |
71 | virtual ~DoubleColumnPrinter() override {} |
72 | void printRow(uint64_t rowId) override; |
73 | void reset(const ColumnVectorBatch& batch) override; |
74 | }; |
75 | |
76 | class TimestampColumnPrinter: public ColumnPrinter { |
77 | private: |
78 | const int64_t* seconds; |
79 | const int64_t* nanoseconds; |
80 | |
81 | public: |
82 | TimestampColumnPrinter(std::string&); |
83 | ~TimestampColumnPrinter() override {} |
84 | void printRow(uint64_t rowId) override; |
85 | void reset(const ColumnVectorBatch& batch) override; |
86 | }; |
87 | |
88 | class DateColumnPrinter: public ColumnPrinter { |
89 | private: |
90 | const int64_t* data; |
91 | |
92 | public: |
93 | DateColumnPrinter(std::string&); |
94 | ~DateColumnPrinter() override {} |
95 | void printRow(uint64_t rowId) override; |
96 | void reset(const ColumnVectorBatch& batch) override; |
97 | }; |
98 | |
99 | class Decimal64ColumnPrinter: public ColumnPrinter { |
100 | private: |
101 | const int64_t* data; |
102 | int32_t scale; |
103 | public: |
104 | Decimal64ColumnPrinter(std::string&); |
105 | ~Decimal64ColumnPrinter() override {} |
106 | void printRow(uint64_t rowId) override; |
107 | void reset(const ColumnVectorBatch& batch) override; |
108 | }; |
109 | |
110 | class Decimal128ColumnPrinter: public ColumnPrinter { |
111 | private: |
112 | const Int128* data; |
113 | int32_t scale; |
114 | public: |
115 | Decimal128ColumnPrinter(std::string&); |
116 | ~Decimal128ColumnPrinter() override {} |
117 | void printRow(uint64_t rowId) override; |
118 | void reset(const ColumnVectorBatch& batch) override; |
119 | }; |
120 | |
121 | class StringColumnPrinter: public ColumnPrinter { |
122 | private: |
123 | const char* const * start; |
124 | const int64_t* length; |
125 | public: |
126 | StringColumnPrinter(std::string&); |
127 | virtual ~StringColumnPrinter() override {} |
128 | void printRow(uint64_t rowId) override; |
129 | void reset(const ColumnVectorBatch& batch) override; |
130 | }; |
131 | |
132 | class BinaryColumnPrinter: public ColumnPrinter { |
133 | private: |
134 | const char* const * start; |
135 | const int64_t* length; |
136 | public: |
137 | BinaryColumnPrinter(std::string&); |
138 | virtual ~BinaryColumnPrinter() override {} |
139 | void printRow(uint64_t rowId) override; |
140 | void reset(const ColumnVectorBatch& batch) override; |
141 | }; |
142 | |
143 | class ListColumnPrinter: public ColumnPrinter { |
144 | private: |
145 | const int64_t* offsets; |
146 | std::unique_ptr<ColumnPrinter> elementPrinter; |
147 | |
148 | public: |
149 | ListColumnPrinter(std::string&, const Type& type); |
150 | virtual ~ListColumnPrinter() override {} |
151 | void printRow(uint64_t rowId) override; |
152 | void reset(const ColumnVectorBatch& batch) override; |
153 | }; |
154 | |
155 | class MapColumnPrinter: public ColumnPrinter { |
156 | private: |
157 | const int64_t* offsets; |
158 | std::unique_ptr<ColumnPrinter> keyPrinter; |
159 | std::unique_ptr<ColumnPrinter> elementPrinter; |
160 | |
161 | public: |
162 | MapColumnPrinter(std::string&, const Type& type); |
163 | virtual ~MapColumnPrinter() override {} |
164 | void printRow(uint64_t rowId) override; |
165 | void reset(const ColumnVectorBatch& batch) override; |
166 | }; |
167 | |
168 | class UnionColumnPrinter: public ColumnPrinter { |
169 | private: |
170 | const unsigned char *tags; |
171 | const uint64_t* offsets; |
172 | std::vector<ColumnPrinter*> fieldPrinter; |
173 | |
174 | public: |
175 | UnionColumnPrinter(std::string&, const Type& type); |
176 | virtual ~UnionColumnPrinter() override; |
177 | void printRow(uint64_t rowId) override; |
178 | void reset(const ColumnVectorBatch& batch) override; |
179 | }; |
180 | |
181 | class StructColumnPrinter: public ColumnPrinter { |
182 | private: |
183 | std::vector<ColumnPrinter*> fieldPrinter; |
184 | std::vector<std::string> fieldNames; |
185 | public: |
186 | StructColumnPrinter(std::string&, const Type& type); |
187 | virtual ~StructColumnPrinter() override; |
188 | void printRow(uint64_t rowId) override; |
189 | void reset(const ColumnVectorBatch& batch) override; |
190 | }; |
191 | |
192 | void writeChar(std::string& file, char ch) { |
193 | file += ch; |
194 | } |
195 | |
196 | void writeString(std::string& file, const char *ptr) { |
197 | size_t len = strlen(ptr); |
198 | file.append(ptr, len); |
199 | } |
200 | |
201 | ColumnPrinter::ColumnPrinter(std::string& _buffer |
202 | ): buffer(_buffer) { |
203 | notNull = nullptr; |
204 | hasNulls = false; |
205 | } |
206 | |
207 | ColumnPrinter::~ColumnPrinter() { |
208 | // PASS |
209 | } |
210 | |
211 | void ColumnPrinter::reset(const ColumnVectorBatch& batch) { |
212 | hasNulls = batch.hasNulls; |
213 | if (hasNulls) { |
214 | notNull = batch.notNull.data(); |
215 | } else { |
216 | notNull = nullptr ; |
217 | } |
218 | } |
219 | |
220 | std::unique_ptr<ColumnPrinter> createColumnPrinter(std::string& buffer, |
221 | const Type* type) { |
222 | ColumnPrinter *result = nullptr; |
223 | if (type == nullptr) { |
224 | result = new VoidColumnPrinter(buffer); |
225 | } else { |
226 | switch(static_cast<int64_t>(type->getKind())) { |
227 | case BOOLEAN: |
228 | result = new BooleanColumnPrinter(buffer); |
229 | break; |
230 | |
231 | case BYTE: |
232 | case SHORT: |
233 | case INT: |
234 | case LONG: |
235 | result = new LongColumnPrinter(buffer); |
236 | break; |
237 | |
238 | case FLOAT: |
239 | case DOUBLE: |
240 | result = new DoubleColumnPrinter(buffer, *type); |
241 | break; |
242 | |
243 | case STRING: |
244 | case VARCHAR : |
245 | case CHAR: |
246 | result = new StringColumnPrinter(buffer); |
247 | break; |
248 | |
249 | case BINARY: |
250 | result = new BinaryColumnPrinter(buffer); |
251 | break; |
252 | |
253 | case TIMESTAMP: |
254 | result = new TimestampColumnPrinter(buffer); |
255 | break; |
256 | |
257 | case LIST: |
258 | result = new ListColumnPrinter(buffer, *type); |
259 | break; |
260 | |
261 | case MAP: |
262 | result = new MapColumnPrinter(buffer, *type); |
263 | break; |
264 | |
265 | case STRUCT: |
266 | result = new StructColumnPrinter(buffer, *type); |
267 | break; |
268 | |
269 | case DECIMAL: |
270 | if (type->getPrecision() == 0 || type->getPrecision() > 18) { |
271 | result = new Decimal128ColumnPrinter(buffer); |
272 | } else { |
273 | result = new Decimal64ColumnPrinter(buffer); |
274 | } |
275 | break; |
276 | |
277 | case DATE: |
278 | result = new DateColumnPrinter(buffer); |
279 | break; |
280 | |
281 | case UNION: |
282 | result = new UnionColumnPrinter(buffer, *type); |
283 | break; |
284 | |
285 | default: |
286 | throw std::logic_error("unknown batch type" ); |
287 | } |
288 | } |
289 | return std::unique_ptr<ColumnPrinter>(result); |
290 | } |
291 | |
292 | VoidColumnPrinter::VoidColumnPrinter(std::string& buffer |
293 | ): ColumnPrinter(buffer) { |
294 | // PASS |
295 | } |
296 | |
297 | void VoidColumnPrinter::reset(const ColumnVectorBatch&) { |
298 | // PASS |
299 | } |
300 | |
301 | void VoidColumnPrinter::printRow(uint64_t) { |
302 | writeString(buffer, "null" ); |
303 | } |
304 | |
305 | LongColumnPrinter::LongColumnPrinter(std::string& buffer |
306 | ): ColumnPrinter(buffer), |
307 | data(nullptr) { |
308 | // PASS |
309 | } |
310 | |
311 | void LongColumnPrinter::reset(const ColumnVectorBatch& batch) { |
312 | ColumnPrinter::reset(batch); |
313 | data = dynamic_cast<const LongVectorBatch&>(batch).data.data(); |
314 | } |
315 | |
316 | void LongColumnPrinter::printRow(uint64_t rowId) { |
317 | if (hasNulls && !notNull[rowId]) { |
318 | writeString(buffer, "null" ); |
319 | } else { |
320 | char numBuffer[64]; |
321 | snprintf(numBuffer, sizeof(numBuffer), "%" INT64_FORMAT_STRING "d" , |
322 | static_cast<int64_t >(data[rowId])); |
323 | writeString(buffer, numBuffer); |
324 | } |
325 | } |
326 | |
327 | DoubleColumnPrinter::DoubleColumnPrinter(std::string& buffer, |
328 | const Type& type |
329 | ): ColumnPrinter(buffer), |
330 | data(nullptr), |
331 | isFloat(type.getKind() == FLOAT){ |
332 | // PASS |
333 | } |
334 | |
335 | void DoubleColumnPrinter::reset(const ColumnVectorBatch& batch) { |
336 | ColumnPrinter::reset(batch); |
337 | data = dynamic_cast<const DoubleVectorBatch&>(batch).data.data(); |
338 | } |
339 | |
340 | void DoubleColumnPrinter::printRow(uint64_t rowId) { |
341 | if (hasNulls && !notNull[rowId]) { |
342 | writeString(buffer, "null" ); |
343 | } else { |
344 | char numBuffer[64]; |
345 | snprintf(numBuffer, sizeof(numBuffer), isFloat ? "%.7g" : "%.14g" , |
346 | data[rowId]); |
347 | writeString(buffer, numBuffer); |
348 | } |
349 | } |
350 | |
351 | Decimal64ColumnPrinter::Decimal64ColumnPrinter(std::string& buffer |
352 | ): ColumnPrinter(buffer), |
353 | data(nullptr), |
354 | scale(0) { |
355 | // PASS |
356 | } |
357 | |
358 | void Decimal64ColumnPrinter::reset(const ColumnVectorBatch& batch) { |
359 | ColumnPrinter::reset(batch); |
360 | data = dynamic_cast<const Decimal64VectorBatch&>(batch).values.data(); |
361 | scale = dynamic_cast<const Decimal64VectorBatch&>(batch).scale; |
362 | } |
363 | |
364 | std::string toDecimalString(int64_t value, int32_t scale) { |
365 | std::stringstream buffer; |
366 | if (scale == 0) { |
367 | buffer << value; |
368 | return buffer.str(); |
369 | } |
370 | std::string sign = "" ; |
371 | if (value < 0) { |
372 | sign = "-" ; |
373 | value = -value; |
374 | } |
375 | buffer << value; |
376 | std::string str = buffer.str(); |
377 | int32_t len = static_cast<int32_t>(str.length()); |
378 | if (len > scale) { |
379 | return sign + str.substr(0, static_cast<size_t>(len - scale)) + "." + |
380 | str.substr(static_cast<size_t>(len - scale), |
381 | static_cast<size_t>(scale)); |
382 | } else if (len == scale) { |
383 | return sign + "0." + str; |
384 | } else { |
385 | std::string result = sign + "0." ; |
386 | for(int32_t i=0; i < scale - len; ++i) { |
387 | result += "0" ; |
388 | } |
389 | return result + str; |
390 | } |
391 | } |
392 | |
393 | void Decimal64ColumnPrinter::printRow(uint64_t rowId) { |
394 | if (hasNulls && !notNull[rowId]) { |
395 | writeString(buffer, "null" ); |
396 | } else { |
397 | writeString(buffer, toDecimalString(data[rowId], scale).c_str()); |
398 | } |
399 | } |
400 | |
401 | Decimal128ColumnPrinter::Decimal128ColumnPrinter(std::string& buffer |
402 | ): ColumnPrinter(buffer), |
403 | data(nullptr), |
404 | scale(0) { |
405 | // PASS |
406 | } |
407 | |
408 | void Decimal128ColumnPrinter::reset(const ColumnVectorBatch& batch) { |
409 | ColumnPrinter::reset(batch); |
410 | data = dynamic_cast<const Decimal128VectorBatch&>(batch).values.data(); |
411 | scale = dynamic_cast<const Decimal128VectorBatch&>(batch).scale; |
412 | } |
413 | |
414 | void Decimal128ColumnPrinter::printRow(uint64_t rowId) { |
415 | if (hasNulls && !notNull[rowId]) { |
416 | writeString(buffer, "null" ); |
417 | } else { |
418 | writeString(buffer, data[rowId].toDecimalString(scale).c_str()); |
419 | } |
420 | } |
421 | |
422 | StringColumnPrinter::StringColumnPrinter(std::string& buffer |
423 | ): ColumnPrinter(buffer), |
424 | start(nullptr), |
425 | length(nullptr) { |
426 | // PASS |
427 | } |
428 | |
429 | void StringColumnPrinter::reset(const ColumnVectorBatch& batch) { |
430 | ColumnPrinter::reset(batch); |
431 | start = dynamic_cast<const StringVectorBatch&>(batch).data.data(); |
432 | length = dynamic_cast<const StringVectorBatch&>(batch).length.data(); |
433 | } |
434 | |
435 | void StringColumnPrinter::printRow(uint64_t rowId) { |
436 | if (hasNulls && !notNull[rowId]) { |
437 | writeString(buffer, "null" ); |
438 | } else { |
439 | writeChar(buffer, '"'); |
440 | for(int64_t i=0; i < length[rowId]; ++i) { |
441 | char ch = static_cast<char>(start[rowId][i]); |
442 | switch (ch) { |
443 | case '\\': |
444 | writeString(buffer, "\\\\" ); |
445 | break; |
446 | case '\b': |
447 | writeString(buffer, "\\b" ); |
448 | break; |
449 | case '\f': |
450 | writeString(buffer, "\\f" ); |
451 | break; |
452 | case '\n': |
453 | writeString(buffer, "\\n" ); |
454 | break; |
455 | case '\r': |
456 | writeString(buffer, "\\r" ); |
457 | break; |
458 | case '\t': |
459 | writeString(buffer, "\\t" ); |
460 | break; |
461 | case '"': |
462 | writeString(buffer, "\\\"" ); |
463 | break; |
464 | default: |
465 | writeChar(buffer, ch); |
466 | break; |
467 | } |
468 | } |
469 | writeChar(buffer, '"'); |
470 | } |
471 | } |
472 | |
473 | ListColumnPrinter::ListColumnPrinter(std::string& buffer, |
474 | const Type& type |
475 | ): ColumnPrinter(buffer), |
476 | offsets(nullptr) { |
477 | elementPrinter = createColumnPrinter(buffer, type.getSubtype(0)); |
478 | } |
479 | |
480 | void ListColumnPrinter::reset(const ColumnVectorBatch& batch) { |
481 | ColumnPrinter::reset(batch); |
482 | offsets = dynamic_cast<const ListVectorBatch&>(batch).offsets.data(); |
483 | elementPrinter->reset(*dynamic_cast<const ListVectorBatch&>(batch). |
484 | elements); |
485 | } |
486 | |
487 | void ListColumnPrinter::printRow(uint64_t rowId) { |
488 | if (hasNulls && !notNull[rowId]) { |
489 | writeString(buffer, "null" ); |
490 | } else { |
491 | writeChar(buffer, '['); |
492 | for(int64_t i=offsets[rowId]; i < offsets[rowId+1]; ++i) { |
493 | if (i != offsets[rowId]) { |
494 | writeString(buffer, ", " ); |
495 | } |
496 | elementPrinter->printRow(static_cast<uint64_t>(i)); |
497 | } |
498 | writeChar(buffer, ']'); |
499 | } |
500 | } |
501 | |
502 | MapColumnPrinter::MapColumnPrinter(std::string& buffer, |
503 | const Type& type |
504 | ): ColumnPrinter(buffer), |
505 | offsets(nullptr) { |
506 | keyPrinter = createColumnPrinter(buffer, type.getSubtype(0)); |
507 | elementPrinter = createColumnPrinter(buffer, type.getSubtype(1)); |
508 | } |
509 | |
510 | void MapColumnPrinter::reset(const ColumnVectorBatch& batch) { |
511 | ColumnPrinter::reset(batch); |
512 | const MapVectorBatch& myBatch = dynamic_cast<const MapVectorBatch&>(batch); |
513 | offsets = myBatch.offsets.data(); |
514 | keyPrinter->reset(*myBatch.keys); |
515 | elementPrinter->reset(*myBatch.elements); |
516 | } |
517 | |
518 | void MapColumnPrinter::printRow(uint64_t rowId) { |
519 | if (hasNulls && !notNull[rowId]) { |
520 | writeString(buffer, "null" ); |
521 | } else { |
522 | writeChar(buffer, '['); |
523 | for(int64_t i=offsets[rowId]; i < offsets[rowId+1]; ++i) { |
524 | if (i != offsets[rowId]) { |
525 | writeString(buffer, ", " ); |
526 | } |
527 | writeString(buffer, "{\"key\": " ); |
528 | keyPrinter->printRow(static_cast<uint64_t>(i)); |
529 | writeString(buffer, ", \"value\": " ); |
530 | elementPrinter->printRow(static_cast<uint64_t>(i)); |
531 | writeChar(buffer, '}'); |
532 | } |
533 | writeChar(buffer, ']'); |
534 | } |
535 | } |
536 | |
537 | UnionColumnPrinter::UnionColumnPrinter(std::string& buffer, |
538 | const Type& type |
539 | ): ColumnPrinter(buffer), |
540 | tags(nullptr), |
541 | offsets(nullptr) { |
542 | for(unsigned int i=0; i < type.getSubtypeCount(); ++i) { |
543 | fieldPrinter.push_back(createColumnPrinter(buffer, type.getSubtype(i)) |
544 | .release()); |
545 | } |
546 | } |
547 | |
548 | UnionColumnPrinter::~UnionColumnPrinter() { |
549 | for (size_t i = 0; i < fieldPrinter.size(); i++) { |
550 | delete fieldPrinter[i]; |
551 | } |
552 | } |
553 | |
554 | void UnionColumnPrinter::reset(const ColumnVectorBatch& batch) { |
555 | ColumnPrinter::reset(batch); |
556 | const UnionVectorBatch& unionBatch = |
557 | dynamic_cast<const UnionVectorBatch&>(batch); |
558 | tags = unionBatch.tags.data(); |
559 | offsets = unionBatch.offsets.data(); |
560 | for(size_t i=0; i < fieldPrinter.size(); ++i) { |
561 | fieldPrinter[i]->reset(*(unionBatch.children[i])); |
562 | } |
563 | } |
564 | |
565 | void UnionColumnPrinter::printRow(uint64_t rowId) { |
566 | if (hasNulls && !notNull[rowId]) { |
567 | writeString(buffer, "null" ); |
568 | } else { |
569 | writeString(buffer, "{\"tag\": " ); |
570 | char numBuffer[64]; |
571 | snprintf(numBuffer, sizeof(numBuffer), "%" INT64_FORMAT_STRING "d" , |
572 | static_cast<int64_t>(tags[rowId])); |
573 | writeString(buffer, numBuffer); |
574 | writeString(buffer, ", \"value\": " ); |
575 | fieldPrinter[tags[rowId]]->printRow(offsets[rowId]); |
576 | writeChar(buffer, '}'); |
577 | } |
578 | } |
579 | |
580 | StructColumnPrinter::StructColumnPrinter(std::string& buffer, |
581 | const Type& type |
582 | ): ColumnPrinter(buffer) { |
583 | for(unsigned int i=0; i < type.getSubtypeCount(); ++i) { |
584 | fieldNames.push_back(type.getFieldName(i)); |
585 | fieldPrinter.push_back(createColumnPrinter(buffer, |
586 | type.getSubtype(i)) |
587 | .release()); |
588 | } |
589 | } |
590 | |
591 | StructColumnPrinter::~StructColumnPrinter() { |
592 | for (size_t i = 0; i < fieldPrinter.size(); i++) { |
593 | delete fieldPrinter[i]; |
594 | } |
595 | } |
596 | |
597 | void StructColumnPrinter::reset(const ColumnVectorBatch& batch) { |
598 | ColumnPrinter::reset(batch); |
599 | const StructVectorBatch& structBatch = |
600 | dynamic_cast<const StructVectorBatch&>(batch); |
601 | for(size_t i=0; i < fieldPrinter.size(); ++i) { |
602 | fieldPrinter[i]->reset(*(structBatch.fields[i])); |
603 | } |
604 | } |
605 | |
606 | void StructColumnPrinter::printRow(uint64_t rowId) { |
607 | if (hasNulls && !notNull[rowId]) { |
608 | writeString(buffer, "null" ); |
609 | } else { |
610 | writeChar(buffer, '{'); |
611 | for(unsigned int i=0; i < fieldPrinter.size(); ++i) { |
612 | if (i != 0) { |
613 | writeString(buffer, ", " ); |
614 | } |
615 | writeChar(buffer, '"'); |
616 | writeString(buffer, fieldNames[i].c_str()); |
617 | writeString(buffer, "\": " ); |
618 | fieldPrinter[i]->printRow(rowId); |
619 | } |
620 | writeChar(buffer, '}'); |
621 | } |
622 | } |
623 | |
624 | DateColumnPrinter::DateColumnPrinter(std::string& buffer |
625 | ): ColumnPrinter(buffer), |
626 | data(nullptr) { |
627 | // PASS |
628 | } |
629 | |
630 | void DateColumnPrinter::printRow(uint64_t rowId) { |
631 | if (hasNulls && !notNull[rowId]) { |
632 | writeString(buffer, "null" ); |
633 | } else { |
634 | const time_t timeValue = data[rowId] * 24 * 60 * 60; |
635 | struct tm tmValue; |
636 | gmtime_r(&timeValue, &tmValue); |
637 | char timeBuffer[11]; |
638 | strftime(timeBuffer, sizeof(timeBuffer), "%Y-%m-%d" , &tmValue); |
639 | writeChar(buffer, '"'); |
640 | writeString(buffer, timeBuffer); |
641 | writeChar(buffer, '"'); |
642 | } |
643 | } |
644 | |
645 | void DateColumnPrinter::reset(const ColumnVectorBatch& batch) { |
646 | ColumnPrinter::reset(batch); |
647 | data = dynamic_cast<const LongVectorBatch&>(batch).data.data(); |
648 | } |
649 | |
650 | BooleanColumnPrinter::BooleanColumnPrinter(std::string& buffer |
651 | ): ColumnPrinter(buffer), |
652 | data(nullptr) { |
653 | // PASS |
654 | } |
655 | |
656 | void BooleanColumnPrinter::printRow(uint64_t rowId) { |
657 | if (hasNulls && !notNull[rowId]) { |
658 | writeString(buffer, "null" ); |
659 | } else { |
660 | writeString(buffer, (data[rowId] ? "true" : "false" )); |
661 | } |
662 | } |
663 | |
664 | void BooleanColumnPrinter::reset(const ColumnVectorBatch& batch) { |
665 | ColumnPrinter::reset(batch); |
666 | data = dynamic_cast<const LongVectorBatch&>(batch).data.data(); |
667 | } |
668 | |
669 | BinaryColumnPrinter::BinaryColumnPrinter(std::string& buffer |
670 | ): ColumnPrinter(buffer), |
671 | start(nullptr), |
672 | length(nullptr) { |
673 | // PASS |
674 | } |
675 | |
676 | void BinaryColumnPrinter::printRow(uint64_t rowId) { |
677 | if (hasNulls && !notNull[rowId]) { |
678 | writeString(buffer, "null" ); |
679 | } else { |
680 | writeChar(buffer, '['); |
681 | for(int64_t i=0; i < length[rowId]; ++i) { |
682 | if (i != 0) { |
683 | writeString(buffer, ", " ); |
684 | } |
685 | char numBuffer[64]; |
686 | snprintf(numBuffer, sizeof(numBuffer), "%d" , |
687 | (static_cast<const int>(start[rowId][i]) & 0xff)); |
688 | writeString(buffer, numBuffer); |
689 | } |
690 | writeChar(buffer, ']'); |
691 | } |
692 | } |
693 | |
694 | void BinaryColumnPrinter::reset(const ColumnVectorBatch& batch) { |
695 | ColumnPrinter::reset(batch); |
696 | start = dynamic_cast<const StringVectorBatch&>(batch).data.data(); |
697 | length = dynamic_cast<const StringVectorBatch&>(batch).length.data(); |
698 | } |
699 | |
700 | TimestampColumnPrinter::TimestampColumnPrinter(std::string& buffer |
701 | ): ColumnPrinter(buffer), |
702 | seconds(nullptr), |
703 | nanoseconds(nullptr) { |
704 | // PASS |
705 | } |
706 | |
707 | void TimestampColumnPrinter::printRow(uint64_t rowId) { |
708 | const int64_t NANO_DIGITS = 9; |
709 | if (hasNulls && !notNull[rowId]) { |
710 | writeString(buffer, "null" ); |
711 | } else { |
712 | int64_t nanos = nanoseconds[rowId]; |
713 | time_t secs = static_cast<time_t>(seconds[rowId]); |
714 | struct tm tmValue; |
715 | gmtime_r(&secs, &tmValue); |
716 | char timeBuffer[20]; |
717 | strftime(timeBuffer, sizeof(timeBuffer), "%Y-%m-%d %H:%M:%S" , &tmValue); |
718 | writeChar(buffer, '"'); |
719 | writeString(buffer, timeBuffer); |
720 | writeChar(buffer, '.'); |
721 | // remove trailing zeros off the back of the nanos value. |
722 | int64_t zeroDigits = 0; |
723 | if (nanos == 0) { |
724 | zeroDigits = 8; |
725 | } else { |
726 | while (nanos % 10 == 0) { |
727 | nanos /= 10; |
728 | zeroDigits += 1; |
729 | } |
730 | } |
731 | char numBuffer[64]; |
732 | snprintf(numBuffer, sizeof(numBuffer), |
733 | "%0*" INT64_FORMAT_STRING "d\"" , |
734 | static_cast<int>(NANO_DIGITS - zeroDigits), |
735 | static_cast<int64_t >(nanos)); |
736 | writeString(buffer, numBuffer); |
737 | } |
738 | } |
739 | |
740 | void TimestampColumnPrinter::reset(const ColumnVectorBatch& batch) { |
741 | ColumnPrinter::reset(batch); |
742 | const TimestampVectorBatch& ts = |
743 | dynamic_cast<const TimestampVectorBatch&>(batch); |
744 | seconds = ts.data.data(); |
745 | nanoseconds = ts.nanoseconds.data(); |
746 | } |
747 | } |
748 | |