forked from ClickHouse/ClickHouse
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfetchSQLiteTableStructure.cpp
108 lines (84 loc) · 2.99 KB
/
fetchSQLiteTableStructure.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include <Databases/SQLite/fetchSQLiteTableStructure.h>
#if USE_SQLITE
#include <Common/quoteString.h>
#include <DataTypes/DataTypeArray.h>
#include <DataTypes/DataTypeDate.h>
#include <DataTypes/DataTypeDateTime.h>
#include <DataTypes/DataTypeFactory.h>
#include <DataTypes/DataTypeNullable.h>
#include <DataTypes/DataTypeString.h>
#include <DataTypes/DataTypesDecimal.h>
#include <DataTypes/DataTypesNumber.h>
#include <Poco/String.h>
#include <string_view>
using namespace std::literals;
namespace DB
{
namespace ErrorCodes
{
extern const int SQLITE_ENGINE_ERROR;
}
static DataTypePtr convertSQLiteDataType(String type)
{
DataTypePtr res;
type = Poco::toLower(type);
if (type == "tinyint")
res = std::make_shared<DataTypeInt8>();
else if (type == "smallint")
res = std::make_shared<DataTypeInt16>();
else if ((type.starts_with("int") && type != "int8") || type == "mediumint")
res = std::make_shared<DataTypeInt32>();
else if (type == "bigint" || type == "int8")
res = std::make_shared<DataTypeInt64>();
else if (type == "float")
res = std::make_shared<DataTypeFloat32>();
else if (type.starts_with("double") || type == "real")
res = std::make_shared<DataTypeFloat64>();
else
res = std::make_shared<DataTypeString>(); // No decimal when fetching data through API
return res;
}
std::shared_ptr<NamesAndTypesList> fetchSQLiteTableStructure(sqlite3 * connection, const String & sqlite_table_name)
{
auto columns = NamesAndTypesList();
auto query = fmt::format("pragma table_info({});", quoteString(sqlite_table_name));
auto callback_get_data = [](void * res, int col_num, char ** data_by_col, char ** col_names) -> int
{
NameAndTypePair name_and_type;
bool is_nullable = false;
for (int i = 0; i < col_num; ++i)
{
if (col_names[i] == "name"sv)
{
name_and_type.name = data_by_col[i];
}
else if (col_names[i] == "type"sv)
{
name_and_type.type = convertSQLiteDataType(data_by_col[i]);
}
else if (col_names[i] == "notnull"sv)
{
is_nullable = (data_by_col[i][0] == '0');
}
}
if (is_nullable)
name_and_type.type = std::make_shared<DataTypeNullable>(name_and_type.type);
static_cast<NamesAndTypesList *>(res)->push_back(name_and_type);
return 0;
};
char * err_message = nullptr;
int status = sqlite3_exec(connection, query.c_str(), callback_get_data, &columns, &err_message);
if (status != SQLITE_OK)
{
String err_msg(err_message);
sqlite3_free(err_message);
throw Exception(ErrorCodes::SQLITE_ENGINE_ERROR,
"Failed to fetch SQLite data. Status: {}. Message: {}",
status, err_msg);
}
if (columns.empty())
return nullptr;
return std::make_shared<NamesAndTypesList>(columns);
}
}
#endif