Skip to content

Commit

Permalink
support nullable columns
Browse files Browse the repository at this point in the history
  • Loading branch information
artpaul committed May 17, 2017
1 parent 1c1a054 commit 1f06eb8
Show file tree
Hide file tree
Showing 13 changed files with 253 additions and 6 deletions.
1 change: 1 addition & 0 deletions driver/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ add_library(clickhouse-odbc SHARED
odbc.cpp
result_set.cpp
statement.cpp
type_parser.cpp
)

set_target_properties(clickhouse-odbc
Expand Down
32 changes: 28 additions & 4 deletions driver/result_set.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "log.h"
#include "result_set.h"
#include "statement.h"
#include "type_parser.h"

#include <Poco/Types.h>

Expand Down Expand Up @@ -49,6 +50,22 @@ void Field::normalizeDate(T& date) const
date.day = 1;
}

static void assignTypeInfo(const TypeAst & ast, ColumnInfo * info)
{
if (ast.meta == TypeAst::Terminal)
{
info->type_without_parameters = ast.name;
}
else if (ast.meta == TypeAst::Nullable)
{
info->is_nullable = true;
assignTypeInfo(ast.elements.front(), info);
}
else
{
throw std::runtime_error("compound types doesn't supported: " + info->type);
}
}

void ResultSet::init(Statement * statement_)
{
Expand All @@ -70,10 +87,17 @@ void ResultSet::init(Statement * statement_)
readString(columns_info[i].name, in());
readString(columns_info[i].type, in());

columns_info[i].type_without_parameters = columns_info[i].type;
auto pos = columns_info[i].type_without_parameters.find('(');
if (std::string::npos != pos)
columns_info[i].type_without_parameters.resize(pos);
{
TypeAst ast;
if (TypeParser(columns_info[i].type).parse(&ast))
{
assignTypeInfo(ast, &columns_info[i]);
}
else
{
throw std::runtime_error("can't pase name of type: " + columns_info[i].type);
}
}
}

readNextBlock();
Expand Down
1 change: 1 addition & 0 deletions driver/result_set.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ struct ColumnInfo
std::string type;
std::string type_without_parameters;
size_t display_size = 0;
bool is_nullable = false;
};


Expand Down
129 changes: 129 additions & 0 deletions driver/type_parser.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#include "type_parser.h"

#include <sstream>

template <typename T>
static inline T fromString(const std::string& s)
{
std::istringstream iss(s);
T result;
iss >> result;
return result;

}
static TypeAst::Meta getTypeMeta(const std::string& name) {
if (name == "Array") {
return TypeAst::Array;
}

if (name == "Null") {
return TypeAst::Null;
}

if (name == "Nullable") {
return TypeAst::Nullable;
}

if (name == "Tuple") {
return TypeAst::Tuple;
}

return TypeAst::Terminal;
}


TypeParser::TypeParser(const std::string& name)
: cur_(name.data())
, end_(name.data() + name.size())
, type_(nullptr)
{
}

TypeParser::~TypeParser() = default;

bool TypeParser::parse(TypeAst* type) {
type_ = type;
open_elements_.push(type_);

do {
const Token& token = nextToken();

switch (token.type) {
case Token::Name:
type_->meta = getTypeMeta(token.value);
type_->name = token.value;
break;
case Token::Number:
type_->meta = TypeAst::Number;
type_->size = fromString<int>(token.value);
break;
case Token::LPar:
type_->elements.emplace_back(TypeAst());
open_elements_.push(type_);
type_ = &type_->elements.back();
break;
case Token::RPar:
type_ = open_elements_.top();
open_elements_.pop();
break;
case Token::Comma:
type_ = open_elements_.top();
open_elements_.pop();
type_->elements.emplace_back(TypeAst());
open_elements_.push(type_);
type_ = &type_->elements.back();
break;
case Token::EOS:
return true;
case Token::Invalid:
return false;
}
} while (true);
}

