Z niewielką pomocą Mata udało mi się ustalić, na czym polega problem, ale ponieważ nie udzielił tego w formie odpowiedzi, będę musiał odpowiedzieć na to, aby można było się nim podzielić dla tych, którzy mają ten sam problem, a także oznaczyć jako odpowiedź.
Mój problem polegał na tym, że nie mogłem połączyć się z bazą danych. Jak zasugerował Mat, powinienem użyć rozszerzonej informacji o błędzie, znanej jako SQLGetDiagRec
a także naprawić argumenty zgodnie z dokumentacją. Zajęło mi chwilę, aby dowiedzieć się, jak SQLGetDiagRec
funkcja działa, ale raz udało mi się przekonwertować wchar_t
na char *
Byłem w stanie zobaczyć błąd, który generował.
Próba połączenia dała mi błąd Data source not found and no default driver specified
. To dało mi wskazówkę, wskazując, że albo napisałem niepoprawny ciąg połączenia, albo że ciąg tekstowy został w jakiś sposób błędnie zinterpretowany lub zniekształcony.
Wykonywanie wyszukiwania w sieci dał mi wgląd, że ciąg został błędnie zinterpretowany, i aby to naprawić, musiałem uczynić go dosłownym ciągiem. Z pewnością postawienie litery L przed napisem rozwiązało ten problem!
retcode = SQLDriverConnect(hdbc, 0,
(SQLWCHAR*)L"DSN=TestConnection;SERVER=localhost;UID=user;PWD=password;DRIVER=MySQL Server;",
_countof(L"DSN=TestConnection;SERVER=localhost;UID=user;PWD=password;DRIVER=MySQL Server;"),
OutConnStr, 255, &OutConnStrLen, SQL_DRIVER_COMPLETE);
Jednocześnie nauczyłem się, jak pozbyć się monitu, co było dość łatwe do zrozumienia po naprawieniu początkowego problemu. Określ null dla uchwytu okna, ustaw uzupełnianie sterownika na SQL_DRIVER_COMPLETE
i upewnij się, że dodałeś wszystkie potrzebne informacje w ciągu połączenia.
Więc kolejny problem, który miałem z zapytaniem z SQLExecDirect
wyświetlał błąd mówiący Syntax error or access violation
. Problem był oczywiście taki sam, jak w przypadku ciągu połączenia. Z pewnością
retcode = SQLExecDirect(hstmt, (SQLWCHAR*)L"SELECT TEST_STRING, TEST_INTEGER, TEST_FLOAT FROM dbo.testfire", SQL_NTS);
Działał jak urok.
Oto kod w całości, w pełni funkcjonalny:
#include <iostream>
#include <windows.h>
#include <sql.h>
#include <sqltypes.h>
#include <sqlext.h>
#include <string>
using namespace std;
int main(){
SQLHENV henv;
SQLHDBC hdbc;
SQLHSTMT hstmt;
SQLRETURN retcode;
SQLWCHAR OutConnStr[255];
SQLSMALLINT OutConnStrLen;
// Allocate environment handle
retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
// Set the ODBC version environment attribute
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
// Allocate connection handle
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
// Set login timeout to 5 seconds
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);
// Connect to data source
retcode = SQLDriverConnect(
hdbc,
0,
(SQLWCHAR*)L"DSN=TestConnection;SERVER=localhost;UID=root;PWD=never140;DRIVER=MySQL Server;",
_countof(L"DSN=TestConnection;SERVER=localhost;UID=root;PWD=never140;DRIVER=MySQL Server;"),
OutConnStr,
255,
&OutConnStrLen,
SQL_DRIVER_COMPLETE );
// Allocate statement handle
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
// Process data
retcode = SQLExecDirect(hstmt, (SQLWCHAR*)L"SELECT TEST_STRING, TEST_INTEGER, TEST_FLOAT FROM dbo.testfire", SQL_NTS);
if (retcode == SQL_SUCCESS) {
SQLINTEGER sTestInt, cbTestStr, cbTestInt, cbTestFloat, iCount = 1;
SQLFLOAT dTestFloat;
SQLCHAR szTestStr[200];
while (TRUE) {
retcode = SQLFetch(hstmt);
if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) {
cout<<"An error occurred";
}
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){
SQLGetData(hstmt, 1, SQL_C_CHAR, szTestStr, 200, &cbTestStr);
SQLGetData(hstmt, 2, SQL_C_ULONG, &sTestInt, 0, &cbTestInt);
SQLGetData(hstmt, 3, SQL_C_DOUBLE, &dTestFloat, 0,&cbTestFloat);
/* Print the row of data */
cout<<"Row "<<iCount<<":"<<endl;
cout<<szTestStr<<endl;
cout<<sTestInt<<endl;
cout<<dTestFloat<<endl;
iCount++;
} else {
break;
}
}
}else{
cout<<"Query execution error."<<endl;
}
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
SQLDisconnect(hdbc);
}else{
cout<<"Connection error"<<endl;
}
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
}
}
SQLFreeHandle(SQL_HANDLE_ENV, henv);
}
system("pause");
return 0;
}
Po prostu widać, że nawet najmniejsza rzecz może sprawić, że wszystko zawiedzie.
Dziękuję Mat za pomoc.