Skip to content

Commit c775f21

Browse files
committed
step
1 parent 50b29ba commit c775f21

File tree

7 files changed

+167
-58
lines changed

7 files changed

+167
-58
lines changed

cmake/testing.cmake

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,9 @@ if (YDB_SDK_ODBC)
102102
LINK_LIBRARIES
103103
${ODBC_TEST_LINK_LIBRARIES}
104104
ODBC::ODBC
105-
LABELS ${ODBC_TEST_LABELS}
105+
LABELS
106+
integration
107+
${ODBC_TEST_LABELS}
106108
)
107109

108110
target_compile_definitions(${ODBC_TEST_NAME}

odbc/README.md

Lines changed: 28 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,105 +1,80 @@
11
# YDB ODBC Driver
22

3-
ODBC драйвер для YDB.
3+
ODBC driver for YDB.
44

5-
## Требования
5+
## Requirements
66

7-
- CMake 3.10 или выше
8-
- Компилятор C/C++ с поддержкой C11 и C++20
7+
- CMake 3.10 or higher
8+
- C/C++ compiler with C11 and C++20 support
99
- YDB C++ SDK
10-
- unixODBC (для Linux/macOS)
10+
- unixODBC (for Linux/macOS)
1111

12-
## Сборка
12+
## Build
1313

1414
```bash
15-
mkdir build && cd build
16-
cmake ..
17-
make
15+
cmake -DYDB_SDK_ODBC=1 --preset release-clang
16+
cmake --build --preset default
1817
```
1918

20-
## Установка
19+
## Configuration
2120

22-
```bash
23-
sudo make install
24-
```
25-
26-
Это установит:
27-
- Библиотеку драйвера в `/usr/local/lib/`
28-
- Конфигурацию драйвера в `/etc/odbcinst.d/`
29-
- Конфигурацию источников данных в `/etc/odbc.ini`
30-
31-
## Настройка
32-
33-
1. Убедитесь, что драйвер зарегистрирован:
21+
1. Make sure the driver is registered:
3422
```bash
3523
odbcinst -q -d
3624
```
3725

38-
2. Проверьте доступные источники данных:
26+
2. Check available data sources:
3927
```bash
4028
odbcinst -q -s
4129
```
4230

43-
3. Отредактируйте `/etc/odbc.ini` для настройки подключения:
31+
3. Edit `/etc/odbc.ini` to configure the connection:
4432
```ini
4533
[YDB]
4634
Driver=YDB
4735
Description=YDB Database Connection
48-
Server=grpc://your-server:2136
49-
Database=your-database
50-
AuthMode=none # или token для аутентификации по токену
36+
Server=your-server:port
37+
Database=/path/to/database
5138
```
5239

53-
## Использование
40+
## Usage
5441

55-
Пример подключения через isql:
42+
Example of connecting via isql:
5643
```bash
5744
isql -v YDB
5845
```
5946

60-
Пример использования в C:
47+
Example usage in C:
6148
```c
6249
SQLHENV env;
6350
SQLHDBC dbc;
6451
SQLHSTMT stmt;
6552

66-
// Инициализация окружения
53+
// Initialize environment
6754
SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
6855
SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
6956

70-
// Подключение
57+
// Connect
7158
SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
7259
SQLConnect(dbc, (SQLCHAR*)"YDB", SQL_NTS,
7360
(SQLCHAR*)"", SQL_NTS,
7461
(SQLCHAR*)"", SQL_NTS);
7562

76-
// Выполнение запроса
63+
// Execute query
7764
SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
7865
SQLExecDirect(stmt, (SQLCHAR*)"SELECT * FROM mytable", SQL_NTS);
7966

80-
// Очистка
67+
// Cleanup
8168
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
8269
SQLDisconnect(dbc);
8370
SQLFreeHandle(SQL_HANDLE_DBC, dbc);
8471
SQLFreeHandle(SQL_HANDLE_ENV, env);
8572
```
8673
87-
## Поддерживаемые функции
88-
89-
- SQLAllocHandle
90-
- SQLConnect
91-
- SQLDisconnect
92-
- SQLExecDirect
93-
- SQLFetch
94-
- SQLGetData
95-
- SQLPrepare
96-
- SQLExecute
97-
- SQLCloseCursor
98-
- SQLFreeHandle
99-
- SQLGetInfo
100-
- SQLGetDescField
101-
- SQLSetDescField
102-
103-
## Лицензия
104-
105-
Apache License 2.0
74+
## Parameters
75+
76+
Use names $p1, $p2, ... for parameter names
77+
78+
## License
79+
80+
Apache License 2.0

odbc/src/connection.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ SQLRETURN TConnection::Connect(const std::string& serverName,
5757
char endpoint[256] = {0};
5858
char database[256] = {0};
5959

60-
SQLGetPrivateProfileString(serverName.c_str(), "Endpoint", "", endpoint, sizeof(endpoint), nullptr);
61-
SQLGetPrivateProfileString(serverName.c_str(), "Database", "", database, sizeof(database), nullptr);
60+
//SQLGetPrivateProfileString(serverName.c_str(), "Endpoint", "", endpoint, sizeof(endpoint), nullptr);
61+
//SQLGetPrivateProfileString(serverName.c_str(), "Database", "", database, sizeof(database), nullptr);
6262

6363
Endpoint_ = endpoint;
6464
Database_ = database;

odbc/src/utils/convert.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,10 +312,15 @@ SQLRETURN ConvertColumn(TValueParser& parser, SQLSMALLINT targetType, SQLPOINTER
312312

313313
switch (targetType) {
314314
case SQL_C_SLONG:
315+
case SQL_C_LONG:
315316
{
316317
int32_t v = 0;
317318
switch (ydbType) {
318-
case EPrimitiveType::Int32: v = parser.GetInt32(); break;
319+
case EPrimitiveType::Int16: v = static_cast<int32_t>(parser.GetInt16()); break;
320+
case EPrimitiveType::Uint16: v = static_cast<int32_t>(parser.GetUint16()); break;
321+
case EPrimitiveType::Int8: v = static_cast<int32_t>(parser.GetInt8()); break;
322+
case EPrimitiveType::Uint8: v = static_cast<int32_t>(parser.GetUint8()); break;
323+
case EPrimitiveType::Int32: v = static_cast<int32_t>(parser.GetInt32()); break;
319324
case EPrimitiveType::Uint32: v = static_cast<int32_t>(parser.GetUint32()); break;
320325
case EPrimitiveType::Int64: v = static_cast<int32_t>(parser.GetInt64()); break;
321326
case EPrimitiveType::Uint64: v = static_cast<int32_t>(parser.GetUint64()); break;

odbc/tests/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
#add_subdirectory(integration)
1+
add_subdirectory(integration)
22
add_subdirectory(unit)

odbc/tests/integration/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
add_odbc_test(NAME odbc-basic_it
2+
SOURCES
3+
basic_it.cpp
4+
)

odbc/tests/integration/basic_it.cpp

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
#include <gtest/gtest.h>
2+
3+
#include <sql.h>
4+
#include <sqlext.h>
5+
6+
#include <string>
7+
8+
9+
#define CHECK_ODBC_OK(rc, handle, type) \
10+
ASSERT_TRUE((rc) == SQL_SUCCESS || (rc) == SQL_SUCCESS_WITH_INFO) << GetOdbcError(handle, type)
11+
12+
std::string GetOdbcError(SQLHANDLE handle, SQLSMALLINT type) {
13+
SQLCHAR sqlState[6], message[256];
14+
SQLINTEGER nativeError;
15+
SQLSMALLINT textLength;
16+
SQLRETURN rc = SQLGetDiagRec(type, handle, 1, sqlState, &nativeError, message, sizeof(message), &textLength);
17+
if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
18+
return std::string((char*)sqlState) + ": " + (char*)message;
19+
}
20+
return "Unknown ODBC error";
21+
}
22+
23+
const char* kConnStr = "Driver=" ODBC_DRIVER_PATH ";Endpoint=localhost:2136;Database=/local;";
24+
25+
TEST(OdbcBasic, SimpleQuery) {
26+
SQLHENV env;
27+
SQLHDBC dbc;
28+
SQLHSTMT stmt;
29+
ASSERT_EQ(SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env), SQL_SUCCESS);
30+
ASSERT_EQ(SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0), SQL_SUCCESS);
31+
ASSERT_EQ(SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc), SQL_SUCCESS);
32+
CHECK_ODBC_OK(SQLDriverConnect(dbc, nullptr, (SQLCHAR*)kConnStr, SQL_NTS, nullptr, 0, nullptr, SQL_DRIVER_COMPLETE), dbc, SQL_HANDLE_DBC);
33+
ASSERT_EQ(SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt), SQL_SUCCESS);
34+
35+
// Simple query
36+
CHECK_ODBC_OK(SQLExecDirect(stmt, (SQLCHAR*)"SELECT 1 AS one, 'abc' AS str", SQL_NTS), stmt, SQL_HANDLE_STMT);
37+
ASSERT_EQ(SQLFetch(stmt), SQL_SUCCESS);
38+
39+
SQLINTEGER ival = 0;
40+
char sval[16] = {0};
41+
SQLLEN ival_ind = 0, sval_ind = 0;
42+
ASSERT_EQ(SQLGetData(stmt, 1, SQL_C_LONG, &ival, 0, &ival_ind), SQL_SUCCESS);
43+
ASSERT_EQ(SQLGetData(stmt, 2, SQL_C_CHAR, sval, sizeof(sval), &sval_ind), SQL_SUCCESS);
44+
ASSERT_EQ(ival, 1);
45+
ASSERT_STREQ(sval, "abc");
46+
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
47+
SQLDisconnect(dbc);
48+
SQLFreeHandle(SQL_HANDLE_DBC, dbc);
49+
SQLFreeHandle(SQL_HANDLE_ENV, env);
50+
}
51+
52+
TEST(OdbcBasic, ParameterizedQuery) {
53+
SQLHENV env;
54+
SQLHDBC dbc;
55+
SQLHSTMT stmt;
56+
ASSERT_EQ(SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env), SQL_SUCCESS);
57+
ASSERT_EQ(SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0), SQL_SUCCESS);
58+
ASSERT_EQ(SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc), SQL_SUCCESS);
59+
CHECK_ODBC_OK(SQLDriverConnect(dbc, nullptr, (SQLCHAR*)kConnStr, SQL_NTS, nullptr, 0, nullptr, SQL_DRIVER_COMPLETE), dbc, SQL_HANDLE_DBC);
60+
ASSERT_EQ(SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt), SQL_SUCCESS);
61+
62+
SQLCHAR query[] = R"(
63+
DECLARE $p1 AS Int32?;
64+
SELECT $p1 + 10 AS res;
65+
)";
66+
67+
// Parameterized query
68+
CHECK_ODBC_OK(SQLPrepare(stmt, query, SQL_NTS), stmt, SQL_HANDLE_STMT);
69+
SQLINTEGER param = 5;
70+
CHECK_ODBC_OK(SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &param, 0, nullptr), stmt, SQL_HANDLE_STMT);
71+
CHECK_ODBC_OK(SQLExecute(stmt), stmt, SQL_HANDLE_STMT);
72+
73+
ASSERT_EQ(SQLFetch(stmt), SQL_SUCCESS);
74+
75+
SQLINTEGER res = 0;
76+
SQLLEN res_ind = 0;
77+
ASSERT_EQ(SQLGetData(stmt, 1, SQL_C_LONG, &res, 0, &res_ind), SQL_SUCCESS);
78+
ASSERT_EQ(res, 15);
79+
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
80+
SQLDisconnect(dbc);
81+
SQLFreeHandle(SQL_HANDLE_DBC, dbc);
82+
SQLFreeHandle(SQL_HANDLE_ENV, env);
83+
}
84+
85+
TEST(OdbcBasic, ColumnBinding) {
86+
SQLHENV env;
87+
SQLHDBC dbc;
88+
SQLHSTMT stmt;
89+
ASSERT_EQ(SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env), SQL_SUCCESS);
90+
ASSERT_EQ(SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0), SQL_SUCCESS);
91+
ASSERT_EQ(SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc), SQL_SUCCESS);
92+
CHECK_ODBC_OK(SQLDriverConnect(dbc, nullptr, (SQLCHAR*)kConnStr, SQL_NTS, nullptr, 0, nullptr, SQL_DRIVER_COMPLETE), dbc, SQL_HANDLE_DBC);
93+
ASSERT_EQ(SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt), SQL_SUCCESS);
94+
95+
SQLCHAR query_ddl[] = R"(
96+
DROP TABLE IF EXISTS test_bind;
97+
CREATE TABLE test_bind (id Int32, name Text, PRIMARY KEY (id));
98+
)";
99+
100+
SQLCHAR query[] = R"(
101+
UPSERT INTO test_bind (id, name) VALUES (1, 'foo'), (2, 'bar');
102+
SELECT id, name FROM test_bind ORDER BY id;
103+
)";
104+
105+
CHECK_ODBC_OK(SQLExecDirect(stmt, query_ddl, SQL_NTS), stmt, SQL_HANDLE_STMT);
106+
CHECK_ODBC_OK(SQLExecDirect(stmt, query, SQL_NTS), stmt, SQL_HANDLE_STMT);
107+
108+
SQLINTEGER id = 0;
109+
char name[16] = {0};
110+
SQLLEN id_ind = 0, name_ind = 0;
111+
ASSERT_EQ(SQLBindCol(stmt, 1, SQL_C_LONG, &id, 0, &id_ind), SQL_SUCCESS);
112+
ASSERT_EQ(SQLBindCol(stmt, 2, SQL_C_CHAR, name, sizeof(name), &name_ind), SQL_SUCCESS);
113+
ASSERT_EQ(SQLFetch(stmt), SQL_SUCCESS);
114+
ASSERT_EQ(id, 1);
115+
ASSERT_STREQ(name, "foo");
116+
ASSERT_EQ(SQLFetch(stmt), SQL_SUCCESS);
117+
ASSERT_EQ(id, 2);
118+
ASSERT_STREQ(name, "bar");
119+
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
120+
SQLDisconnect(dbc);
121+
SQLFreeHandle(SQL_HANDLE_DBC, dbc);
122+
SQLFreeHandle(SQL_HANDLE_ENV, env);
123+
}

0 commit comments

Comments
 (0)