Skip to content

Commit e4d516a

Browse files
committed
Parameter bind
1 parent efd7311 commit e4d516a

File tree

14 files changed

+431
-159
lines changed

14 files changed

+431
-159
lines changed

odbc/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Добавляем исходники
22
add_library(ydb-odbc SHARED
3+
src/utils/convert.cpp
34
src/odbc_driver.cpp
45
src/connection.cpp
56
src/statement.cpp

odbc/examples/basic/main.cpp

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22
#include <sqlext.h>
33

44
#include <iostream>
5-
#include <cstring>
6-
#include <cstdlib>
7-
#include <cstdint>
85

96
void PrintOdbcError(SQLSMALLINT handleType, SQLHANDLE handle) {
107
SQLCHAR sqlState[6] = {0};
@@ -65,16 +62,16 @@ int main() {
6562

6663
std::cout << "6. Executing query" << std::endl;
6764
SQLCHAR query[] = R"(
68-
DECLARE $p1 AS Int64;
69-
SELECT $p1 + 1, 'test1' as String;
70-
SELECT $p1 + 2, 'test2' as String;
71-
SELECT $p1 + 3, 'test3' as String;
72-
SELECT $p1 + 4, 'test4' as String;
73-
SELECT $p1 + 5, 'test5' as String;
74-
SELECT $p1 + 6, 'test6' as String;
75-
SELECT $p1 + 7, 'test7' as String;
76-
SELECT $p1 + 8, 'test8' as String;
77-
SELECT $p1 + 9, 'test9' as String;
65+
DECLARE $p1 AS Int64?;
66+
SELECT $p1 + 1, 'test1';
67+
SELECT $p1 + 2, 'test2';
68+
SELECT $p1 + 3, 'test3';
69+
SELECT $p1 + 4, 'test4';
70+
SELECT $p1 + 5, 'test5';
71+
SELECT $p1 + 6, 'test6';
72+
SELECT $p1 + 7, 'test7';
73+
SELECT $p1 + 8, 'test8';
74+
SELECT $p1 + 9, 'test9';
7875
)";
7976

8077
int64_t paramValue = 42;

odbc/odbcinst.ini

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
[YDB]
22
Description=YDB ODBC Driver
3-
Driver=/usr/local/lib/libydb-odbc.so
4-
Setup=/usr/local/lib/libydb-odbc.so
5-
Threading=2
6-
FileUsage=1
7-
UsageCount=1
3+
Driver=/home/brgayazov/ydbwork/ydb-cpp-sdk/build/odbc/libydb-odbc.so
4+
Setup=/home/brgayazov/ydbwork/ydb-cpp-sdk/build/odbc/libydb-odbc.so

odbc/src/connection.cpp

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
#include "connection.h"
22
#include "statement.h"
3+
34
#include <cstring>
45
#include <string>
56
#include <map>
7+
68
#include <sql.h>
79
#include <sqlext.h>
810

@@ -12,7 +14,6 @@ namespace NYdb {
1214
namespace NOdbc {
1315

1416
SQLRETURN TConnection::DriverConnect(const std::string& connectionString) {
15-
// Парсим параметры
1617
std::map<std::string, std::string> params;
1718
size_t pos = 0;
1819
while (pos < connectionString.size()) {
@@ -50,7 +51,7 @@ SQLRETURN TConnection::DriverConnect(const std::string& connectionString) {
5051
SQLRETURN TConnection::Connect(const std::string& serverName,
5152
const std::string& userName,
5253
const std::string& auth) {
53-
// Получаем параметры из секции DSN через Driver Manager API
54+
5455
char endpoint[256] = {0};
5556
char database[256] = {0};
5657

@@ -82,13 +83,24 @@ SQLRETURN TConnection::Disconnect() {
8283

8384
SQLRETURN TConnection::GetDiagRec(SQLSMALLINT recNumber, SQLCHAR* sqlState, SQLINTEGER* nativeError,
8485
SQLCHAR* messageText, SQLSMALLINT bufferLength, SQLSMALLINT* textLength) {
85-
if (recNumber < 1 || recNumber > (SQLSMALLINT)Errors_.size()) return SQL_NO_DATA;
86+
if (recNumber < 1 || recNumber > (SQLSMALLINT)Errors_.size()) {
87+
return SQL_NO_DATA;
88+
}
89+
8690
const auto& err = Errors_[recNumber-1];
87-
if (sqlState) strncpy((char*)sqlState, err.SqlState.c_str(), 6);
88-
if (nativeError) *nativeError = err.NativeError;
91+
if (sqlState) {
92+
strncpy((char*)sqlState, err.SqlState.c_str(), 6);
93+
}
94+
95+
if (nativeError) {
96+
*nativeError = err.NativeError;
97+
}
98+
8999
if (messageText && bufferLength > 0) {
90100
strncpy((char*)messageText, err.Message.c_str(), bufferLength);
91-
if (textLength) *textLength = (SQLSMALLINT)std::min((int)err.Message.size(), (int)bufferLength);
101+
if (textLength) {
102+
*textLength = (SQLSMALLINT)std::min((int)err.Message.size(), (int)bufferLength);
103+
}
92104
}
93105
return SQL_SUCCESS;
94106
}
@@ -111,7 +123,7 @@ void TConnection::ClearErrors() {
111123
}
112124

113125
std::pair<std::string, std::string> TConnection::ParseConnectionString(const std::string& connectionString) {
114-
// Заглушка
126+
// TODO: Implement
115127
return {"", ""};
116128
}
117129

odbc/src/connection.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
#pragma once
22

3+
#include "environment.h"
4+
5+
#include <ydb-cpp-sdk/client/driver/driver.h>
6+
#include <ydb-cpp-sdk/client/query/client.h>
7+
38
#include <sql.h>
49
#include <sqlext.h>
10+
511
#include <memory>
612
#include <vector>
713
#include <string>
814

9-
#include <ydb-cpp-sdk/client/driver/driver.h>
10-
#include <ydb-cpp-sdk/client/query/client.h>
11-
12-
#include "environment.h"
13-
1415
namespace NYdb {
1516
namespace NOdbc {
1617

odbc/src/environment.cpp

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,31 @@ SQLRETURN TEnvironment::SetAttribute(SQLINTEGER attribute, SQLPOINTER value, SQL
1313
return SQL_SUCCESS;
1414
}
1515

16-
SQLRETURN TEnvironment::GetDiagRec(SQLSMALLINT recNumber, SQLCHAR* sqlState, SQLINTEGER* nativeError, SQLCHAR* messageText, SQLSMALLINT bufferLength, SQLSMALLINT* textLength) {
17-
// Заглушка
18-
if (recNumber < 1 || recNumber > (SQLSMALLINT)Errors_.size()) return SQL_NO_DATA;
16+
SQLRETURN TEnvironment::GetDiagRec(SQLSMALLINT recNumber,
17+
SQLCHAR* sqlState,
18+
SQLINTEGER* nativeError,
19+
SQLCHAR* messageText,
20+
SQLSMALLINT bufferLength,
21+
SQLSMALLINT* textLength) {
22+
23+
if (recNumber < 1 || recNumber > (SQLSMALLINT)Errors_.size()) {
24+
return SQL_NO_DATA;
25+
}
26+
1927
const auto& err = Errors_[recNumber-1];
20-
if (sqlState) strncpy((char*)sqlState, err.SqlState.c_str(), 6);
21-
if (nativeError) *nativeError = err.NativeError;
28+
if (sqlState) {
29+
strncpy((char*)sqlState, err.SqlState.c_str(), 6);
30+
}
31+
32+
if (nativeError) {
33+
*nativeError = err.NativeError;
34+
}
35+
2236
if (messageText && bufferLength > 0) {
2337
strncpy((char*)messageText, err.Message.c_str(), bufferLength);
24-
if (textLength) *textLength = (SQLSMALLINT)std::min((int)err.Message.size(), (int)bufferLength);
38+
if (textLength) {
39+
*textLength = (SQLSMALLINT)std::min((int)err.Message.size(), (int)bufferLength);
40+
}
2541
}
2642
return SQL_SUCCESS;
2743
}
@@ -35,4 +51,4 @@ void TEnvironment::ClearErrors() {
3551
}
3652

3753
} // namespace NOdbc
38-
} // namespace NYdb
54+
} // namespace NYdb

odbc/src/environment.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,4 @@ class TEnvironment {
3737
};
3838

3939
} // namespace NOdbc
40-
} // namespace NYdb
40+
} // namespace NYdb

odbc/src/statement.cpp

Lines changed: 29 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#include "statement.h"
22

3-
#include <cstring>
43
#include <ydb-cpp-sdk/client/params/params.h>
54
#include <ydb-cpp-sdk/client/value/value.h>
65

@@ -22,7 +21,6 @@ SQLRETURN TStatement::ExecDirect(const std::string& statementText) {
2221
if (!Errors_.empty()) {
2322
return SQL_ERROR;
2423
}
25-
// --- конец сборки параметров ---
2624

2725
auto sessionResult = client->GetSession().ExtractValueSync();
2826
if (!sessionResult.IsSuccess()) {
@@ -50,7 +48,6 @@ SQLRETURN TStatement::Fetch() {
5048
while (true) {
5149
if (ResultSetParser_) {
5250
if (ResultSetParser_->TryNextRow()) {
53-
// Автоматически заполняем связанные буферы
5451
for (const auto& col : BoundColumns_) {
5552
GetData(col.ColumnNumber, col.TargetType, col.TargetValue, col.BufferLength, col.StrLenOrInd);
5653
}
@@ -95,22 +92,38 @@ SQLRETURN TStatement::GetData(SQLUSMALLINT columnNumber, SQLSMALLINT targetType,
9592

9693
SQLRETURN TStatement::GetDiagRec(SQLSMALLINT recNumber, SQLCHAR* sqlState, SQLINTEGER* nativeError,
9794
SQLCHAR* messageText, SQLSMALLINT bufferLength, SQLSMALLINT* textLength) {
98-
if (recNumber < 1 || recNumber > (SQLSMALLINT)Errors_.size()) return SQL_NO_DATA;
95+
96+
if (recNumber < 1 || recNumber > (SQLSMALLINT)Errors_.size()) {
97+
return SQL_NO_DATA;
98+
}
99+
99100
const auto& err = Errors_[recNumber-1];
100-
if (sqlState) strncpy((char*)sqlState, err.SqlState.c_str(), 6);
101-
if (nativeError) *nativeError = err.NativeError;
101+
if (sqlState) {
102+
strncpy((char*)sqlState, err.SqlState.c_str(), 6);
103+
}
104+
105+
if (nativeError) {
106+
*nativeError = err.NativeError;
107+
}
108+
102109
if (messageText && bufferLength > 0) {
103110
strncpy((char*)messageText, err.Message.c_str(), bufferLength);
104-
if (textLength) *textLength = (SQLSMALLINT)std::min((int)err.Message.size(), (int)bufferLength);
111+
if (textLength) {
112+
*textLength = (SQLSMALLINT)std::min((int)err.Message.size(), (int)bufferLength);
113+
}
105114
}
106115
return SQL_SUCCESS;
107116
}
108117

109-
SQLRETURN TStatement::BindCol(SQLUSMALLINT columnNumber, SQLSMALLINT targetType, SQLPOINTER targetValue, SQLLEN bufferLength, SQLLEN* strLenOrInd) {
110-
// Удаляем старую связь для этой колонки, если есть
118+
SQLRETURN TStatement::BindCol(SQLUSMALLINT columnNumber,
119+
SQLSMALLINT targetType,
120+
SQLPOINTER targetValue,
121+
SQLLEN bufferLength,
122+
SQLLEN* strLenOrInd) {
123+
111124
BoundColumns_.erase(std::remove_if(BoundColumns_.begin(), BoundColumns_.end(),
112125
[columnNumber](const TBoundColumn& col) { return col.ColumnNumber == columnNumber; }), BoundColumns_.end());
113-
// Если targetValue == nullptr, просто удаляем связь
126+
114127
if (!targetValue) {
115128
return SQL_SUCCESS;
116129
}
@@ -127,14 +140,15 @@ SQLRETURN TStatement::BindParameter(SQLUSMALLINT paramNumber,
127140
SQLPOINTER parameterValuePtr,
128141
SQLLEN bufferLength,
129142
SQLLEN* strLenOrIndPtr) {
143+
130144
if (inputOutputType != SQL_PARAM_INPUT) {
131145
AddError("HYC00", 0, "Only input parameters are supported");
132146
return SQL_ERROR;
133147
}
134-
// Удаляем старую связь для этого параметра, если есть
148+
135149
BoundParams_.erase(std::remove_if(BoundParams_.begin(), BoundParams_.end(),
136150
[paramNumber](const TBoundParam& p) { return p.ParamNumber == paramNumber; }), BoundParams_.end());
137-
// Если parameterValuePtr == nullptr, просто удаляем связь
151+
138152
if (!parameterValuePtr) {
139153
return SQL_SUCCESS;
140154
}
@@ -162,7 +176,6 @@ SQLRETURN TStatement::ConvertYdbValue(NYdb::TValueParser& valueParser,
162176
SQLLEN bufferLength,
163177
SQLLEN* strLenOrInd) {
164178

165-
// 1. Проверка на NULL
166179
if (valueParser.IsNull()) {
167180
if (strLenOrInd) *strLenOrInd = SQL_NULL_DATA;
168181
return SQL_SUCCESS;
@@ -249,7 +262,6 @@ SQLRETURN TStatement::ConvertYdbValue(NYdb::TValueParser& valueParser,
249262
if (strLenOrInd) *strLenOrInd = sizeof(char);
250263
return SQL_SUCCESS;
251264
}
252-
// Добавьте обработку дат/времени, бинарных данных и других типов по необходимости
253265
default:
254266
return SQL_ERROR;
255267
}
@@ -259,84 +271,12 @@ NYdb::TParams TStatement::BuildParams() {
259271
Errors_.clear();
260272
NYdb::TParamsBuilder paramsBuilder;
261273
for (const auto& param : BoundParams_) {
262-
std::string paramName = "$p" + std::to_string(param.ParamNumber); // ODBC нумерует с 1
263-
auto& builder = paramsBuilder.AddParam(paramName);
264-
// Обработка NULL
265-
if (param.StrLenOrIndPtr && *param.StrLenOrIndPtr == SQL_NULL_DATA) {
266-
builder.EmptyOptional();
267-
builder.Build();
268-
continue;
269-
}
270-
271-
switch (param.ValueType) {
272-
case SQL_C_SLONG: {
273-
auto value = *static_cast<SQLINTEGER*>(param.ParameterValuePtr);
274-
switch (param.ParameterType) {
275-
case SQL_INTEGER:
276-
builder.Int32(static_cast<int32_t>(value));
277-
break;
278-
case SQL_BIGINT:
279-
builder.Int64(static_cast<int64_t>(value));
280-
break;
281-
case SQL_DOUBLE:
282-
builder.Double(static_cast<double>(value));
283-
break;
284-
case SQL_FLOAT:
285-
builder.Float(static_cast<float>(value));
286-
break;
287-
case SQL_VARCHAR:
288-
case SQL_CHAR:
289-
case SQL_LONGVARCHAR:
290-
builder.Utf8(std::to_string(value));
291-
break;
292-
case SQL_BIT:
293-
builder.Uint8(static_cast<uint8_t>(value));
294-
break;
295-
default:
296-
AddError("07006", 0, "Unsupported SQL type");
297-
return paramsBuilder.Build();
298-
}
299-
break;
300-
}
301-
case SQL_C_SBIGINT: {
302-
auto v = *static_cast<SQLBIGINT*>(param.ParameterValuePtr);
303-
builder.Int32(static_cast<int32_t>(v));
304-
break;
305-
}
306-
default: {
307-
AddError("07006", 0, "Unsupported C type");
308-
return paramsBuilder.Build();
309-
}
310-
}
311-
312-
switch (param.ParameterType) {
313-
case SQL_INTEGER:
314-
case SQL_BIGINT:
315-
break;
316-
case SQL_DOUBLE:
317-
builder.Double(*reinterpret_cast<double*>(param.ParameterValuePtr));
318-
break;
319-
case SQL_FLOAT:
320-
builder.Double(*reinterpret_cast<double*>(param.ParameterValuePtr));
321-
break;
322-
case SQL_VARCHAR:
323-
case SQL_CHAR:
324-
case SQL_LONGVARCHAR:
325-
builder.Utf8(*reinterpret_cast<std::string*>(param.ParameterValuePtr));
326-
break;
327-
case SQL_BIT:
328-
builder.Bool(*reinterpret_cast<bool*>(param.ParameterValuePtr));
329-
break;
330-
default:
331-
AddError("07006", 0, "Unsupported SQL type");
332-
return paramsBuilder.Build();
333-
}
334-
335-
builder.Build();
274+
std::string paramName = "$p" + std::to_string(param.ParamNumber);
275+
ConvertValue(param, paramsBuilder.AddParam(paramName));
336276
}
337277

338278
return paramsBuilder.Build();
339279
}
340280

341281
} // namespace NOdbc
342-
} // namespace NYdb
282+
} // namespace NYdb

0 commit comments

Comments
 (0)