1#pragma once
2
3#include <cstring>
4#include <cstdio>
5#include <limits>
6#include <algorithm>
7#include <iterator>
8
9#include <common/DateLUT.h>
10#include <common/LocalDate.h>
11#include <common/LocalDateTime.h>
12#include <common/find_symbols.h>
13#include <common/StringRef.h>
14
15#include <Core/DecimalFunctions.h>
16#include <Core/Types.h>
17#include <Core/UUID.h>
18
19#include <Common/Exception.h>
20#include <Common/StringUtils/StringUtils.h>
21#include <Common/UInt128.h>
22
23#include <IO/CompressionMethod.h>
24#include <IO/WriteBuffer.h>
25#include <IO/WriteIntText.h>
26#include <IO/VarInt.h>
27#include <IO/DoubleConverter.h>
28#include <IO/WriteBufferFromString.h>
29#include <IO/ZlibDeflatingWriteBuffer.h>
30
31#include <Formats/FormatSettings.h>
32
33namespace DB
34{
35
36namespace ErrorCodes
37{
38 extern const int CANNOT_PRINT_FLOAT_OR_DOUBLE_NUMBER;
39 extern const int ILLEGAL_TYPE_OF_ARGUMENT;
40}
41
42/// Helper functions for formatted and binary output.
43
44inline void writeChar(char x, WriteBuffer & buf)
45{
46 buf.nextIfAtEnd();
47 *buf.position() = x;
48 ++buf.position();
49}
50
51/// Write the same character n times.
52inline void writeChar(char c, size_t n, WriteBuffer & buf)
53{
54 while (n)
55 {
56 buf.nextIfAtEnd();
57 size_t count = std::min(n, buf.available());
58 memset(buf.position(), c, count);
59 n -= count;
60 buf.position() += count;
61 }
62}
63
64/// Write POD-type in native format. It's recommended to use only with packed (dense) data types.
65template <typename T>
66inline void writePODBinary(const T & x, WriteBuffer & buf)
67{
68 buf.write(reinterpret_cast<const char *>(&x), sizeof(x));
69}
70
71template <typename T>
72inline void writeIntBinary(const T & x, WriteBuffer & buf)
73{
74 writePODBinary(x, buf);
75}
76
77template <typename T>
78inline void writeFloatBinary(const T & x, WriteBuffer & buf)
79{
80 writePODBinary(x, buf);
81}
82
83
84inline void writeStringBinary(const std::string & s, WriteBuffer & buf)
85{
86 writeVarUInt(s.size(), buf);
87 buf.write(s.data(), s.size());
88}
89
90inline void writeStringBinary(const char * s, WriteBuffer & buf)
91{
92 writeVarUInt(strlen(s), buf);
93 buf.write(s, strlen(s));
94}
95
96inline void writeStringBinary(const StringRef & s, WriteBuffer & buf)
97{
98 writeVarUInt(s.size, buf);
99 buf.write(s.data, s.size);
100}
101
102
103template <typename T>
104void writeVectorBinary(const std::vector<T> & v, WriteBuffer & buf)
105{
106 writeVarUInt(v.size(), buf);
107
108 for (typename std::vector<T>::const_iterator it = v.begin(); it != v.end(); ++it)
109 writeBinary(*it, buf);
110}
111
112
113inline void writeBoolText(bool x, WriteBuffer & buf)
114{
115 writeChar(x ? '1' : '0', buf);
116}
117
118template <typename T>
119inline size_t writeFloatTextFastPath(T x, char * buffer, int len)
120{
121 using Converter = DoubleConverter<false>;
122 double_conversion::StringBuilder builder{buffer, len};
123
124 bool result = false;
125 if constexpr (std::is_same_v<T, double>)
126 result = Converter::instance().ToShortest(x, &builder);
127 else
128 result = Converter::instance().ToShortestSingle(x, &builder);
129
130 if (!result)
131 throw Exception("Cannot print floating point number", ErrorCodes::CANNOT_PRINT_FLOAT_OR_DOUBLE_NUMBER);
132 return builder.position();
133}
134
135template <typename T>
136inline void writeFloatText(T x, WriteBuffer & buf)
137{
138 static_assert(std::is_same_v<T, double> || std::is_same_v<T, float>, "Argument for writeFloatText must be float or double");
139
140 using Converter = DoubleConverter<false>;
141 if (likely(buf.available() >= Converter::MAX_REPRESENTATION_LENGTH))
142 {
143 buf.position() += writeFloatTextFastPath(x, buf.position(), Converter::MAX_REPRESENTATION_LENGTH);
144 return;
145 }
146
147 Converter::BufferType buffer;
148 double_conversion::StringBuilder builder{buffer, sizeof(buffer)};
149
150 bool result = false;
151 if constexpr (std::is_same_v<T, double>)
152 result = Converter::instance().ToShortest(x, &builder);
153 else
154 result = Converter::instance().ToShortestSingle(x, &builder);
155
156 if (!result)
157 throw Exception("Cannot print floating point number", ErrorCodes::CANNOT_PRINT_FLOAT_OR_DOUBLE_NUMBER);
158
159 buf.write(buffer, builder.position());
160}
161
162
163inline void writeString(const String & s, WriteBuffer & buf)
164{
165 buf.write(s.data(), s.size());
166}
167
168inline void writeString(const char * data, size_t size, WriteBuffer & buf)
169{
170 buf.write(data, size);
171}
172
173inline void writeString(const StringRef & ref, WriteBuffer & buf)
174{
175 writeString(ref.data, ref.size, buf);
176}
177
178
179/** Writes a C-string without creating a temporary object. If the string is a literal, then `strlen` is executed at the compilation stage.
180 * Use when the string is a literal.
181 */
182#define writeCString(s, buf) \
183 (buf).write((s), strlen(s))
184
185/** Writes a string for use in the JSON format:
186 * - the string is written in double quotes
187 * - slash character '/' is escaped for compatibility with JavaScript
188 * - bytes from the range 0x00-0x1F except `\b', '\f', '\n', '\r', '\t' are escaped as \u00XX
189 * - code points U+2028 and U+2029 (byte sequences in UTF-8: e2 80 a8, e2 80 a9) are escaped as \u2028 and \u2029
190 * - it is assumed that string is in UTF-8, the invalid UTF-8 is not processed
191 * - all other non-ASCII characters remain as is
192 */
193inline void writeJSONString(const char * begin, const char * end, WriteBuffer & buf, const FormatSettings & settings)
194{
195 writeChar('"', buf);
196 for (const char * it = begin; it != end; ++it)
197 {
198 switch (*it)
199 {
200 case '\b':
201 writeChar('\\', buf);
202 writeChar('b', buf);
203 break;
204 case '\f':
205 writeChar('\\', buf);
206 writeChar('f', buf);
207 break;
208 case '\n':
209 writeChar('\\', buf);
210 writeChar('n', buf);
211 break;
212 case '\r':
213 writeChar('\\', buf);
214 writeChar('r', buf);
215 break;
216 case '\t':
217 writeChar('\\', buf);
218 writeChar('t', buf);
219 break;
220 case '\\':
221 writeChar('\\', buf);
222 writeChar('\\', buf);
223 break;
224 case '/':
225 if (settings.json.escape_forward_slashes)
226 writeChar('\\', buf);
227 writeChar('/', buf);
228 break;
229 case '"':
230 writeChar('\\', buf);
231 writeChar('"', buf);
232 break;
233 default:
234 UInt8 c = *it;
235 if (c <= 0x1F)
236 {
237 /// Escaping of ASCII control characters.
238
239 UInt8 higher_half = c >> 4;
240 UInt8 lower_half = c & 0xF;
241
242 writeCString("\\u00", buf);
243 writeChar('0' + higher_half, buf);
244
245 if (lower_half <= 9)
246 writeChar('0' + lower_half, buf);
247 else
248 writeChar('A' + lower_half - 10, buf);
249 }
250 else if (end - it >= 3 && it[0] == '\xE2' && it[1] == '\x80' && (it[2] == '\xA8' || it[2] == '\xA9'))
251 {
252 /// This is for compatibility with JavaScript, because unescaped line separators are prohibited in string literals,
253 /// and these code points are alternative line separators.
254
255 if (it[2] == '\xA8')
256 writeCString("\\u2028", buf);
257 if (it[2] == '\xA9')
258 writeCString("\\u2029", buf);
259
260 /// Byte sequence is 3 bytes long. We have additional two bytes to skip.
261 it += 2;
262 }
263 else
264 writeChar(*it, buf);
265 }
266 }
267 writeChar('"', buf);
268}
269
270
271/** Will escape quote_character and a list of special characters('\b', '\f', '\n', '\r', '\t', '\0', '\\').
272 * - when escape_quote_with_quote is true, use backslash to escape list of special characters,
273 * and use quote_character to escape quote_character. such as: 'hello''world'
274 * - otherwise use backslash to escape list of special characters and quote_character
275 */
276template <char quote_character, bool escape_quote_with_quote = false>
277void writeAnyEscapedString(const char * begin, const char * end, WriteBuffer & buf)
278{
279 const char * pos = begin;
280 while (true)
281 {
282 /// On purpose we will escape more characters than minimally necessary.
283 const char * next_pos = find_first_symbols<'\b', '\f', '\n', '\r', '\t', '\0', '\\', quote_character>(pos, end);
284
285 if (next_pos == end)
286 {
287 buf.write(pos, next_pos - pos);
288 break;
289 }
290 else
291 {
292 buf.write(pos, next_pos - pos);
293 pos = next_pos;
294 switch (*pos)
295 {
296 case '\b':
297 writeChar('\\', buf);
298 writeChar('b', buf);
299 break;
300 case '\f':
301 writeChar('\\', buf);
302 writeChar('f', buf);
303 break;
304 case '\n':
305 writeChar('\\', buf);
306 writeChar('n', buf);
307 break;
308 case '\r':
309 writeChar('\\', buf);
310 writeChar('r', buf);
311 break;
312 case '\t':
313 writeChar('\\', buf);
314 writeChar('t', buf);
315 break;
316 case '\0':
317 writeChar('\\', buf);
318 writeChar('0', buf);
319 break;
320 case '\\':
321 writeChar('\\', buf);
322 writeChar('\\', buf);
323 break;
324 case quote_character:
325 {
326 if constexpr (escape_quote_with_quote)
327 writeChar(quote_character, buf);
328 else
329 writeChar('\\', buf);
330 writeChar(quote_character, buf);
331 break;
332 }
333 default:
334 writeChar(*pos, buf);
335 }
336 ++pos;
337 }
338 }
339}
340
341
342inline void writeJSONString(const String & s, WriteBuffer & buf, const FormatSettings & settings)
343{
344 writeJSONString(s.data(), s.data() + s.size(), buf, settings);
345}
346
347
348inline void writeJSONString(const StringRef & ref, WriteBuffer & buf, const FormatSettings & settings)
349{
350 writeJSONString(ref.data, ref.data + ref.size, buf, settings);
351}
352
353
354template <char c>
355void writeAnyEscapedString(const String & s, WriteBuffer & buf)
356{
357 writeAnyEscapedString<c>(s.data(), s.data() + s.size(), buf);
358}
359
360
361inline void writeEscapedString(const char * str, size_t size, WriteBuffer & buf)
362{
363 writeAnyEscapedString<'\''>(str, str + size, buf);
364}
365
366
367inline void writeEscapedString(const String & s, WriteBuffer & buf)
368{
369 writeEscapedString(s.data(), s.size(), buf);
370}
371
372
373inline void writeEscapedString(const StringRef & ref, WriteBuffer & buf)
374{
375 writeEscapedString(ref.data, ref.size, buf);
376}
377
378
379template <char quote_character>
380void writeAnyQuotedString(const char * begin, const char * end, WriteBuffer & buf)
381{
382 writeChar(quote_character, buf);
383 writeAnyEscapedString<quote_character>(begin, end, buf);
384 writeChar(quote_character, buf);
385}
386
387
388
389template <char quote_character>
390void writeAnyQuotedString(const String & s, WriteBuffer & buf)
391{
392 writeAnyQuotedString<quote_character>(s.data(), s.data() + s.size(), buf);
393}
394
395
396template <char quote_character>
397void writeAnyQuotedString(const StringRef & ref, WriteBuffer & buf)
398{
399 writeAnyQuotedString<quote_character>(ref.data, ref.data + ref.size, buf);
400}
401
402
403inline void writeQuotedString(const String & s, WriteBuffer & buf)
404{
405 writeAnyQuotedString<'\''>(s, buf);
406}
407
408
409inline void writeQuotedString(const StringRef & ref, WriteBuffer & buf)
410{
411 writeAnyQuotedString<'\''>(ref, buf);
412}
413
414inline void writeDoubleQuotedString(const StringRef & s, WriteBuffer & buf)
415{
416 writeAnyQuotedString<'"'>(s, buf);
417}
418
419/// Outputs a string in backquotes.
420inline void writeBackQuotedString(const StringRef & s, WriteBuffer & buf)
421{
422 writeAnyQuotedString<'`'>(s, buf);
423}
424
425/// Outputs a string in backquotes for MySQL.
426inline void writeBackQuotedStringMySQL(const StringRef & s, WriteBuffer & buf)
427{
428 writeChar('`', buf);
429 writeAnyEscapedString<'`', true>(s.data, s.data + s.size, buf);
430 writeChar('`', buf);
431}
432
433
434/// The same, but quotes apply only if there are characters that do not match the identifier without quotes.
435template <typename F>
436inline void writeProbablyQuotedStringImpl(const StringRef & s, WriteBuffer & buf, F && write_quoted_string)
437{
438 if (!s.size || !isValidIdentifierBegin(s.data[0]))
439 write_quoted_string(s, buf);
440 else
441 {
442 const char * pos = s.data + 1;
443 const char * end = s.data + s.size;
444 for (; pos < end; ++pos)
445 if (!isWordCharASCII(*pos))
446 break;
447 if (pos != end)
448 write_quoted_string(s, buf);
449 else
450 writeString(s, buf);
451 }
452}
453
454inline void writeProbablyBackQuotedString(const StringRef & s, WriteBuffer & buf)
455{
456 writeProbablyQuotedStringImpl(s, buf, [](const StringRef & s_, WriteBuffer & buf_) { return writeBackQuotedString(s_, buf_); });
457}
458
459inline void writeProbablyDoubleQuotedString(const StringRef & s, WriteBuffer & buf)
460{
461 writeProbablyQuotedStringImpl(s, buf, [](const StringRef & s_, WriteBuffer & buf_) { return writeDoubleQuotedString(s_, buf_); });
462}
463
464inline void writeProbablyBackQuotedStringMySQL(const StringRef & s, WriteBuffer & buf)
465{
466 writeProbablyQuotedStringImpl(s, buf, [](const StringRef & s_, WriteBuffer & buf_) { return writeBackQuotedStringMySQL(s_, buf_); });
467}
468
469
470/** Outputs the string in for the CSV format.
471 * Rules:
472 * - the string is outputted in quotation marks;
473 * - the quotation mark inside the string is outputted as two quotation marks in sequence.
474 */
475template <char quote = '"'>
476void writeCSVString(const char * begin, const char * end, WriteBuffer & buf)
477{
478 writeChar(quote, buf);
479
480 const char * pos = begin;
481 while (true)
482 {
483 const char * next_pos = find_first_symbols<quote>(pos, end);
484
485 if (next_pos == end)
486 {
487 buf.write(pos, end - pos);
488 break;
489 }
490 else /// Quotation.
491 {
492 ++next_pos;
493 buf.write(pos, next_pos - pos);
494 writeChar(quote, buf);
495 }
496
497 pos = next_pos;
498 }
499
500 writeChar(quote, buf);
501}
502
503template <char quote = '"'>
504void writeCSVString(const String & s, WriteBuffer & buf)
505{
506 writeCSVString<quote>(s.data(), s.data() + s.size(), buf);
507}
508
509template <char quote = '"'>
510void writeCSVString(const StringRef & s, WriteBuffer & buf)
511{
512 writeCSVString<quote>(s.data, s.data + s.size, buf);
513}
514
515
516/// Writing a string to a text node in XML (not into an attribute - otherwise you need more escaping).
517inline void writeXMLString(const char * begin, const char * end, WriteBuffer & buf)
518{
519 const char * pos = begin;
520 while (true)
521 {
522 /// NOTE Perhaps for some XML parsers, you need to escape the zero byte and some control characters.
523 const char * next_pos = find_first_symbols<'<', '&'>(pos, end);
524
525 if (next_pos == end)
526 {
527 buf.write(pos, end - pos);
528 break;
529 }
530 else if (*next_pos == '<')
531 {
532 buf.write(pos, next_pos - pos);
533 ++next_pos;
534 writeCString("&lt;", buf);
535 }
536 else if (*next_pos == '&')
537 {
538 buf.write(pos, next_pos - pos);
539 ++next_pos;
540 writeCString("&amp;", buf);
541 }
542
543 pos = next_pos;
544 }
545}
546
547inline void writeXMLString(const String & s, WriteBuffer & buf)
548{
549 writeXMLString(s.data(), s.data() + s.size(), buf);
550}
551
552inline void writeXMLString(const StringRef & s, WriteBuffer & buf)
553{
554 writeXMLString(s.data, s.data + s.size, buf);
555}
556
557template <typename IteratorSrc, typename IteratorDst>
558void formatHex(IteratorSrc src, IteratorDst dst, const size_t num_bytes);
559void formatUUID(const UInt8 * src16, UInt8 * dst36);
560void formatUUID(std::reverse_iterator<const UInt8 *> dst16, UInt8 * dst36);
561
562inline void writeUUIDText(const UUID & uuid, WriteBuffer & buf)
563{
564 char s[36];
565
566 formatUUID(std::reverse_iterator<const UInt8 *>(reinterpret_cast<const UInt8 *>(&uuid) + 16), reinterpret_cast<UInt8 *>(s));
567 buf.write(s, sizeof(s));
568}
569
570
571static const char digits100[201] =
572 "00010203040506070809"
573 "10111213141516171819"
574 "20212223242526272829"
575 "30313233343536373839"
576 "40414243444546474849"
577 "50515253545556575859"
578 "60616263646566676869"
579 "70717273747576777879"
580 "80818283848586878889"
581 "90919293949596979899";
582
583/// in YYYY-MM-DD format
584template <char delimiter = '-'>
585inline void writeDateText(const LocalDate & date, WriteBuffer & buf)
586{
587 if (buf.position() + 10 <= buf.buffer().end())
588 {
589 memcpy(buf.position(), &digits100[date.year() / 100 * 2], 2);
590 buf.position() += 2;
591 memcpy(buf.position(), &digits100[date.year() % 100 * 2], 2);
592 buf.position() += 2;
593 *buf.position() = delimiter;
594 ++buf.position();
595 memcpy(buf.position(), &digits100[date.month() * 2], 2);
596 buf.position() += 2;
597 *buf.position() = delimiter;
598 ++buf.position();
599 memcpy(buf.position(), &digits100[date.day() * 2], 2);
600 buf.position() += 2;
601 }
602 else
603 {
604 buf.write(&digits100[date.year() / 100 * 2], 2);
605 buf.write(&digits100[date.year() % 100 * 2], 2);
606 buf.write(delimiter);
607 buf.write(&digits100[date.month() * 2], 2);
608 buf.write(delimiter);
609 buf.write(&digits100[date.day() * 2], 2);
610 }
611}
612
613template <char delimiter = '-'>
614inline void writeDateText(DayNum date, WriteBuffer & buf)
615{
616 if (unlikely(!date))
617 {
618 static const char s[] = {'0', '0', '0', '0', delimiter, '0', '0', delimiter, '0', '0'};
619 buf.write(s, sizeof(s));
620 return;
621 }
622
623 writeDateText<delimiter>(LocalDate(date), buf);
624}
625
626
627/// In the format YYYY-MM-DD HH:MM:SS
628template <char date_delimeter = '-', char time_delimeter = ':', char between_date_time_delimiter = ' '>
629inline void writeDateTimeText(const LocalDateTime & datetime, WriteBuffer & buf)
630{
631 if (buf.position() + 19 <= buf.buffer().end())
632 {
633 memcpy(buf.position(), &digits100[datetime.year() / 100 * 2], 2);
634 buf.position() += 2;
635 memcpy(buf.position(), &digits100[datetime.year() % 100 * 2], 2);
636 buf.position() += 2;
637 *buf.position() = date_delimeter;
638 ++buf.position();
639 memcpy(buf.position(), &digits100[datetime.month() * 2], 2);
640 buf.position() += 2;
641 *buf.position() = date_delimeter;
642 ++buf.position();
643 memcpy(buf.position(), &digits100[datetime.day() * 2], 2);
644 buf.position() += 2;
645 *buf.position() = between_date_time_delimiter;
646 ++buf.position();
647 memcpy(buf.position(), &digits100[datetime.hour() * 2], 2);
648 buf.position() += 2;
649 *buf.position() = time_delimeter;
650 ++buf.position();
651 memcpy(buf.position(), &digits100[datetime.minute() * 2], 2);
652 buf.position() += 2;
653 *buf.position() = time_delimeter;
654 ++buf.position();
655 memcpy(buf.position(), &digits100[datetime.second() * 2], 2);
656 buf.position() += 2;
657 }
658 else
659 {
660 buf.write(&digits100[datetime.year() / 100 * 2], 2);
661 buf.write(&digits100[datetime.year() % 100 * 2], 2);
662 buf.write(date_delimeter);
663 buf.write(&digits100[datetime.month() * 2], 2);
664 buf.write(date_delimeter);
665 buf.write(&digits100[datetime.day() * 2], 2);
666 buf.write(between_date_time_delimiter);
667 buf.write(&digits100[datetime.hour() * 2], 2);
668 buf.write(time_delimeter);
669 buf.write(&digits100[datetime.minute() * 2], 2);
670 buf.write(time_delimeter);
671 buf.write(&digits100[datetime.second() * 2], 2);
672 }
673}
674
675/// In the format YYYY-MM-DD HH:MM:SS, according to the specified time zone.
676template <char date_delimeter = '-', char time_delimeter = ':', char between_date_time_delimiter = ' '>
677inline void writeDateTimeText(time_t datetime, WriteBuffer & buf, const DateLUTImpl & date_lut = DateLUT::instance())
678{
679 if (unlikely(!datetime))
680 {
681 static const char s[] =
682 {
683 '0', '0', '0', '0', date_delimeter, '0', '0', date_delimeter, '0', '0',
684 between_date_time_delimiter,
685 '0', '0', time_delimeter, '0', '0', time_delimeter, '0', '0'
686 };
687 buf.write(s, sizeof(s));
688 return;
689 }
690
691 const auto & values = date_lut.getValues(datetime);
692 writeDateTimeText<date_delimeter, time_delimeter, between_date_time_delimiter>(
693 LocalDateTime(values.year, values.month, values.day_of_month,
694 date_lut.toHour(datetime), date_lut.toMinute(datetime), date_lut.toSecond(datetime)), buf);
695}
696
697/// In the format YYYY-MM-DD HH:MM:SS.NNNNNNNNN, according to the specified time zone.
698template <char date_delimeter = '-', char time_delimeter = ':', char between_date_time_delimiter = ' ', char fractional_time_delimiter = '.'>
699inline void writeDateTimeText(DateTime64 datetime64, UInt32 scale, WriteBuffer & buf, const DateLUTImpl & date_lut = DateLUT::instance())
700{
701 static constexpr UInt32 MaxScale = DecimalUtils::maxPrecision<DateTime64>();
702 scale = scale > MaxScale ? MaxScale : scale;
703 if (unlikely(!datetime64))
704 {
705 static const char s[] =
706 {
707 '0', '0', '0', '0', date_delimeter, '0', '0', date_delimeter, '0', '0',
708 between_date_time_delimiter,
709 '0', '0', time_delimeter, '0', '0', time_delimeter, '0', '0',
710 fractional_time_delimiter,
711 // Exactly MaxScale zeroes
712 '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'
713 };
714 buf.write(s, sizeof(s) - (MaxScale - scale));
715 return;
716 }
717 auto c = DecimalUtils::split(datetime64, scale);
718 const auto & values = date_lut.getValues(c.whole);
719 writeDateTimeText<date_delimeter, time_delimeter, between_date_time_delimiter>(
720 LocalDateTime(values.year, values.month, values.day_of_month,
721 date_lut.toHour(c.whole), date_lut.toMinute(c.whole), date_lut.toSecond(c.whole)), buf);
722
723 if (scale > 0)
724 {
725 buf.write(fractional_time_delimiter);
726
727 char data[20] = {'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'};
728 static_assert(sizeof(data) >= MaxScale);
729
730 auto fractional = c.fractional;
731 for (Int32 pos = scale - 1; pos >= 0 && fractional; --pos, fractional /= DateTime64(10))
732 data[pos] += fractional % DateTime64(10);
733
734 writeString(&data[0], static_cast<size_t>(scale), buf);
735 }
736}
737
738/// In the RFC 1123 format: "Tue, 03 Dec 2019 00:11:50 GMT". You must provide GMT DateLUT.
739/// This is needed for HTTP requests.
740inline void writeDateTimeTextRFC1123(time_t datetime, WriteBuffer & buf, const DateLUTImpl & date_lut)
741{
742 const auto & values = date_lut.getValues(datetime);
743
744 static const char week_days[3 * 8 + 1] = "XXX" "Mon" "Tue" "Wed" "Thu" "Fri" "Sat" "Sun";
745 static const char months[3 * 13 + 1] = "XXX" "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec";
746
747 buf.write(&week_days[values.day_of_week * 3], 3);
748 buf.write(", ", 2);
749 buf.write(&digits100[values.day_of_month * 2], 2);
750 buf.write(' ');
751 buf.write(&months[values.month * 3], 3);
752 buf.write(' ');
753 buf.write(&digits100[values.year / 100 * 2], 2);
754 buf.write(&digits100[values.year % 100 * 2], 2);
755 buf.write(' ');
756 buf.write(&digits100[date_lut.toHour(datetime) * 2], 2);
757 buf.write(':');
758 buf.write(&digits100[date_lut.toMinute(datetime) * 2], 2);
759 buf.write(':');
760 buf.write(&digits100[date_lut.toSecond(datetime) * 2], 2);
761 buf.write(" GMT", 4);
762}
763
764
765/// Methods for output in binary format.
766template <typename T>
767inline std::enable_if_t<is_arithmetic_v<T>, void>
768writeBinary(const T & x, WriteBuffer & buf) { writePODBinary(x, buf); }
769
770inline void writeBinary(const String & x, WriteBuffer & buf) { writeStringBinary(x, buf); }
771inline void writeBinary(const StringRef & x, WriteBuffer & buf) { writeStringBinary(x, buf); }
772inline void writeBinary(const Int128 & x, WriteBuffer & buf) { writePODBinary(x, buf); }
773inline void writeBinary(const UInt128 & x, WriteBuffer & buf) { writePODBinary(x, buf); }
774inline void writeBinary(const UInt256 & x, WriteBuffer & buf) { writePODBinary(x, buf); }
775inline void writeBinary(const Decimal32 & x, WriteBuffer & buf) { writePODBinary(x, buf); }
776inline void writeBinary(const Decimal64 & x, WriteBuffer & buf) { writePODBinary(x, buf); }
777inline void writeBinary(const Decimal128 & x, WriteBuffer & buf) { writePODBinary(x, buf); }
778inline void writeBinary(const LocalDate & x, WriteBuffer & buf) { writePODBinary(x, buf); }
779inline void writeBinary(const LocalDateTime & x, WriteBuffer & buf) { writePODBinary(x, buf); }
780
781
782/// Methods for outputting the value in text form for a tab-separated format.
783template <typename T>
784inline std::enable_if_t<is_integral_v<T>, void>
785writeText(const T & x, WriteBuffer & buf) { writeIntText(x, buf); }
786
787template <typename T>
788inline std::enable_if_t<std::is_floating_point_v<T>, void>
789writeText(const T & x, WriteBuffer & buf) { writeFloatText(x, buf); }
790
791inline void writeText(const String & x, WriteBuffer & buf) { writeEscapedString(x, buf); }
792
793/// Implemented as template specialization (not function overload) to avoid preference over templates on arithmetic types above.
794template <> inline void writeText<bool>(const bool & x, WriteBuffer & buf) { writeBoolText(x, buf); }
795
796/// unlike the method for std::string
797/// assumes here that `x` is a null-terminated string.
798inline void writeText(const char * x, WriteBuffer & buf) { writeEscapedString(x, strlen(x), buf); }
799inline void writeText(const char * x, size_t size, WriteBuffer & buf) { writeEscapedString(x, size, buf); }
800
801inline void writeText(const LocalDate & x, WriteBuffer & buf) { writeDateText(x, buf); }
802inline void writeText(const LocalDateTime & x, WriteBuffer & buf) { writeDateTimeText(x, buf); }
803inline void writeText(const UUID & x, WriteBuffer & buf) { writeUUIDText(x, buf); }
804inline void writeText(const UInt128 & x, WriteBuffer & buf) { writeText(UUID(x), buf); }
805
806template <typename T>
807void writeText(Decimal<T> value, UInt32 scale, WriteBuffer & ostr)
808{
809 if (value < Decimal<T>(0))
810 {
811 value *= Decimal<T>(-1);
812 writeChar('-', ostr); /// avoid crop leading minus when whole part is zero
813 }
814
815 const T whole_part = DecimalUtils::getWholePart(value, scale);
816
817 writeIntText(whole_part, ostr);
818 if (scale)
819 {
820 writeChar('.', ostr);
821 String str_fractional(scale, '0');
822 for (Int32 pos = scale - 1; pos >= 0; --pos, value /= Decimal<T>(10))
823 str_fractional[pos] += value % Decimal<T>(10);
824 ostr.write(str_fractional.data(), scale);
825 }
826}
827
828/// String, date, datetime are in single quotes with C-style escaping. Numbers - without.
829template <typename T>
830inline std::enable_if_t<is_arithmetic_v<T>, void>
831writeQuoted(const T & x, WriteBuffer & buf) { writeText(x, buf); }
832
833inline void writeQuoted(const String & x, WriteBuffer & buf) { writeQuotedString(x, buf); }
834
835inline void writeQuoted(const LocalDate & x, WriteBuffer & buf)
836{
837 writeChar('\'', buf);
838 writeDateText(x, buf);
839 writeChar('\'', buf);
840}
841
842inline void writeQuoted(const LocalDateTime & x, WriteBuffer & buf)
843{
844 writeChar('\'', buf);
845 writeDateTimeText(x, buf);
846 writeChar('\'', buf);
847}
848
849inline void writeQuoted(const UUID & x, WriteBuffer & buf)
850{
851 writeChar('\'', buf);
852 writeText(x, buf);
853 writeChar('\'', buf);
854}
855
856/// String, date, datetime are in double quotes with C-style escaping. Numbers - without.
857template <typename T>
858inline std::enable_if_t<is_arithmetic_v<T>, void>
859writeDoubleQuoted(const T & x, WriteBuffer & buf) { writeText(x, buf); }
860
861inline void writeDoubleQuoted(const String & x, WriteBuffer & buf) { writeDoubleQuotedString(x, buf); }
862
863inline void writeDoubleQuoted(const LocalDate & x, WriteBuffer & buf)
864{
865 writeChar('"', buf);
866 writeDateText(x, buf);
867 writeChar('"', buf);
868}
869
870inline void writeDoubleQuoted(const LocalDateTime & x, WriteBuffer & buf)
871{
872 writeChar('"', buf);
873 writeDateTimeText(x, buf);
874 writeChar('"', buf);
875}
876
877inline void writeDoubleQuoted(const UUID & x, WriteBuffer & buf)
878{
879 writeChar('"', buf);
880 writeText(x, buf);
881 writeChar('"', buf);
882}
883
884
885/// String - in double quotes and with CSV-escaping; date, datetime - in double quotes. Numbers - without.
886template <typename T>
887inline std::enable_if_t<is_arithmetic_v<T>, void>
888writeCSV(const T & x, WriteBuffer & buf) { writeText(x, buf); }
889
890inline void writeCSV(const String & x, WriteBuffer & buf) { writeCSVString<>(x, buf); }
891inline void writeCSV(const LocalDate & x, WriteBuffer & buf) { writeDoubleQuoted(x, buf); }
892inline void writeCSV(const LocalDateTime & x, WriteBuffer & buf) { writeDoubleQuoted(x, buf); }
893inline void writeCSV(const UUID & x, WriteBuffer & buf) { writeDoubleQuoted(x, buf); }
894[[noreturn]] inline void writeCSV(const UInt128, WriteBuffer &)
895{
896 /** Because UInt128 isn't a natural type, without arithmetic operator and only use as an intermediary type -for UUID-
897 * it should never arrive here. But because we used the DataTypeNumber class we should have at least a definition of it.
898 */
899 throw Exception("UInt128 cannot be write as a text", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
900}
901
902template <typename T>
903void writeBinary(const std::vector<T> & x, WriteBuffer & buf)
904{
905 size_t size = x.size();
906 writeVarUInt(size, buf);
907 for (size_t i = 0; i < size; ++i)
908 writeBinary(x[i], buf);
909}
910
911template <typename T>
912void writeQuoted(const std::vector<T> & x, WriteBuffer & buf)
913{
914 writeChar('[', buf);
915 for (size_t i = 0, size = x.size(); i < size; ++i)
916 {
917 if (i != 0)
918 writeChar(',', buf);
919 writeQuoted(x[i], buf);
920 }
921 writeChar(']', buf);
922}
923
924template <typename T>
925void writeDoubleQuoted(const std::vector<T> & x, WriteBuffer & buf)
926{
927 writeChar('[', buf);
928 for (size_t i = 0, size = x.size(); i < size; ++i)
929 {
930 if (i != 0)
931 writeChar(',', buf);
932 writeDoubleQuoted(x[i], buf);
933 }
934 writeChar(']', buf);
935}
936
937template <typename T>
938void writeText(const std::vector<T> & x, WriteBuffer & buf)
939{
940 writeQuoted(x, buf);
941}
942
943
944
945/// Serialize exception (so that it can be transferred over the network)
946void writeException(const Exception & e, WriteBuffer & buf, bool with_stack_trace);
947
948
949/// An easy-to-use method for converting something to a string in text form.
950template <typename T>
951inline String toString(const T & x)
952{
953 WriteBufferFromOwnString buf;
954 writeText(x, buf);
955 return buf.str();
956}
957
958template <class TWriteBuffer, class... Types>
959std::unique_ptr<WriteBuffer> getWriteBuffer(const DB::CompressionMethod method, Types&&... args)
960{
961 if (method == DB::CompressionMethod::Gzip)
962 {
963 auto write_buf = std::make_unique<TWriteBuffer>(std::forward<Types>(args)...);
964 return std::make_unique<ZlibDeflatingWriteBuffer>(std::move(write_buf), method, 1 /* compression level */);
965 }
966 return std::make_unique<TWriteBuffer>(args...);
967}
968
969}
970