Как связать строку std :: string, хранящуюся в std :: any Vector с вызовом процедуры ODBC SQLC++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Как связать строку std :: string, хранящуюся в std :: any Vector с вызовом процедуры ODBC SQL

Сообщение Anonymous »

Я хочу создать общий класс C ++ C ++, который обрабатывает взаимодействие с базой данных SQL Server через ODBC. std :: wstring-s прилегают правильно, но std :: string-s даже не так, если логика одинакова. std :: wstring правильно достигает базы данных, но std :: string нет.

Код: Выделить всё

// allocate statement
// prepare statement
// bind return code

template
inline void StoredProc::bindInputParameter(const T& param)
{
lengths.push_back(0); // member of StoredProc class
SQLLEN* len = &lengths.back();
bound_parameters.push_back(param); // member of StoredProc class
auto& stored_param = std::any_cast(bound_parameters.back());
if constexpr (std::is_same_v) {
strings.push_back(param);
std::string& stored_param = strings.back();
errorCode = SQLBindParameter(
statementHandle, paramNumber++, SQL_PARAM_INPUT,
SQL_C_CHAR, SQL_VARCHAR, 80,
0, (SQLPOINTER)(stored_param.c_str()), stored_param.size() + 1,
NULL
);
}
else if constexpr (std::is_same_v) {
errorCode = SQLBindParameter(
statementHandle, paramNumber++, SQL_PARAM_INPUT,
SQL_C_WCHAR, SQL_WVARCHAR, 80,
0, (SQLPOINTER)(stored_param.c_str()), (stored_param.size() + 1) * sizeof(wchar_t),
NULL
);
}
// other types ...
if (!SQL_SUCCEEDED(errorCode)) { // no errors
cleanup();
throw std::exception(Errors::SQL_STATEMENT_BIND_INPUT_ERROR.data());
}
}
//... bind output parameters
// SQLExecute(statementHandle);
// return code == 0 and no errors registered
левый столбец - это varchar (100) , соответствующий std :: string , должен быть "123" , правый столбец - это nvarchar (max) , соответствует std :: wString , является правильным: Image
Ideb std :: ecector , использовал его для обработки `std :: string` parameters привязка, и это сработало. Однако логика загромождена в этом подходе. < /P>

Код: Выделить всё

// this works
if constexpr (std::is_same_v) {
strings.push_back(param); //member in StoredProc
std::string& stored_param = strings.back();
errorCode = SQLBindParameter(
statementHandle, paramNumber++, SQL_PARAM_INPUT,
SQL_C_CHAR, SQL_VARCHAR, 80,
0, (SQLPOINTER)(stored_param.c_str()), stored_param.size() + 1,
NULL
);
}
Мне кажется, что преобразование std :: string в std :: any и обратно в std :: string вызывает некоторые проблемы, о которых я не знаю. Что не так в первом фрагменте? Похоже, база данных не знает, что параметр представляет собой нулевую строку. Можете ли вы дать мне какой -нибудь совет? Другие идеи дизайна для класса StoreDProc приветствуются. В настоящее время появляется та же проблема, если я использую std :: variant и std :: view .
Весь код класса:

Код: Выделить всё

//SoredProc.h
#pragma once

#include "Errors.h"

#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 

using procedureName = std::string;

class StoredProc {
public:
StoredProc(const SQLHDBC dbH) : connectionHandle{ dbH } {}
~StoredProc() = default;

template
std::tuple execute(const procedureName& p, const InputTypes&...  parameters);

protected:
inline static size_t MAX_SIZE_BUFFER{ 255 };

static void handleDiagnosticRecord(SQLHANDLE hHandle, SQLSMALLINT hType, RETCODE RetCode);

void allocate();

void prepare(const procedureName& p, const size_t totalNumberOfParameters);

void bindReturnCode();

template
void bindOutputs(std::tuple& results);

template
void bindInputs(const InputTypes&... parameters);

template
void call(const procedureName& p, const size_t totalNumberOfParameters, std::tuple& results, const InputTypes&...  parameters);

template
void fetchOutputs(const size_t totalNumberOfParameters, std::tuple& results);

void cleanup();

template
void bindInputParameter(const T& param);

template
void bindOutputParameter(const T& param);

template
void fetchOneOutput(T& param, size_t index);

SQLHDBC connectionHandle{};
SQLHSTMT statementHandle{};
SQLRETURN errorCode{ 0 };
SQLUSMALLINT paramNumber{ 1 };
SQLINTEGER returnCode{ -1 };
std::vector bound_parameters{};
std::vector lengths{};
};