TypeParser::Token TypeParser::nextToken() {
for (; cur_ < end_; ++cur_) {
switch (*cur_) {
case ' ':
case '\n':
case '\t':
case '\0':
continue;

case '(':
return Token{Token::LPar, std::string(cur_++, 1)};
case ')':
return Token{Token::RPar, std::string(cur_++, 1)};
case ',':
return Token{Token::Comma, std::string(cur_++, 1)};

default: {
const char* st = cur_;

if (isalpha(*cur_)) {
for (; cur_ < end_; ++cur_) {
if (!isalpha(*cur_) && !isdigit(*cur_)) {
break;
}
}

return Token{Token::Name, std::string(st, cur_)};
}

if (isdigit(*cur_)) {
for (; cur_ < end_; ++cur_) {
if (!isdigit(*cur_)) {
break;
}
}

return Token{Token::Number, std::string(st, cur_)};
}

return Token{Token::Invalid, std::string()};
}
}
}

return Token{Token::EOS, std::string()};
}
60 changes: 60 additions & 0 deletions driver/type_parser.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#pragma once

#include <list>
#include <stack>
#include <string>

struct TypeAst {
enum Meta {
Array,
Null,
Nullable,
Number,
Terminal,
Tuple,
};

/// Type's category.
Meta meta;
/// Type's name.
std::string name;
/// Size of type's instance. For fixed-width types only.
size_t size = 0;
/// Subelements of the type.
std::list<TypeAst> elements;
};


