2017-01-16 2 views
0

Могу ли я использовать дескриптор инструкции ODBC еще раз (т. Е. Он действителен) после команды, использующей его, например SQLExecute, сбой? (не возвращает SQL_SUCCESS или SQL_SUCCESS_WITH_INFO)Могу ли я использовать инструкцию ODBC после ошибки (действительно ли она)?

И возможно ли это, что это DBMS/драйвер?

Я ничего не мог найти об этом на странице ODBC Programmer's reference.

ответ

1

Я не могу найти никаких авторитетных ответов в документе. Но я бы сказал: Да - вы можете, за исключением возвращается код ошибки SQL_INVALID_HANDLE:

Рассуждение:

  1. Ни один из докторов функций, которые требуют справку-ручки в качестве аргумента не говоря ничего о недействительным в случае ошибки. Все, что имеет значение, - это код возврата. Поэтому, если это явно запрещено, оно должно работать.

  2. В случае возврата SQL_ERROR вы можете использовать один и тот же дескриптор инструкции для получения дополнительной информации об этой ошибке. Таким образом, инструкция handle имеет действительный контекст.

    3: Мы используем тот же оператор снова и снова, даже в случае возврата SQL_ERROR. И пока у нас не было никаких проблем. Ну, но в основном мы не получаем никаких ошибок ..

Update, после того, как комментарий о «Заявлении был прекращен»: Да, вы можете повторно использовать тот же оператор-ручку. Ошибка просто указывает на то, что выполняемый в настоящий момент оператор был завершен сервером. См следующий пример, который производит такую ​​ошибку, а затем использует тот же оператор снова сделать успешную вставку:

#include <windows.h> 
#include <tchar.h> 
#include <iostream> 
#include <sql.h> 
#include <sqlext.h> 
#include <sqlucode.h> 

void printErr(SQLHANDLE handle, SQLSMALLINT handleType) 
{ 
    SQLSMALLINT recNr = 1; 
    SQLRETURN ret = SQL_SUCCESS; 
    while (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) 
    { 
     SQLWCHAR errMsg[SQL_MAX_MESSAGE_LENGTH + 1]; 
     SQLWCHAR sqlState[5 + 1]; 
     errMsg[0] = 0; 
     SQLINTEGER nativeError; 
     SQLSMALLINT cb = 0; 
     ret = SQLGetDiagRec(handleType, handle, recNr, sqlState, &nativeError, errMsg, SQL_MAX_MESSAGE_LENGTH + 1, &cb); 
     if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) 
     { 
      std::wcerr << L"ERROR; native: " << nativeError << L"; state: " << sqlState << L"; msg: " << errMsg << std::endl; 
     } 
     ++recNr; 
    } 
} 


int _tmain(int argc, _TCHAR* argv[]) 
{ 
    // connect to db 
    SQLRETURN nResult = 0; 
    SQLHANDLE handleEnv = 0; 

    nResult = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, (SQLHANDLE*)&handleEnv); 
    nResult = SQLSetEnvAttr(handleEnv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3_80, SQL_IS_INTEGER); 

    SQLHANDLE handleDBC = 0; 
    nResult = SQLAllocHandle(SQL_HANDLE_DBC, handleEnv, (SQLHANDLE*)&handleDBC); 

    SQLWCHAR  strConnect[256] = L"Driver={SQL Server};Server=.\\INSTANCE;Database=Test;Trusted_Connection=yes;"; 
    SQLWCHAR  strConnectOut[1024] = { 0 }; 
    SQLSMALLINT nNumOut = 0; 
    nResult = SQLDriverConnect(handleDBC, NULL, (SQLWCHAR*)strConnect, SQL_NTS, (SQLWCHAR*)strConnectOut, sizeof(strConnectOut), &nNumOut, SQL_DRIVER_NOPROMPT); 
    if (!SQL_SUCCEEDED(nResult)) 
     printErr(handleDBC, SQL_HANDLE_DBC); 

    SQLHSTMT handleStatement = SQL_NULL_HSTMT; 
    nResult = SQLAllocHandle(SQL_HANDLE_STMT, handleDBC, (SQLHANDLE*)&handleStatement); 
    if (!SQL_SUCCEEDED(nResult)) 
     printErr(handleDBC, SQL_HANDLE_DBC); 

    // try to drop table Wallet, ignore if it exists 
    nResult = SQLExecDirect(handleStatement, L"DROP TABLE Wallet", SQL_NTS); 

    // create table Wallet 
    nResult = SQLExecDirect(handleStatement, L"CREATE TABLE Wallet (WalletID int NOT NULL, Name nvarchar(5) NOT NULL)", SQL_NTS); 
    if (!SQL_SUCCEEDED(nResult)) 
      printErr(handleStatement, SQL_HANDLE_STMT); 

    // Create a query that fails with data truncation and statement got terminated error: 
    nResult = SQLExecDirect(handleStatement, L"INSERT INTO Wallet (WalletID, Name) VALUES (1, 'SomethingTooLong')", SQL_NTS); 
    if (!SQL_SUCCEEDED(nResult)) 
     printErr(handleStatement, SQL_HANDLE_STMT); 

    // and now run a query on the same statement and check in the db: Has been inserted just fine 
    nResult = SQLExecDirect(handleStatement, L"INSERT INTO Wallet (WalletID, Name) VALUES (2, 'Fan')", SQL_NTS); 
    if (!SQL_SUCCEEDED(nResult)) 
     printErr(handleStatement, SQL_HANDLE_STMT); 
    // actually we should now free all handles properly... 
    return 0; 
} 

Вывод этой программы:

ОШИБКА; native: 8152; состояние: 22001; msg: [Microsoft] [ODBC SQL Server Драйвер] [SQL Server] Строковые или двоичные данные будут усечены. ОШИБКА; родной: 3621; состояние: 01000; msg: [Microsoft] [ODBC SQL Server Драйвер] [SQL Server] Оператор завершен.

Но последний запрос вставки, которая работает без ошибок, с помощью оператора, был успешно выполнен: Проверить в базе данных и убедиться, что строка была вставлена ​​(и что SQLExecDirect не возвратили ошибки).

Смотрите здесь SQL_INVALID_HANDLE: https://msdn.microsoft.com/en-us/library/ms716219(v=vs.85).aspx

+0

Я спрашиваю, потому что с MSSQL может случиться так, что если выполнить не удается, MSSQL можно сказать, что заявление было прекращено (и, следовательно, непригодным для использования, я думаю). Вы можете, конечно, получить от него ошибки, но можете ли вы, например, выполнить его снова с разными параметрами? '[22003] (родной 8115): [Microsoft] [драйвер ODBC 11 для SQL Server] [SQL Server] Ошибка арифметического переполнения, преобразующая выражение в тип данных tinyint; [01000] (родной номер 3621): [Microsoft] [драйвер ODBC 11 для SQL Server] [SQL Server] Оператор завершен. ' – omusil

Смежные вопросы