LCOV - code coverage report
Current view: top level - src/odbc/unittests - raiserror.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 112 127 88.2 %
Date: 2025-02-21 09:36:06 Functions: 6 6 100.0 %

          Line data    Source code
       1             : #include "common.h"
       2             : 
       3             : /* test RAISERROR in a store procedure, from Tom Rogers tests */
       4             : 
       5             : /* TODO add support for Sybase */
       6             : 
       7             : #define SP_TEXT "{?=call #tmp1(?,?,?)}"
       8             : #define OUTSTRING_LEN 20
       9             : #define INVALID_RETURN (-12345)
      10             : 
      11             : static const char create_proc[] =
      12             :         "CREATE PROCEDURE #tmp1\n"
      13             :         "    @InParam int,\n"
      14             :         "    @OutParam int OUTPUT,\n"
      15             :         "    @OutString varchar(20) OUTPUT\n"
      16             :         "AS\n"
      17             :         "%s"
      18             :         "     SET @OutParam = @InParam\n"
      19             :         "     SET @OutString = 'This is bogus!'\n"
      20             :         "     SELECT 'Here is the first row' AS FirstResult\n"
      21             :         "     RAISERROR('An error occurred.', @InParam, 1)\n"
      22             :         "%s"
      23             :         "     RETURN (0)";
      24             : 
      25             : static SQLSMALLINT ReturnCode;
      26             : static char OutString[OUTSTRING_LEN];
      27             : static int g_nocount, g_second_select;
      28             : 
      29             : #ifdef TDS_NO_DM
      30             : static const int tds_no_dm = 1;
      31             : #else
      32             : static const int tds_no_dm = 0;
      33             : #endif
      34             : 
      35             : static void
      36         188 : TestResult(SQLRETURN result0, int level, const char *func)
      37             : {
      38         188 :         ODBC_BUF *odbc_buf = NULL;
      39             :         SQLTCHAR SqlState[6];
      40             :         SQLINTEGER NativeError;
      41             :         SQLTCHAR MessageText[1000];
      42             :         SQLSMALLINT TextLength;
      43         188 :         SQLRETURN result = result0, rc;
      44             : 
      45         188 :         if (result == SQL_NO_DATA && strcmp(func, "SQLFetch") == 0)
      46          16 :                 result = SQL_SUCCESS_WITH_INFO;
      47             : 
      48         188 :         if ((level <= 10 && result != SQL_SUCCESS_WITH_INFO) || (level > 10 && result != SQL_ERROR) || ReturnCode != INVALID_RETURN) {
      49           0 :                 fprintf(stderr, "%s failed!\n", func);
      50           0 :                 exit(1);
      51             :         }
      52             : 
      53             :         /*
      54             :          * unixODBC till 2.2.11 do not support getting error if SQL_NO_DATA
      55             :          */
      56             :         if (!tds_no_dm && result0 == SQL_NO_DATA && strcmp(func, "SQLFetch") == 0)
      57             :                 return;
      58             : 
      59         188 :         SqlState[0] = 0;
      60         188 :         MessageText[0] = 0;
      61         188 :         NativeError = 0;
      62         188 :         rc = CHKGetDiagRec(SQL_HANDLE_STMT, odbc_stmt, 1, SqlState, &NativeError, MessageText, TDS_VECTOR_SIZE(MessageText), &TextLength, "SI");
      63         188 :         printf("Func=%s Result=%d DIAG REC 1: State=%s Error=%d: %s\n", func, (int) rc, C(SqlState), (int) NativeError, C(MessageText));
      64             : 
      65         188 :         if (strstr(C(MessageText), "An error occurred") == NULL) {
      66           0 :                 fprintf(stderr, "Wrong error returned!\n");
      67           0 :                 fprintf(stderr, "Error returned: %s\n", C(MessageText));
      68           0 :                 exit(1);
      69             :         }
      70         188 :         ODBC_FREE();
      71             : }
      72             : 
      73             : #define MY_ERROR(msg) odbc_report_error(msg, line, __FILE__)
      74             : 
      75             : static void
      76         544 : CheckData(const char *s, int line)
      77             : {
      78             :         char buf[80];
      79             :         SQLLEN ind;
      80             :         SQLRETURN rc;
      81             : 
      82         544 :         rc = CHKGetData(1, SQL_C_CHAR, buf, sizeof(buf), &ind, "SE");
      83             : 
      84         544 :         if (rc == SQL_ERROR) {
      85         384 :                 buf[0] = 0;
      86         384 :                 ind = 0;
      87             :         }
      88             : 
      89         544 :         if (strlen(s) != ind || strcmp(buf, s) != 0)
      90           0 :                 MY_ERROR("Invalid result");
      91         544 : }
      92             : 
      93             : #define CheckData(s) CheckData(s, __LINE__)
      94             : 
      95             : static void
      96         252 : CheckReturnCode(SQLRETURN result, SQLSMALLINT expected, int line)
      97             : {
      98         252 :         if (ReturnCode == expected && (expected != INVALID_RETURN || strcmp(OutString, "Invalid!") == 0)
      99         252 :             && (expected == INVALID_RETURN || strcmp(OutString, "This is bogus!") == 0))
     100             :                 return;
     101             : 
     102           0 :         printf("SpDateTest Output:\n");
     103           0 :         printf("   Result = %d\n", (int) result);
     104           0 :         printf("   Return Code = %d\n", (int) ReturnCode);
     105           0 :         printf("   OutString = \"%s\"\n", OutString);
     106           0 :         MY_ERROR("Invalid ReturnCode");
     107             : }
     108             : 
     109             : #define CheckReturnCode(res, exp) CheckReturnCode(res, exp, __LINE__)
     110             : 
     111             : static const char yes_no[][4] = {
     112             :         "no", "yes"
     113             : };
     114             : #define yes_no(cond) yes_no[!!(cond)]
     115             : 
     116             : static void
     117          96 : Test(int level)
     118             : {
     119             :         SQLRETURN result;
     120          96 :         SQLSMALLINT InParam = level;
     121          96 :         SQLSMALLINT OutParam = 1;
     122          96 :         SQLLEN cbReturnCode = 0, cbInParam = 0, cbOutParam = 0;
     123          96 :         SQLLEN cbOutString = SQL_NTS;
     124             : 
     125             :         char sql[80];
     126             : 
     127          96 :         printf("ODBC %d nocount %s select %s level %d\n", odbc_use_version3 ? 3 : 2,
     128          96 :                yes_no(g_nocount), yes_no(g_second_select), level);
     129             : 
     130          96 :         ReturnCode = INVALID_RETURN;
     131          96 :         memset(&OutString, 0, sizeof(OutString));
     132             : 
     133             :         /* test with SQLExecDirect */
     134          96 :         sprintf(sql, "RAISERROR('An error occurred.', %d, 1)", level);
     135          96 :         result = odbc_command_with_result(odbc_stmt, sql);
     136             : 
     137          96 :         TestResult(result, level, "SQLExecDirect");
     138             : 
     139             :         /* test with SQLPrepare/SQLExecute */
     140          96 :         printf("Preparing: %s\n", SP_TEXT);
     141          96 :         CHKPrepare(T(SP_TEXT), strlen(SP_TEXT), "SI");
     142             : 
     143          96 :         SQLBindParameter(odbc_stmt, 1, SQL_PARAM_OUTPUT, SQL_C_SSHORT, SQL_INTEGER, 0, 0, &ReturnCode, 0, &cbReturnCode);
     144          96 :         SQLBindParameter(odbc_stmt, 2, SQL_PARAM_INPUT, SQL_C_SSHORT, SQL_INTEGER, 0, 0, &InParam, 0, &cbInParam);
     145          96 :         SQLBindParameter(odbc_stmt, 3, SQL_PARAM_OUTPUT, SQL_C_SSHORT, SQL_INTEGER, 0, 0, &OutParam, 0, &cbOutParam);
     146          96 :         strcpy(OutString, "Invalid!");
     147          96 :         SQLBindParameter(odbc_stmt, 4, SQL_PARAM_OUTPUT, SQL_C_CHAR, SQL_VARCHAR, OUTSTRING_LEN, 0, OutString, OUTSTRING_LEN,
     148             :                          &cbOutString);
     149             : 
     150          96 :         CHKExecute("S");
     151             : 
     152             :         /* first select, check data are returned.
     153             :          * SET statements before does not affect results
     154             :          */
     155          96 :         CheckData("");
     156          96 :         CHKFetch("S");
     157          96 :         CheckData("Here is the first row");
     158             : 
     159          96 :         result = SQLFetch(odbc_stmt);
     160          96 :         if (odbc_use_version3) {
     161             :                 SQLTCHAR SqlState[6];
     162             :                 SQLINTEGER NativeError;
     163             :                 SQLTCHAR MessageText[1000];
     164             :                 SQLSMALLINT TextLength;
     165             :                 SQLRETURN expected;
     166             :                 SQLLEN rows;
     167             : 
     168          64 :                 if (result != SQL_NO_DATA)
     169           0 :                         ODBC_REPORT_ERROR("SQLFetch should return NO DATA");
     170          64 :                 CHKGetDiagRec(SQL_HANDLE_STMT, odbc_stmt, 1, SqlState, &NativeError, MessageText,
     171             :                                        TDS_VECTOR_SIZE(MessageText), &TextLength, "No");
     172          64 :                 result = SQLMoreResults(odbc_stmt);
     173          64 :                 expected = level > 10 ? SQL_ERROR : SQL_SUCCESS_WITH_INFO;
     174          64 :                 if (result != expected)
     175           0 :                         ODBC_REPORT_ERROR("SQLMoreResults returned unexpected result");
     176          64 :                 if (!g_second_select && g_nocount) {
     177          16 :                         if (ReturnCode == INVALID_RETURN) {
     178           4 :                                 result = SQLMoreResults(odbc_stmt);
     179             :                         } else {
     180          12 :                                 CheckReturnCode(result, 0);
     181          12 :                                 ReturnCode = INVALID_RETURN;
     182          12 :                                 TestResult(result, level, "SQLMoreResults");
     183          12 :                                 ReturnCode = 0;
     184             :                         }
     185             :                 } else {
     186          48 :                         TestResult(result, level, "SQLMoreResults");
     187             :                 }
     188             : 
     189             :                 /* a recordset with only warnings/errors do not contains rows */
     190          64 :                 if (CHKRowCount(&rows, "SE") == SQL_SUCCESS && rows != -1)
     191           0 :                         ODBC_REPORT_ERROR("SQLRowCount returned some rows");
     192             :         } else {
     193             :                 /* in ODBC 2 errors/warnings are not handled as different recordset */
     194          32 :                 TestResult(result, level, "SQLFetch");
     195             :         }
     196             : 
     197          96 :         if (odbc_driver_is_freetds())
     198          96 :                 CheckData("");
     199             : 
     200          96 :         if (!g_second_select) {
     201             :                 SQLLEN rows;
     202             : 
     203          32 :                 if (CHKRowCount(&rows, "SE") == SQL_SUCCESS && rows != -1)
     204           0 :                         ODBC_REPORT_ERROR("SQLRowCount returned some rows");
     205          32 :                 CheckReturnCode(result, g_nocount ? 0 : INVALID_RETURN);
     206             : 
     207          32 :                 result = SQLMoreResults(odbc_stmt);
     208             : #ifdef ENABLE_DEVELOPING
     209             :                 if (result != SQL_NO_DATA)
     210             :                         ODBC_REPORT_ERROR("SQLMoreResults should return NO DATA");
     211             : 
     212             :                 ODBC_CHECK_ROWS(-2);
     213             : #endif
     214          32 :                 CheckReturnCode(result, 0);
     215             :                 return;
     216             :         }
     217             : 
     218          64 :         if (!odbc_use_version3 || !g_nocount) {
     219             :                 /* mssql 2008 return SUCCESS_WITH_INFO with previous error */
     220          48 :                 CHKMoreResults("S");
     221          48 :                 result = SQL_SUCCESS;
     222             :         }
     223             : 
     224          64 :         CheckReturnCode(result, INVALID_RETURN);
     225             : 
     226          64 :         CheckData("");
     227          64 :         if (g_nocount && odbc_use_version3 && g_second_select && level >= 10) {
     228           8 :                 if (CHKFetch("SE") == SQL_ERROR) {
     229           4 :                         SQLMoreResults(odbc_stmt);
     230           4 :                         CHKFetch("S");
     231             :                 }
     232             :         } else {
     233          56 :                 CHKFetch("S");
     234             :         }
     235          64 :         CheckData("Here is the last row");
     236             : 
     237          64 :         CHKFetch("No");
     238          64 :         CheckData("");
     239             : 
     240          64 :         if (!odbc_use_version3 || g_nocount)
     241          48 :                 CheckReturnCode(result, 0);
     242             : #ifdef ENABLE_DEVELOPING
     243             :         else
     244             :                 CheckReturnCode(result, INVALID_RETURN);
     245             : #endif
     246             : 
     247             :         /* FIXME how to handle return in store procedure ??  */
     248          64 :         result = SQLMoreResults(odbc_stmt);
     249             : #ifdef ENABLE_DEVELOPING
     250             :         if (result != SQL_NO_DATA)
     251             :                 ODBC_REPORT_ERROR("SQLMoreResults return other data");
     252             : #endif
     253             : 
     254          64 :         CheckReturnCode(result, 0);
     255             : 
     256          64 :         CheckData("");
     257          64 :         ODBC_FREE();
     258             : }
     259             : 
     260             : static void
     261          60 : Test2(int nocount, int second_select)
     262             : {
     263             :         char sql[512];
     264             : 
     265          60 :         g_nocount = nocount;
     266          60 :         g_second_select = second_select;
     267             : 
     268             :         /* this test does not work with Sybase */
     269          60 :         if (!odbc_db_is_microsoft())
     270          12 :                 return;
     271             : 
     272          48 :         sprintf(sql, create_proc, nocount ? "     SET NOCOUNT ON\n" : "",
     273             :                 second_select ? "     SELECT 'Here is the last row' AS LastResult\n" : "");
     274          48 :         odbc_command(sql);
     275             : 
     276          48 :         Test(5);
     277             : 
     278          48 :         Test(11);
     279             : 
     280          48 :         odbc_command("DROP PROC #tmp1");
     281             : }
     282             : 
     283             : int
     284          10 : main(void)
     285             : {
     286          10 :         odbc_connect();
     287             : 
     288          10 :         Test2(0, 1);
     289             : 
     290          10 :         Test2(1, 1);
     291             : 
     292          10 :         odbc_disconnect();
     293             : 
     294          10 :         odbc_use_version3 = 1;
     295             : 
     296          10 :         odbc_connect();
     297             : 
     298          10 :         Test2(0, 1);
     299          10 :         Test2(1, 1);
     300             : 
     301          10 :         Test2(0, 0);
     302          10 :         Test2(1, 0);
     303             : 
     304          10 :         odbc_disconnect();
     305             : 
     306          10 :         printf("Done.\n");
     307             :         return 0;
     308             : }

Generated by: LCOV version 1.13