From 973bdab77ff6a380347030fab2727edf7ca5fc98 Mon Sep 17 00:00:00 2001 From: proller Date: Fri, 10 Aug 2018 04:20:10 +0300 Subject: [PATCH] Format ODBCDriver2 with NULL support (#2834) * Format ODBCDriver2 with NULL support * Fix comment * Update ODBCDriver2BlockOutputStream.cpp * clean --- dbms/src/Formats/FormatFactory.cpp | 2 + .../Formats/ODBCDriver2BlockOutputStream.cpp | 95 +++++++++++++++++++ .../Formats/ODBCDriver2BlockOutputStream.h | 44 +++++++++ 3 files changed, 141 insertions(+) create mode 100644 dbms/src/Formats/ODBCDriver2BlockOutputStream.cpp create mode 100644 dbms/src/Formats/ODBCDriver2BlockOutputStream.h diff --git a/dbms/src/Formats/FormatFactory.cpp b/dbms/src/Formats/FormatFactory.cpp index a1910492afd..068454c8681 100644 --- a/dbms/src/Formats/FormatFactory.cpp +++ b/dbms/src/Formats/FormatFactory.cpp @@ -120,6 +120,7 @@ void registerOutputFormatJSON(FormatFactory & factory); void registerOutputFormatJSONCompact(FormatFactory & factory); void registerOutputFormatXML(FormatFactory & factory); void registerOutputFormatODBCDriver(FormatFactory & factory); +void registerOutputFormatODBCDriver2(FormatFactory & factory); void registerOutputFormatNull(FormatFactory & factory); /// Input only formats. @@ -153,6 +154,7 @@ FormatFactory::FormatFactory() registerOutputFormatJSONCompact(*this); registerOutputFormatXML(*this); registerOutputFormatODBCDriver(*this); + registerOutputFormatODBCDriver2(*this); registerOutputFormatNull(*this); } diff --git a/dbms/src/Formats/ODBCDriver2BlockOutputStream.cpp b/dbms/src/Formats/ODBCDriver2BlockOutputStream.cpp new file mode 100644 index 00000000000..85af97903ae --- /dev/null +++ b/dbms/src/Formats/ODBCDriver2BlockOutputStream.cpp @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#include + + +#include + + +namespace DB +{ +ODBCDriver2BlockOutputStream::ODBCDriver2BlockOutputStream( + WriteBuffer & out_, const Block & header_, const FormatSettings & format_settings) + : out(out_), header(header_), format_settings(format_settings) +{ +} + +void ODBCDriver2BlockOutputStream::flush() +{ + out.next(); +} + +void writeODBCString(WriteBuffer & out, const std::string & str) +{ + writeIntBinary(Int32(str.size()), out); + out.write(str.data(), str.size()); +} + +void ODBCDriver2BlockOutputStream::write(const Block & block) +{ + const size_t rows = block.rows(); + const size_t columns = block.columns(); + String text_value; + + for (size_t i = 0; i < rows; ++i) + { + for (size_t j = 0; j < columns; ++j) + { + text_value.resize(0); + const ColumnWithTypeAndName & col = block.getByPosition(j); + + if (col.column->isNullAt(i)) + { + writeIntBinary(Int32(-1), out); + } + else + { + { + WriteBufferFromString text_out(text_value); + col.type->serializeText(*col.column, i, text_out, format_settings); + } + writeODBCString(out, text_value); + } + } + } +} + +void ODBCDriver2BlockOutputStream::writePrefix() +{ + const size_t columns = header.columns(); + + /// Number of header rows. + writeIntBinary(Int32(2), out); + + /// Names of columns. + /// Number of columns + 1 for first name column. + writeIntBinary(Int32(columns + 1), out); + writeODBCString(out, "name"); + for (size_t i = 0; i < columns; ++i) + { + const ColumnWithTypeAndName & col = header.getByPosition(i); + writeODBCString(out, col.name); + } + + /// Types of columns. + writeIntBinary(Int32(columns + 1), out); + writeODBCString(out, "type"); + for (size_t i = 0; i < columns; ++i) + { + const ColumnWithTypeAndName & col = header.getByPosition(i); + writeODBCString(out, col.type->getName()); + } +} + + +void registerOutputFormatODBCDriver2(FormatFactory & factory) +{ + factory.registerOutputFormat( + "ODBCDriver2", [](WriteBuffer & buf, const Block & sample, const Context &, const FormatSettings & format_settings) { + return std::make_shared(buf, sample, format_settings); + }); +} + +} diff --git a/dbms/src/Formats/ODBCDriver2BlockOutputStream.h b/dbms/src/Formats/ODBCDriver2BlockOutputStream.h new file mode 100644 index 00000000000..7e295b52d60 --- /dev/null +++ b/dbms/src/Formats/ODBCDriver2BlockOutputStream.h @@ -0,0 +1,44 @@ +#pragma once + +#include +#include +#include +#include + + +namespace DB +{ +class WriteBuffer; + + +/** A data format designed to simplify the implementation of the ODBC driver. + * ODBC driver is designed to be build for different platforms without dependencies from the main code, + * so the format is made that way so that it can be as easy as possible to parse it. + * A header is displayed with the required information. + * The data is then output in the order of the rows. Each value is displayed as follows: length in Int32 format (-1 for NULL), then data in text form. + */ +class ODBCDriver2BlockOutputStream : public IBlockOutputStream +{ +public: + ODBCDriver2BlockOutputStream(WriteBuffer & out_, const Block & header_, const FormatSettings & format_settings); + + Block getHeader() const override + { + return header; + } + void write(const Block & block) override; + void writePrefix() override; + + void flush() override; + std::string getContentType() const override + { + return "application/octet-stream"; + } + +private: + WriteBuffer & out; + const Block header; + const FormatSettings format_settings; +}; + +}