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
34namespace 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