template
inline std::tuple StoredProc::execute(const procedureName& p, const InputTypes&... parameters)
{
std::tuple results{};
size_t totalNumberOfParameters = std::tuple_size::value + sizeof...(parameters);

allocate();
prepare(p, totalNumberOfParameters);
bindReturnCode();
bindInputs(parameters...);
bindOutputs(results);
call(p, totalNumberOfParameters, results, parameters...);
fetchOutputs(totalNumberOfParameters, results);
cleanup();

return results;
}

template
inline void StoredProc::bindInputs(const InputTypes&... parameters)
{
(bindInputParameter(parameters), ...);
}

template
inline void StoredProc::bindOutputs(std::tuple& results)
{
std::apply([this](auto&... params) {
(this->bindOutputParameter(params), ...);
},
results);
}

template
inline void StoredProc::call(const procedureName& p, const size_t totalNumberOfParameters, std::tuple& results, const InputTypes&...  parameters)
{
errorCode = SQLExecute(statementHandle);
if (!SQL_SUCCEEDED(errorCode)) {
cleanup();
throw std::exception(Errors::SQL_EXECUTE_ERROR.data());
}
if (returnCode) {
cleanup();
throw std::exception(Errors::SQL_RETURN_CODE_ERROR.data());
}
}

template
inline void StoredProc::fetchOutputs(const size_t totalNumberOfParameters, std::tuple& results)
{

}

template
inline void StoredProc::bindInputParameter(const T& param)
{
lengths.push_back(0);
SQLLEN* len = &lengths.back();
bound_parameters.push_back(param); // store value
auto& stored_param = std::any_cast(bound_parameters.back());

if constexpr (std::is_same_v) {
*len = sizeof(int);
errorCode = SQLBindParameter(
statementHandle, paramNumber++, SQL_PARAM_INPUT,
SQL_C_LONG, SQL_INTEGER, 10,
0, (SQLPOINTER)std::addressof(stored_param), 0,
NULL
);
}
else if constexpr (std::is_same_v) {
*len = sizeof(bool);
errorCode = SQLBindParameter(
statementHandle, paramNumber++, SQL_PARAM_INPUT,
SQL_C_BIT, SQL_BIT, 1,
0, (SQLPOINTER)std::addressof(stored_param), 0,
NULL
);
}
else if constexpr (std::is_same_v) { // here wrong
errorCode = SQLBindParameter(
statementHandle, paramNumber++, SQL_PARAM_INPUT,
SQL_C_CHAR, SQL_VARCHAR, 80,
0, (SQLPOINTER)(stored_param.c_str()), stored_param.size() + 1,
NULL
);
}
else if constexpr (std::is_same_v) { // here correct
errorCode = SQLBindParameter(
statementHandle, paramNumber++, SQL_PARAM_INPUT,
SQL_C_WCHAR, SQL_WVARCHAR, 80,
0, (SQLPOINTER)(stored_param.c_str()), (stored_param.size() + 1) * sizeof(wchar_t),
NULL
);
}

if (!SQL_SUCCEEDED(errorCode)) {
cleanup();
throw std::exception(Errors::SQL_STATEMENT_BIND_INPUT_ERROR.data());
}
}

template
inline void StoredProc::bindOutputParameter(const T& param)
{
lengths.push_back(0);
SQLLEN* len = &lengths.back();
bound_parameters.push_back(param);
auto& stored_param = std::any_cast(bound_parameters.back());

if constexpr (std::is_same_v) {
errorCode = SQLBindParameter(
statementHandle, paramNumber++, SQL_PARAM_OUTPUT,
SQL_C_LONG, SQL_INTEGER, sizeof(stored_param),
0, (SQLPOINTER)std::addressof(stored_param), sizeof(stored_param),
len
);
}
else if constexpr (std::is_same_v) {
errorCode = SQLBindParameter(
statementHandle, paramNumber++, SQL_PARAM_OUTPUT,
SQL_C_TINYINT, SQL_TINYINT, 1,
0, (SQLPOINTER)std::addressof(stored_param), 0,
len
);
}
else if constexpr (std::is_same_v) {
*len = MAX_SIZE_BUFFER;
stored_param.resize(*len);
errorCode = SQLBindParameter(
statementHandle, paramNumber++, SQL_PARAM_OUTPUT,
SQL_C_CHAR, SQL_VARCHAR, 80,
0, (SQLPOINTER)stored_param.data(), static_cast(stored_param.size()),
len
);
}
else if constexpr (std::is_same_v) {
*len = MAX_SIZE_BUFFER * sizeof(wchar_t);
stored_param.resize(MAX_SIZE_BUFFER);
errorCode = SQLBindParameter(
statementHandle, paramNumber++, SQL_PARAM_OUTPUT,
SQL_C_WCHAR, SQL_WVARCHAR, 80,
0, (SQLPOINTER)stored_param.data(), static_cast(stored_param.size()) * sizeof(wchar_t),
len
);
}

if (!SQL_SUCCEEDED(errorCode)) {
cleanup();
throw std::exception(Errors::SQL_STATEMENT_BIND_OUTPUT_ERROR.data());
}
}