class TypeParser {

struct Token {
enum Type {
Invalid = 0,
Name,
Number,
LPar,
RPar,
Comma,
EOS,
};

Type type;
std::string value;
};

public:
explicit TypeParser(const std::string& name);
~TypeParser();

bool parse(TypeAst* type);

private:
Token nextToken();

private:
const char* cur_;
const char* end_;

TypeAst* type_;
std::stack<TypeAst*> open_elements_;
};
4 changes: 3 additions & 1 deletion vs/driver32/driver32.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@
<ClInclude Include="..\..\driver\result_set.h" />
<ClInclude Include="..\..\driver\statement.h" />
<ClInclude Include="..\..\driver\string_ref.h" />
<ClInclude Include="..\..\driver\type_parser.h" />
<ClInclude Include="..\..\driver\utils.h" />
<ClInclude Include="..\..\driver\win\resource.h" />
</ItemGroup>
Expand All @@ -178,6 +179,7 @@
<ClCompile Include="..\..\driver\config.cpp" />
<ClCompile Include="..\..\driver\connection.cpp" />
<ClCompile Include="..\..\driver\diagnostics.cpp" />
<ClCompile Include="..\..\driver\type_parser.cpp" />
<ClCompile Include="..\..\driver\win\dllmain.cpp" />
<ClCompile Include="..\..\driver\win\setup.cpp" />
</ItemGroup>
Expand All @@ -198,4 +200,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>
8 changes: 7 additions & 1 deletion vs/driver32/driver32.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@
<ClInclude Include="..\..\driver\config.h">
<Filter>Заголовочные файлы</Filter>
</ClInclude>
<ClInclude Include="..\..\driver\type_parser.h">
<Filter>Заголовочные файлы</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\driver\attr.cpp">
Expand Down Expand Up @@ -86,6 +89,9 @@
<ClCompile Include="..\..\driver\config.cpp">
<Filter>Файлы исходного кода</Filter>
</ClCompile>
<ClCompile Include="..\..\driver\type_parser.cpp">
<Filter>Файлы исходного кода</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\driver\win\resource.rc">
Expand All @@ -97,4 +103,4 @@
<Filter>Файлы исходного кода</Filter>
</None>
</ItemGroup>
</Project>
</Project>
2 changes: 2 additions & 0 deletions vs/driver32w/driver32w.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@
<ClInclude Include="..\..\driver\read_helpers.h" />
<ClInclude Include="..\..\driver\statement.h" />
<ClInclude Include="..\..\driver\string_ref.h" />
<ClInclude Include="..\..\driver\type_parser.h" />
<ClInclude Include="..\..\driver\utils.h" />
<ClInclude Include="..\..\driver\win\resource.h" />
</ItemGroup>
Expand All @@ -170,6 +171,7 @@
<ClCompile Include="..\..\driver\odbc.cpp" />
<ClCompile Include="..\..\driver\result_set.cpp" />
<ClCompile Include="..\..\driver\statement.cpp" />
<ClCompile Include="..\..\driver\type_parser.cpp" />
<ClCompile Include="..\..\driver\win\dllmain.cpp" />
<ClCompile Include="..\..\driver\win\setup.cpp" />
</ItemGroup>
Expand Down
6 changes: 6 additions & 0 deletions vs/driver32w/driver32w.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@
<ClInclude Include="..\..\driver\config.h">
<Filter>Заголовочные файлы</Filter>
</ClInclude>
<ClInclude Include="..\..\driver\type_parser.h">
<Filter>Заголовочные файлы</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\driver\attr.cpp">
Expand Down Expand Up @@ -83,6 +86,9 @@
<ClCompile Include="..\..\driver\config.cpp">
<Filter>Файлы исходного кода</Filter>
</ClCompile>
<ClCompile Include="..\..\driver\type_parser.cpp">
<Filter>Файлы исходного кода</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\..\driver\win\exportw.def">
Expand Down
2 changes: 2 additions & 0 deletions vs/driver64/driver64.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@
<ClInclude Include="..\..\driver\result_set.h" />
<ClInclude Include="..\..\driver\statement.h" />
<ClInclude Include="..\..\driver\string_ref.h" />
<ClInclude Include="..\..\driver\type_parser.h" />
<ClInclude Include="..\..\driver\utils.h" />
<ClInclude Include="..\..\driver\win\resource.h" />
</ItemGroup>
Expand All @@ -173,6 +174,7 @@
<ClCompile Include="..\..\driver\odbc.cpp" />
<ClCompile Include="..\..\driver\result_set.cpp" />
<ClCompile Include="..\..\driver\statement.cpp" />
<ClCompile Include="..\..\driver\type_parser.cpp" />
<ClCompile Include="..\..\driver\win\dllmain.cpp" />
<ClCompile Include="..\..\driver\win\setup.cpp" />
</ItemGroup>
Expand Down
6 changes: 6 additions & 0 deletions vs/driver64/driver64.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@
<ClInclude Include="..\..\driver\config.h">
<Filter>Заголовочные файлы</Filter>
</ClInclude>
<ClInclude Include="..\..\driver\type_parser.h">
<Filter>Заголовочные файлы</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\driver\attr.cpp">
Expand Down Expand Up @@ -86,6 +89,9 @@
<ClCompile Include="..\..\driver\config.cpp">
<Filter>Файлы исходного кода</Filter>
</ClCompile>
<ClCompile Include="..\..\driver\type_parser.cpp">
<Filter>Файлы исходного кода</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\driver\win\resource.rc">
Expand Down
2 changes: 2 additions & 0 deletions vs/driver64w/driver64w.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@
<ClInclude Include="..\..\driver\result_set.h" />
<ClInclude Include="..\..\driver\statement.h" />
<ClInclude Include="..\..\driver\string_ref.h" />
<ClInclude Include="..\..\driver\type_parser.h" />
<ClInclude Include="..\..\driver\utils.h" />
<ClInclude Include="..\..\driver\win\resource.h" />
</ItemGroup>
Expand All @@ -172,6 +173,7 @@
<ClCompile Include="..\..\driver\odbc.cpp" />
<ClCompile Include="..\..\driver\result_set.cpp" />
<ClCompile Include="..\..\driver\statement.cpp" />
<ClCompile Include="..\..\driver\type_parser.cpp" />
<ClCompile Include="..\..\driver\win\dllmain.cpp" />
<ClCompile Include="..\..\driver\win\setup.cpp" />
</ItemGroup>
Expand Down
Loading

0 comments on commit 1f06eb8

Please sign in to comment.