Skip to content

Commit 1f06eb8

Browse files
committed
support nullable columns
1 parent 1c1a054 commit 1f06eb8

File tree

13 files changed

+253
-6
lines changed

13 files changed

+253
-6
lines changed

driver/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ add_library(clickhouse-odbc SHARED
99
odbc.cpp
1010
result_set.cpp
1111
statement.cpp
12+
type_parser.cpp
1213
)
1314

1415
set_target_properties(clickhouse-odbc

driver/result_set.cpp

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "log.h"
22
#include "result_set.h"
33
#include "statement.h"
4+
#include "type_parser.h"
45

56
#include <Poco/Types.h>
67

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

53+
static void assignTypeInfo(const TypeAst & ast, ColumnInfo * info)
54+
{
55+
if (ast.meta == TypeAst::Terminal)
56+
{
57+
info->type_without_parameters = ast.name;
58+
}
59+
else if (ast.meta == TypeAst::Nullable)
60+
{
61+
info->is_nullable = true;
62+
assignTypeInfo(ast.elements.front(), info);
63+
}
64+
else
65+
{
66+
throw std::runtime_error("compound types doesn't supported: " + info->type);
67+
}
68+
}
5269

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

73-
columns_info[i].type_without_parameters = columns_info[i].type;
74-
auto pos = columns_info[i].type_without_parameters.find('(');
75-
if (std::string::npos != pos)
76-
columns_info[i].type_without_parameters.resize(pos);
90+
{
91+
TypeAst ast;
92+
if (TypeParser(columns_info[i].type).parse(&ast))
93+
{
94+
assignTypeInfo(ast, &columns_info[i]);
95+
}
96+
else
97+
{
98+
throw std::runtime_error("can't pase name of type: " + columns_info[i].type);
99+
}
100+
}
77101
}
78102

79103
readNextBlock();

driver/result_set.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ struct ColumnInfo
5555
std::string type;
5656
std::string type_without_parameters;
5757
size_t display_size = 0;
58+
bool is_nullable = false;
5859
};
5960

6061

driver/type_parser.cpp

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
#include "type_parser.h"
2+
3+
#include <sstream>
4+
5+
template <typename T>
6+
static inline T fromString(const std::string& s)
7+
{
8+
std::istringstream iss(s);
9+
T result;
10+
iss >> result;
11+
return result;
12+
13+
}
14+
static TypeAst::Meta getTypeMeta(const std::string& name) {
15+
if (name == "Array") {
16+
return TypeAst::Array;
17+
}
18+
19+
if (name == "Null") {
20+
return TypeAst::Null;
21+
}
22+
23+
if (name == "Nullable") {
24+
return TypeAst::Nullable;
25+
}
26+
27+
if (name == "Tuple") {
28+
return TypeAst::Tuple;
29+
}
30+
31+
return TypeAst::Terminal;
32+
}
33+
34+
35+
TypeParser::TypeParser(const std::string& name)
36+
: cur_(name.data())
37+
, end_(name.data() + name.size())
38+
, type_(nullptr)
39+
{
40+
}
41+
42+
TypeParser::~TypeParser() = default;
43+
44+
bool TypeParser::parse(TypeAst* type) {
45+
type_ = type;
46+
open_elements_.push(type_);
47+
48+
do {
49+
const Token& token = nextToken();
50+
51+
switch (token.type) {
52+
case Token::Name:
53+
type_->meta = getTypeMeta(token.value);
54+
type_->name = token.value;
55+
break;
56+
case Token::Number:
57+
type_->meta = TypeAst::Number;
58+
type_->size = fromString<int>(token.value);
59+
break;
60+
case Token::LPar:
61+
type_->elements.emplace_back(TypeAst());
62+
open_elements_.push(type_);
63+
type_ = &type_->elements.back();
64+
break;
65+
case Token::RPar:
66+
type_ = open_elements_.top();
67+
open_elements_.pop();
68+
break;
69+
case Token::Comma:
70+
type_ = open_elements_.top();
71+
open_elements_.pop();
72+
type_->elements.emplace_back(TypeAst());
73+
open_elements_.push(type_);
74+
type_ = &type_->elements.back();
75+
break;
76+
case Token::EOS:
77+
return true;
78+
case Token::Invalid:
79+
return false;
80+
}
81+
} while (true);
82+
}
83+
84+
TypeParser::Token TypeParser::nextToken() {
85+
for (; cur_ < end_; ++cur_) {
86+
switch (*cur_) {
87+
case ' ':
88+
case '\n':
89+
case '\t':
90+
case '\0':
91+
continue;
92+
93+
case '(':
94+
return Token{Token::LPar, std::string(cur_++, 1)};
95+
case ')':
96+
return Token{Token::RPar, std::string(cur_++, 1)};
97+
case ',':
98+
return Token{Token::Comma, std::string(cur_++, 1)};
99+
100+
default: {
101+
const char* st = cur_;
102+
103+
if (isalpha(*cur_)) {
104+
for (; cur_ < end_; ++cur_) {
105+
if (!isalpha(*cur_) && !isdigit(*cur_)) {
106+
break;
107+
}
108+
}
109+
110+
return Token{Token::Name, std::string(st, cur_)};
111+
}
112+
113+
if (isdigit(*cur_)) {
114+
for (; cur_ < end_; ++cur_) {
115+
if (!isdigit(*cur_)) {
116+
break;
117+
}
118+
}
119+
120+
return Token{Token::Number, std::string(st, cur_)};
121+
}
122+
123+
return Token{Token::Invalid, std::string()};
124+
}
125+
}
126+
}
127+
128+
return Token{Token::EOS, std::string()};
129+
}

