static void Test(int level) { SQLRETURN result; SQLSMALLINT InParam = level; SQLSMALLINT OutParam = 1; SQLLEN cbReturnCode = 0, cbInParam = 0, cbOutParam = 0; SQLLEN cbOutString = SQL_NTS; char sql[80]; printf("ODBC %d nocount %s select %s level %d\n", odbc_use_version3 ? 3 : 2, g_nocount ? "yes" : "no", g_second_select ? "yes" : "no", level); ReturnCode = INVALID_RETURN; memset(&OutString, 0, sizeof(OutString)); /* test with SQLExecDirect */ sprintf(sql, "RAISERROR('An error occurred.', %d, 1)", level); result = odbc_command_with_result(odbc_stmt, sql); TestResult(result, level, "SQLExecDirect"); /* test with SQLPrepare/SQLExecute */ if (!SQL_SUCCEEDED(SQLPrepare(odbc_stmt, T(SP_TEXT), strlen(SP_TEXT)))) { fprintf(stderr, "SQLPrepare failure!\n"); exit(1); } SQLBindParameter(odbc_stmt, 1, SQL_PARAM_OUTPUT, SQL_C_SSHORT, SQL_INTEGER, 0, 0, &ReturnCode, 0, &cbReturnCode); SQLBindParameter(odbc_stmt, 2, SQL_PARAM_INPUT, SQL_C_SSHORT, SQL_INTEGER, 0, 0, &InParam, 0, &cbInParam); SQLBindParameter(odbc_stmt, 3, SQL_PARAM_OUTPUT, SQL_C_SSHORT, SQL_INTEGER, 0, 0, &OutParam, 0, &cbOutParam); strcpy(OutString, "Invalid!"); SQLBindParameter(odbc_stmt, 4, SQL_PARAM_OUTPUT, SQL_C_CHAR, SQL_VARCHAR, OUTSTRING_LEN, 0, OutString, OUTSTRING_LEN, &cbOutString); CHKExecute("S"); /* first select, check data are returned. * SET statements before does not affect results */ CheckData(""); CHKFetch("S"); CheckData("Here is the first row"); result = SQLFetch(odbc_stmt); if (odbc_use_version3) { SQLTCHAR SqlState[6]; SQLINTEGER NativeError; SQLTCHAR MessageText[1000]; SQLSMALLINT TextLength; SQLRETURN expected; SQLLEN rows; if (result != SQL_NO_DATA) ODBC_REPORT_ERROR("SQLFetch should return NO DATA"); CHKGetDiagRec(SQL_HANDLE_STMT, odbc_stmt, 1, SqlState, &NativeError, MessageText, ODBC_VECTOR_SIZE(MessageText), &TextLength, "No"); result = SQLMoreResults(odbc_stmt); expected = level > 10 ? SQL_ERROR : SQL_SUCCESS_WITH_INFO; if (result != expected) ODBC_REPORT_ERROR("SQLMoreResults returned unexpected result"); if (!g_second_select && g_nocount) { if (ReturnCode == INVALID_RETURN) { result = SQLMoreResults(odbc_stmt); } else { CheckReturnCode(result, 0); ReturnCode = INVALID_RETURN; TestResult(result, level, "SQLMoreResults"); ReturnCode = 0; } } else { TestResult(result, level, "SQLMoreResults"); } /* a recordset with only warnings/errors do not contains rows */ if (CHKRowCount(&rows, "SE") == SQL_SUCCESS && rows != -1) ODBC_REPORT_ERROR("SQLRowCount returned some rows"); } else { /* in ODBC 2 errors/warnings are not handled as different recordset */ TestResult(result, level, "SQLFetch"); } if (odbc_driver_is_freetds()) CheckData(""); if (!g_second_select) { SQLLEN rows; if (CHKRowCount(&rows, "SE") == SQL_SUCCESS && rows != -1) ODBC_REPORT_ERROR("SQLRowCount returned some rows"); CheckReturnCode(result, g_nocount ? 0 : INVALID_RETURN); result = SQLMoreResults(odbc_stmt); #ifdef ENABLE_DEVELOPING if (result != SQL_NO_DATA) ODBC_REPORT_ERROR("SQLMoreResults should return NO DATA"); ODBC_CHECK_ROWS(-2); #endif CheckReturnCode(result, 0); return; } if (!odbc_use_version3 || !g_nocount) { /* mssql 2008 return SUCCESS_WITH_INFO with previous error */ CHKMoreResults("S"); result = SQL_SUCCESS; } CheckReturnCode(result, INVALID_RETURN); CheckData(""); if (g_nocount && odbc_use_version3 && g_second_select && level >= 10) { if (CHKFetch("SE") == SQL_ERROR) { SQLMoreResults(odbc_stmt); CHKFetch("S"); } } else { CHKFetch("S"); } CheckData("Here is the last row"); CHKFetch("No"); CheckData(""); if (!odbc_use_version3 || g_nocount) CheckReturnCode(result, 0); #ifdef ENABLE_DEVELOPING else CheckReturnCode(result, INVALID_RETURN); #endif /* FIXME how to handle return in store procedure ?? */ result = SQLMoreResults(odbc_stmt); #ifdef ENABLE_DEVELOPING if (result != SQL_NO_DATA) ODBC_REPORT_ERROR("SQLMoreResults return other data"); #endif CheckReturnCode(result, 0); CheckData(""); ODBC_FREE(); }
static int test(int odbc3) { SQLLEN cnamesize; const char *query; odbc_use_version3 = odbc3; odbc_connect(); /* issue print statement and test message returned */ output[0] = 0; query = "print 'START' select count(*) from sysobjects where name='sysobjects' print 'END'"; odbc_command2(query, "I"); odbc_read_error(); if (!strstr(odbc_err, "START")) { printf("Message invalid\n"); return 1; } odbc_err[0] = 0; if (odbc3) { ODBC_CHECK_COLS(0); ODBC_CHECK_ROWS(-1); CHKFetch("E"); CHKMoreResults("S"); } ODBC_CHECK_COLS(1); ODBC_CHECK_ROWS(-1); CHKFetch("S"); ODBC_CHECK_COLS(1); ODBC_CHECK_ROWS(-1); /* check no data */ CHKFetch("No"); ODBC_CHECK_COLS(1); ODBC_CHECK_ROWS(1); /* SQLMoreResults return NO DATA or SUCCESS WITH INFO ... */ if (tds_no_dm && !odbc3) CHKMoreResults("No"); else if (odbc3) CHKMoreResults("I"); else CHKMoreResults("INo"); /* * ... but read error * (unixODBC till 2.2.11 do not read errors on NO DATA, skip test) */ if (tds_no_dm || odbc3) { odbc_read_error(); if (!strstr(odbc_err, "END")) { printf("Message invalid\n"); return 1; } odbc_err[0] = 0; } if (odbc3) { ODBC_CHECK_COLS(0); ODBC_CHECK_ROWS(-1); CHKMoreResults("No"); } /* issue invalid command and test error */ odbc_command2("SELECT donotexistsfield FROM donotexiststable", "E"); odbc_read_error(); /* test no data returned */ CHKFetch("E"); odbc_read_error(); CHKGetData(1, SQL_C_CHAR, output, sizeof(output), &cnamesize, "E"); odbc_read_error(); odbc_disconnect(); return 0; }
static void DoTest(int prepare) { int n = 0; static const char query[] = /* on prepared this recordset should be skipped */ "DECLARE @b INT SELECT @b = 25 " "SELECT * FROM #tmp1 WHERE i <= 3 " /* on prepare we cannot distinguish these recordset */ "INSERT INTO #tmp2 SELECT * FROM #tmp1 WHERE i = 1 " "INSERT INTO #tmp2 SELECT * FROM #tmp1 WHERE i <= 3 " "SELECT * FROM #tmp1 WHERE i = 1 " /* but FreeTDS can detect last recordset */ "UPDATE #tmp1 SET i=i+1 WHERE i >= 2"; if (prepare) { CHKPrepare(T(query), SQL_NTS, "S"); CHKExecute("S"); } else { /* execute a batch command select insert insert select and check rows */ CHKExecDirect(T(query), SQL_NTS, "S"); } if (!prepare) { printf("Result %d\n", ++n); ODBC_CHECK_COLS(0); ODBC_CHECK_ROWS(1); CHKMoreResults("S"); } printf("Result %d\n", ++n); ODBC_CHECK_COLS(1); ODBC_CHECK_ROWS(-1); CHKFetch("S"); CHKFetch("S"); ODBC_CHECK_COLS(1); ODBC_CHECK_ROWS(-1); CHKFetch("No"); ODBC_CHECK_COLS(1); ODBC_CHECK_ROWS(2); CHKMoreResults("S"); if (!prepare) { printf("Result %d\n", ++n); ODBC_CHECK_COLS(0); ODBC_CHECK_ROWS(1); CHKMoreResults("S"); printf("Result %d\n", ++n); ODBC_CHECK_COLS(0); ODBC_CHECK_ROWS(2); CHKMoreResults("S"); } printf("Result %d\n", ++n); ODBC_CHECK_COLS(1); ODBC_CHECK_ROWS(-1); CHKFetch("S"); ODBC_CHECK_COLS(1); ODBC_CHECK_ROWS(-1); CHKFetch("No"); ODBC_CHECK_COLS(1); if (prepare) { /* collapse 2 recordset... after a lot of testing this is the behavior! */ if (odbc_driver_is_freetds()) ODBC_CHECK_ROWS(2); } else { ODBC_CHECK_ROWS(1); CHKMoreResults("S"); ODBC_CHECK_COLS(0); ODBC_CHECK_ROWS(2); } CHKMoreResults("No"); #ifndef TDS_NO_DM if (!prepare) ODBC_CHECK_COLS(-1); ODBC_CHECK_ROWS(-2); #endif ODBC_FREE(); }