Я пытаюсь подключиться к серверу MySQL, используя C ++ с драйвером MySQL ODBC 5.1 в Visual C ++ 2008 Express Edition.
Я следую этим инструкциям MSDN:
Единственное отличие состоит в том, что мне нужно преобразовать все SQLCHAR
в SQLWCHAR
, чтобы соответствовать параметрам функции, надеюсь, это не повлияет на строку подключения.
Каждый раз, когда я подключаюсь, я получаю SQL_ERROR
в качестве возвращаемого значения.
Поэтому я предполагаю, что что-то не так со строкой соединения или оператором соединения.
Я пробовал
DNS=TestConnection; UID=user; PSW=password
и
SERVER=localhost; DRIVER={MySQL ODBC 5.1 Driver}; PORT=3306; UID=user; PSW=password; DATABASE=dbo;
и другие похожие строки подключения.
DNS, который называется TestConnection
, имеет ту же информацию, что и последняя строка подключения.
Схема dbo
и имеет одну таблицу с именем testfire
со следующими характеристиками столбца:
TEST_ID( INT(11), PRIMARY, AUTO INCREMENT)
TEST_STRING( VARCHAR(50) )
TEST_INTEGER( INT(11) )
TEST_FLOAT( FLOAT )
TEST_DATE( DATETIME )
С 3 рядами:
ID STRING INT FLOAT DATE
------------------------------------------------------
| 1 | Test 1 | 1 | 0.1 | 2001-01-01 00:00:00 |
| 2 | Test 2 | 2 | 0.2 | 2002-01-01 00:00:00 |
| 3 | Test 3 | 3 | 0.3 | 2003-01-01 00:00:00 |
------------------------------------------------------
Я пытался получить данные с помощью соединения Excel, в основном, чтобы проверить, работает ли драйвер. Excel успешно извлек данные без проблем, поэтому DNS с именем TestConnection действителен, как и учетные данные.
- Что я делаю не так?
- Что я должен изменить?
- Преобразование в
MYSQLWCHAR *
портит строку подключения?
- Есть ли другой, возможно, лучший и более эффективный подход? (кроме, возможно, инкапсуляции классов, это то, что я собираюсь сделать после успешного прохождения теста)
О, и компилятор не выдает никаких ошибок или предупреждений, код скомпилирован и работает без проблем.
Итак, вот тестовый код, который возвращает «Ошибка выполнения запроса»:
#include <iostream>
#include <windows.h>
#include <sql.h>
#include <sqltypes.h>
#include <sqlext.h>
using namespace std;
int main(){
SQLHENV henv;
SQLHDBC hdbc;
SQLHSTMT hstmt;
SQLRETURN retcode;
HWND desktopHandle = GetDesktopWindow();
SQLWCHAR OutConnStr[255];
SQLSMALLINT OutConnStrLen;
SQLWCHAR szDNS[2048] ={0};
// 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,
desktopHandle,
(SQLWCHAR*)"driver=MySQL Server",
_countof("driver=MySQL Server"),
OutConnStr,
255,
&OutConnStrLen,
SQL_DRIVER_PROMPT );
// 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*)"SELECT TEST_STRING, TEST_INTEGER, TEST_FLOAT FROM dbo.testfire", SQL_NTS);
if (retcode == SQL_SUCCESS) {
SQLINTEGER sTestInt, cbTestStr, cbTestInt, cbTestFloat;
SQLFLOAT dTestFloat;
SQLCHAR szTestStr[200];
while (TRUE) {
cout<<"Inside loop";
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_FLOAT, &dTestFloat, 0,&cbTestFloat);
/* Print the row of data */
cout<<szTestStr<<endl;
cout<<sTestInt<<endl;
cout<<dTestFloat<<endl;
} else {
break;
}
}
}else{
cout<<"Query execution error."<<endl;
SQLWCHAR SqlState[6], Msg[SQL_MAX_MESSAGE_LENGTH];
SQLINTEGER NativeError;
SQLSMALLINT i, MsgLen;
SQLRETURN rc2;
// Get the status records.
i = 1;
while ((rc2 = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, SqlState, &NativeError,
Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA) {
cout<<SqlState<<endl;
cout<<NativeError<<endl;
cout<<Msg<<endl;
cout<<MsgLen<<endl;
i++;
}
}
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
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;
}
UPDATE
После обновления кода (и публикации) с использованием правильных аргументов для SQLDriverConnect
из документации, предоставленной Mat (см. Комментарии ниже), соединение работает. Как я могу сделать то же самое, не запрашивая DNS-имя? Поставить дескриптор окна как ноль и ...?
Теперь он выходит из строя на SQLExecDirect(hstmt, (SQLWCHAR*)"SELECT TEST_STRING, TEST_INTEGER, TEST_FLOAT FROM dbo.testfire", SQL_NTS)
, но запрос правильный, так в чем же проблема?
Точное возвращаемое сообщение об ошибке:
Sql State: 42000
Native Error: 1064
Message:
Message Length: 211
42000: Syntax error or access violation
*StatementText contained an SQL statement that was not preparable or contained a syntax error.
The user did not have permission to execute the SQL statement contained in *StatementText.
Так ... что это значит?
Как я могу не иметь разрешения?
Как это может генерировать синтаксическую ошибку, это явно правильный запрос?