driver/type_parser.h

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#pragma once
2+
3+
#include <list>
4+
#include <stack>
5+
#include <string>
6+
7+
struct TypeAst {
8+
enum Meta {
9+
Array,
10+
Null,
11+
Nullable,
12+
Number,
13+
Terminal,
14+
Tuple,
15+
};
16+
17+
/// Type's category.
18+
Meta meta;
19+
/// Type's name.
20+
std::string name;
21+
/// Size of type's instance. For fixed-width types only.
22+
size_t size = 0;
23+
/// Subelements of the type.
24+
std::list<TypeAst> elements;
25+
};
26+
27+
28+
class TypeParser {
29+
30+
struct Token {
31+
enum Type {
32+
Invalid = 0,
33+
Name,
34+
Number,
35+
LPar,
36+
RPar,
37+
Comma,
38+
EOS,
39+
};
40+
41+
Type type;
42+
std::string value;
43+
};
44+
45+
public:
46+
explicit TypeParser(const std::string& name);
47+
~TypeParser();
48+
49+
bool parse(TypeAst* type);
50+
51+
private:
52+
Token nextToken();
53+
54+
private:
55+
const char* cur_;
56+
const char* end_;
57+
58+
TypeAst* type_;
59+
std::stack<TypeAst*> open_elements_;
60+
};

vs/driver32/driver32.vcxproj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@
165165
<ClInclude Include="..\..\driver\result_set.h" />
166166
<ClInclude Include="..\..\driver\statement.h" />
167167
<ClInclude Include="..\..\driver\string_ref.h" />
168+
<ClInclude Include="..\..\driver\type_parser.h" />
168169
<ClInclude Include="..\..\driver\utils.h" />
169170
<ClInclude Include="..\..\driver\win\resource.h" />
170171
</ItemGroup>
@@ -178,6 +179,7 @@
178179
<ClCompile Include="..\..\driver\config.cpp" />
179180
<ClCompile Include="..\..\driver\connection.cpp" />
180181
<ClCompile Include="..\..\driver\diagnostics.cpp" />
182+
<ClCompile Include="..\..\driver\type_parser.cpp" />
181183
<ClCompile Include="..\..\driver\win\dllmain.cpp" />
182184
<ClCompile Include="..\..\driver\win\setup.cpp" />
183185
</ItemGroup>
@@ -198,4 +200,4 @@
198200
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
199201
<ImportGroup Label="ExtensionTargets">
200202
</ImportGroup>
201-
</Project>
203+
</Project>