template
inline void StoredProc::fetchOneOutput(T&  param, size_t any_index)
{

}

//StoredProc.cpp
#include "StoredProc.h"

void StoredProc::handleDiagnosticRecord(SQLHANDLE hHandle, SQLSMALLINT hType, RETCODE RetCode)
{
SQLSMALLINT iRec = 0;
SQLINTEGER  iError;
WCHAR       wszMessage[1000];
WCHAR       wszState[SQL_SQLSTATE_SIZE + 1];

if (RetCode == SQL_INVALID_HANDLE)
{
fwprintf(stderr, L"Invalid handle!\n");
return;
}

while (SQLGetDiagRecW(
hType, hHandle, ++iRec,
wszState, &iError, wszMessage,
(SQLSMALLINT)(sizeof(wszMessage) / sizeof(WCHAR)),
(SQLSMALLINT*)NULL) == SQL_SUCCESS)
if (wcsncmp(wszState, L"01004", 5))
fwprintf(stderr, L"[%5.5s] %s (%d)\n", wszState, wszMessage, iError);
}

void StoredProc::allocate()
{
errorCode = SQLAllocHandle(SQL_HANDLE_STMT, connectionHandle, &statementHandle);
if (!SQL_SUCCEEDED(errorCode))
throw std::exception(Errors::SQL_STATEMENT_ALLOC_ERROR.data());
}

void StoredProc::prepare(const procedureName& p, const size_t totalNumberOfParameters)
{
std::string procedureCall{ "{ ? = CALL " + p + "(" };
for (size_t i = 0; i < totalNumberOfParameters; ++i)
procedureCall += "?, ";
if (totalNumberOfParameters > 0)
procedureCall.erase(procedureCall.end() - 2, procedureCall.end());
procedureCall += ") }";

errorCode = SQLPrepare(statementHandle, (SQLCHAR*)(procedureCall.c_str()), SQL_NTS);
if (!SQL_SUCCEEDED(errorCode)) {
cleanup();
throw std::exception(Errors::SQL_STATEMENT_PREP_ERROR.data());
}
}

void StoredProc::bindReturnCode()
{
// must be first
lengths.push_back(0);
SQLLEN* len = &lengths.back();
errorCode = SQLBindParameter(
statementHandle, paramNumber++, SQL_PARAM_OUTPUT,
SQL_C_LONG, SQL_INTEGER, sizeof(returnCode),
0, reinterpret_cast(&returnCode), sizeof(returnCode),
len
);
if (!SQL_SUCCEEDED(errorCode)) {
cleanup();
throw std::exception(Errors::SQL_STATEMENT_BIND_RETCODE_ERROR.data());
}
}

void StoredProc::cleanup()
{
handleDiagnosticRecord(statementHandle, SQL_HANDLE_STMT, errorCode);
errorCode = SQLFreeHandle(SQL_HANDLE_STMT, statementHandle);
if (!SQL_SUCCEEDED(errorCode)) {
handleDiagnosticRecord(statementHandle, SQL_HANDLE_STMT, errorCode);
throw std::exception(Errors::SQL_STATEMENT_CLEANUP_ERROR.data());
}
}
< /code>
Вы сможете вызвать любую хранимую процедуру как: < /p>
#include "StoredProc.h"

int main()
{
// connect to database
StoredProc proc{ connectionHandle };

// define parameters;
std::string in_param1 = "param1";
std::wstring in_param2 = L"something";
int in_param3 = 6;
bool in_param4 = true;

// order of types matters:  returns an int and a bool as OUTPUT parameters
auto t = proc.execute("[dbo][]", in_param1, in_param2, in_param3, in_param4);
return 0;
}
См. Это для подключения к базе данных SQL Server.


Подробнее здесь: https://stackoverflow.com/questions/797 ... rocedure-c
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»