diff --git a/src/Processors/Formats/IOutputFormat.cpp b/src/Processors/Formats/IOutputFormat.cpp index f7fc6170cad3ba7f5a6f50471a0c5676490a37bb..76920c0fa533554752d1299efe5943702a5c9cfc 100644 --- a/src/Processors/Formats/IOutputFormat.cpp +++ b/src/Processors/Formats/IOutputFormat.cpp @@ -46,6 +46,12 @@ IOutputFormat::Status IOutputFormat::prepare() void IOutputFormat::work() { + if (!prefix_written) + { + doWritePrefix(); + prefix_written = true; + } + if (finished && !finalized) { if (rows_before_limit_counter && rows_before_limit_counter->hasAppliedLimit()) diff --git a/src/Processors/Formats/IOutputFormat.h b/src/Processors/Formats/IOutputFormat.h index bab746c1772f655ed231ce5587ab48ecf4158f62..67c307df2aa801d8eadd70e6337ea76b02cdad3b 100644 --- a/src/Processors/Formats/IOutputFormat.h +++ b/src/Processors/Formats/IOutputFormat.h @@ -87,6 +87,8 @@ private: /// Counters for consumed chunks. Are used for QueryLog. size_t result_rows = 0; size_t result_bytes = 0; + + bool prefix_written = false; }; } diff --git a/src/Processors/Formats/Impl/TabSeparatedRowOutputFormat.cpp b/src/Processors/Formats/Impl/TabSeparatedRowOutputFormat.cpp index 1c493cd1ab42121586c40adfc059ecdf214c91cd..95377c13b55a577481c3da36f8f1760861ae3221 100644 --- a/src/Processors/Formats/Impl/TabSeparatedRowOutputFormat.cpp +++ b/src/Processors/Formats/Impl/TabSeparatedRowOutputFormat.cpp @@ -18,7 +18,7 @@ TabSeparatedRowOutputFormat::TabSeparatedRowOutputFormat( } -void TabSeparatedRowOutputFormat::writePrefix() +void TabSeparatedRowOutputFormat::doWritePrefix() { const auto & header = getPort(PortKind::Main).getHeader(); size_t columns = header.columns(); diff --git a/src/Processors/Formats/Impl/TabSeparatedRowOutputFormat.h b/src/Processors/Formats/Impl/TabSeparatedRowOutputFormat.h index 3d3f82e7833d41d6ddf0b9d3cdbbc23953069c04..137ffde4b185160fd714a76e495fe6645105c965 100644 --- a/src/Processors/Formats/Impl/TabSeparatedRowOutputFormat.h +++ b/src/Processors/Formats/Impl/TabSeparatedRowOutputFormat.h @@ -31,10 +31,11 @@ public: void writeField(const IColumn & column, const IDataType & type, size_t row_num) override; void writeFieldDelimiter() override; void writeRowEndDelimiter() override; - void writePrefix() override; void writeBeforeTotals() override; void writeBeforeExtremes() override; + void doWritePrefix() override; + /// https://www.iana.org/assignments/media-types/text/tab-separated-values String getContentType() const override { return "text/tab-separated-values; charset=UTF-8"; } diff --git a/src/Processors/Sources/SinkToOutputStream.cpp b/src/Processors/Sources/SinkToOutputStream.cpp index 29619dff463f52070988fd85f9e72fda357be1c4..9727b637d8bb7bc85a04f8fae0a6f1950a63c88b 100644 --- a/src/Processors/Sources/SinkToOutputStream.cpp +++ b/src/Processors/Sources/SinkToOutputStream.cpp @@ -8,15 +8,11 @@ SinkToOutputStream::SinkToOutputStream(BlockOutputStreamPtr stream_) : ISink(stream_->getHeader()) , stream(std::move(stream_)) { + stream->writePrefix(); } void SinkToOutputStream::consume(Chunk chunk) { - if (!initialized) - stream->writePrefix(); - - initialized = true; - stream->write(getPort().getHeader().cloneWithColumns(chunk.detachColumns())); } diff --git a/src/Processors/Sources/SinkToOutputStream.h b/src/Processors/Sources/SinkToOutputStream.h index 037cee0085d7e6753a47cb06ad7f0031dfb04a89..5362608551f5e2df7e87abdfb9e107487c29c2e7 100644 --- a/src/Processors/Sources/SinkToOutputStream.h +++ b/src/Processors/Sources/SinkToOutputStream.h @@ -22,7 +22,6 @@ protected: private: BlockOutputStreamPtr stream; - bool initialized = false; }; } diff --git a/tests/queries/0_stateless/01375_output_format_tsv_csv_with_names.reference b/tests/queries/0_stateless/01375_output_format_tsv_csv_with_names.reference new file mode 100644 index 0000000000000000000000000000000000000000..6f1974ccd73df9a354724974ab76c636a1a57c72 --- /dev/null +++ b/tests/queries/0_stateless/01375_output_format_tsv_csv_with_names.reference @@ -0,0 +1,13 @@ +TSVWithNames +number +0 +1 +TSVWithNamesAndTypes +number +UInt64 +0 +1 +CSVWithNames +"number" +0 +1 diff --git a/tests/queries/0_stateless/01375_output_format_tsv_csv_with_names.sh b/tests/queries/0_stateless/01375_output_format_tsv_csv_with_names.sh new file mode 100755 index 0000000000000000000000000000000000000000..de4486a88a5cdb52acf2346bcbcf66c16b633ea1 --- /dev/null +++ b/tests/queries/0_stateless/01375_output_format_tsv_csv_with_names.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +. "$CURDIR"/../shell_config.sh + +opts=( + --input-format CSV + -q 'SELECT number FROM numbers(2)' +) + +echo 'TSVWithNames' +${CLICKHOUSE_LOCAL} "${opts[@]}" --format TSVWithNames + +echo 'TSVWithNamesAndTypes' +${CLICKHOUSE_LOCAL} "${opts[@]}" --format TSVWithNamesAndTypes + +echo 'CSVWithNames' +${CLICKHOUSE_LOCAL} "${opts[@]}" --format CSVWithNames diff --git a/tests/queries/0_stateless/01375_storage_file_tsv_csv_with_names_write_prefix.reference b/tests/queries/0_stateless/01375_storage_file_tsv_csv_with_names_write_prefix.reference new file mode 100644 index 0000000000000000000000000000000000000000..4f2a79b99059a6497dc5f86601497396db696ea2 --- /dev/null +++ b/tests/queries/0_stateless/01375_storage_file_tsv_csv_with_names_write_prefix.reference @@ -0,0 +1,17 @@ +zero rows +TSVWithNames +TSVWithNamesAndTypes +CSVWithNames +multi clickhouse-local one file +TSVWithNames +0 +0 +0 +TSVWithNamesAndTypes +0 +0 +0 +CSVWithNames +0 +0 +0 diff --git a/tests/queries/0_stateless/01375_storage_file_tsv_csv_with_names_write_prefix.sh b/tests/queries/0_stateless/01375_storage_file_tsv_csv_with_names_write_prefix.sh new file mode 100755 index 0000000000000000000000000000000000000000..d396981f873c4c048cb00513e39360531eb644fa --- /dev/null +++ b/tests/queries/0_stateless/01375_storage_file_tsv_csv_with_names_write_prefix.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +. "$CURDIR"/../shell_config.sh + +# zero rows +echo 'zero rows' +for format in TSVWithNames TSVWithNamesAndTypes CSVWithNames; do + echo $format + ${CLICKHOUSE_LOCAL} --query=" + CREATE TABLE ${format}_01375 ENGINE File($format, '01375_$format.tsv') AS SELECT * FROM numbers(1) WHERE number < 0; + SELECT * FROM ${format}_01375; + DROP TABLE ${format}_01375; + " + rm 01375_$format.tsv +done + +# run multiple times to the same file +echo 'multi clickhouse-local one file' +for format in TSVWithNames TSVWithNamesAndTypes CSVWithNames; do + echo $format + for _ in {1..2}; do + ${CLICKHOUSE_LOCAL} --query=" + CREATE TABLE ${format}_01375 ENGINE File($format, '01375_$format.tsv') AS SELECT * FROM numbers(1); + SELECT * FROM ${format}_01375; + DROP TABLE ${format}_01375; + " + done + rm 01375_$format.tsv +done diff --git a/tests/queries/0_stateless/01375_storage_file_write_prefix.reference b/tests/queries/0_stateless/01375_storage_file_write_prefix_csv_with_names.reference similarity index 100% rename from tests/queries/0_stateless/01375_storage_file_write_prefix.reference rename to tests/queries/0_stateless/01375_storage_file_write_prefix_csv_with_names.reference diff --git a/tests/queries/0_stateless/01375_storage_file_write_prefix.sql b/tests/queries/0_stateless/01375_storage_file_write_prefix_csv_with_names.sql similarity index 100% rename from tests/queries/0_stateless/01375_storage_file_write_prefix.sql rename to tests/queries/0_stateless/01375_storage_file_write_prefix_csv_with_names.sql diff --git a/tests/queries/0_stateless/01375_storage_file_write_prefix_tsv_with_names.reference b/tests/queries/0_stateless/01375_storage_file_write_prefix_tsv_with_names.reference new file mode 100644 index 0000000000000000000000000000000000000000..ed9a18b934635e597f0e5df74087c6ff3c7cc705 --- /dev/null +++ b/tests/queries/0_stateless/01375_storage_file_write_prefix_tsv_with_names.reference @@ -0,0 +1,30 @@ +0 0 +1 1 +2 2 +3 3 +4 4 +5 5 +6 6 +7 7 +8 8 +9 9 +0 0 +1 1 +2 2 +3 3 +4 4 +5 5 +6 6 +7 7 +8 8 +9 9 +0 0 +1 1 +2 2 +3 3 +4 4 +5 5 +6 6 +7 7 +8 8 +9 9 diff --git a/tests/queries/0_stateless/01375_storage_file_write_prefix_tsv_with_names.sql b/tests/queries/0_stateless/01375_storage_file_write_prefix_tsv_with_names.sql new file mode 100644 index 0000000000000000000000000000000000000000..55a97eb6e9570f15a5379af3bc20cd717ea0dc30 --- /dev/null +++ b/tests/queries/0_stateless/01375_storage_file_write_prefix_tsv_with_names.sql @@ -0,0 +1,14 @@ +DROP TABLE IF EXISTS tmp_01375; +DROP TABLE IF EXISTS table_tsv_01375; + +CREATE TABLE tmp_01375 (n UInt32, s String) ENGINE = Memory; +CREATE TABLE table_tsv_01375 AS tmp_01375 ENGINE = File(TSVWithNames); + +INSERT INTO table_tsv_01375 SELECT number as n, toString(n) as s FROM numbers(10); +INSERT INTO table_tsv_01375 SELECT number as n, toString(n) as s FROM numbers(10); +INSERT INTO table_tsv_01375 SELECT number as n, toString(n) as s FROM numbers(10); + +SELECT * FROM table_tsv_01375; + +DROP TABLE IF EXISTS tmp_01375; +DROP TABLE IF EXISTS table_tsv_01375;