Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Format ODBCDriver2 with NULL support #2834

Merged
merged 6 commits into from
Aug 10, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions dbms/src/Formats/FormatFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -153,6 +154,7 @@ FormatFactory::FormatFactory()
registerOutputFormatJSONCompact(*this);
registerOutputFormatXML(*this);
registerOutputFormatODBCDriver(*this);
registerOutputFormatODBCDriver2(*this);
registerOutputFormatNull(*this);
}

Expand Down
95 changes: 95 additions & 0 deletions dbms/src/Formats/ODBCDriver2BlockOutputStream.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#include <Core/Block.h>
#include <Formats/FormatFactory.h>
#include <Formats/ODBCDriver2BlockOutputStream.h>
#include <IO/WriteBuffer.h>
#include <IO/WriteHelpers.h>


#include <Core/iostream_debug_helpers.h>


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()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cannot understand the motivation behind this format.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expandable header without breaking format - we can send any column flags, for example length for display_size or something else

{
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<ODBCDriver2BlockOutputStream>(buf, sample, format_settings);
});
}

}
44 changes: 44 additions & 0 deletions dbms/src/Formats/ODBCDriver2BlockOutputStream.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#pragma once

#include <string>
#include <Core/Block.h>
#include <DataStreams/IBlockOutputStream.h>
#include <Formats/FormatSettings.h>


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;
};

}