vs/driver32/driver32.vcxproj.filters

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@
5151
<ClInclude Include="..\..\driver\config.h">
5252
<Filter>Заголовочные файлы</Filter>
5353
</ClInclude>
54+
<ClInclude Include="..\..\driver\type_parser.h">
55+
<Filter>Заголовочные файлы</Filter>
56+
</ClInclude>
5457
</ItemGroup>
5558
<ItemGroup>
5659
<ClCompile Include="..\..\driver\attr.cpp">
@@ -86,6 +89,9 @@
8689
<ClCompile Include="..\..\driver\config.cpp">
8790
<Filter>Файлы исходного кода</Filter>
8891
</ClCompile>
92+
<ClCompile Include="..\..\driver\type_parser.cpp">
93+
<Filter>Файлы исходного кода</Filter>
94+
</ClCompile>
8995
</ItemGroup>
9096
<ItemGroup>
9197
<ResourceCompile Include="..\..\driver\win\resource.rc">
@@ -97,4 +103,4 @@
97103
<Filter>Файлы исходного кода</Filter>
98104
</None>
99105
</ItemGroup>
100-
</Project>
106+
</Project>

vs/driver32w/driver32w.vcxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@
157157
<ClInclude Include="..\..\driver\read_helpers.h" />
158158
<ClInclude Include="..\..\driver\statement.h" />
159159
<ClInclude Include="..\..\driver\string_ref.h" />
160+
<ClInclude Include="..\..\driver\type_parser.h" />
160161
<ClInclude Include="..\..\driver\utils.h" />
161162
<ClInclude Include="..\..\driver\win\resource.h" />
162163
</ItemGroup>
@@ -170,6 +171,7 @@
170171
<ClCompile Include="..\..\driver\odbc.cpp" />
171172
<ClCompile Include="..\..\driver\result_set.cpp" />
172173
<ClCompile Include="..\..\driver\statement.cpp" />
174+
<ClCompile Include="..\..\driver\type_parser.cpp" />
173175
<ClCompile Include="..\..\driver\win\dllmain.cpp" />
174176
<ClCompile Include="..\..\driver\win\setup.cpp" />
175177
</ItemGroup>

vs/driver32w/driver32w.vcxproj.filters

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@
4848
<ClInclude Include="..\..\driver\config.h">
4949
<Filter>Заголовочные файлы</Filter>
5050
</ClInclude>
51+
<ClInclude Include="..\..\driver\type_parser.h">
52+
<Filter>Заголовочные файлы</Filter>
53+
</ClInclude>
5154
</ItemGroup>
5255
<ItemGroup>
5356
<ClCompile Include="..\..\driver\attr.cpp">
@@ -83,6 +86,9 @@
8386
<ClCompile Include="..\..\driver\config.cpp">
8487
<Filter>Файлы исходного кода</Filter>
8588
</ClCompile>
89+
<ClCompile Include="..\..\driver\type_parser.cpp">
90+
<Filter>Файлы исходного кода</Filter>
91+
</ClCompile>
8692
</ItemGroup>
8793
<ItemGroup>
8894
<None Include="..\..\driver\win\exportw.def">

vs/driver64/driver64.vcxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@
160160
<ClInclude Include="..\..\driver\result_set.h" />
161161
<ClInclude Include="..\..\driver\statement.h" />
162162
<ClInclude Include="..\..\driver\string_ref.h" />
163+
<ClInclude Include="..\..\driver\type_parser.h" />
163164
<ClInclude Include="..\..\driver\utils.h" />
164165
<ClInclude Include="..\..\driver\win\resource.h" />
165166
</ItemGroup>
@@ -173,6 +174,7 @@
173174
<ClCompile Include="..\..\driver\odbc.cpp" />
174175
<ClCompile Include="..\..\driver\result_set.cpp" />
175176
<ClCompile Include="..\..\driver\statement.cpp" />
177+
<ClCompile Include="..\..\driver\type_parser.cpp" />
176178
<ClCompile Include="..\..\driver\win\dllmain.cpp" />
177179
<ClCompile Include="..\..\driver\win\setup.cpp" />
178180
</ItemGroup>

0 commit comments

Comments
 (0)