LCOV - code coverage report
Current view: top level - src/ctlib/unittests - cancel.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 65 82 79.3 %
Date: 2025-07-26 13:53:51 Functions: 3 3 100.0 %

          Line data    Source code
       1             : #include "common.h"
       2             : 
       3             : #include <freetds/time.h>
       4             : 
       5             : #include <sys/types.h>
       6             : 
       7             : #if HAVE_UNISTD_H
       8             : #include <unistd.h>
       9             : #endif /* HAVE_UNISTD_H */
      10             : 
      11             : #include <signal.h>
      12             : 
      13             : #include <freetds/macros.h>
      14             : 
      15             : #if defined(HAVE_ALARM) && defined(HAVE_SETITIMER)
      16             : 
      17             : /* protos */
      18             : static int do_fetch(CS_COMMAND * cmd, int *cnt);
      19             : 
      20             : /* Globals */
      21             : static volatile CS_COMMAND *g_cmd = NULL;
      22             : 
      23             : static void
      24          66 : catch_alrm(int sig_num TDS_UNUSED)
      25             : {
      26          66 :         signal(SIGALRM, catch_alrm);
      27             : 
      28          66 :         printf("- SIGALRM\n");
      29             : 
      30             :         /* Cancel current command */
      31          66 :         if (g_cmd)
      32          66 :                 ct_cancel(NULL, (CS_COMMAND *) g_cmd, CS_CANCEL_ATTN);
      33             : 
      34          66 :         fflush(stdout);
      35          66 : }
      36             : 
      37             : /* Testing: Test asynchronous ct_cancel() */
      38          10 : TEST_MAIN()
      39             : {
      40             :         CS_CONTEXT *ctx;
      41             :         CS_CONNECTION *conn;
      42             :         CS_COMMAND *cmd;
      43          10 :         int i, verbose = 0, cnt = 0;
      44             : 
      45             :         CS_RETCODE ret;
      46             :         CS_INT result_type;
      47             : 
      48             :         struct itimerval timer;
      49             :         char query[1024];
      50             : 
      51          10 :         unsigned clock = 200000;
      52             : 
      53          10 :         printf("%s: Check asynchronous called ct_cancel()\n", __FILE__);
      54             : 
      55             :         /* disable dump for this test, there are some issues with concurrent
      56             :          * execution of this test if logging is enabled. */
      57          10 :         unsetenv("TDSDUMP");
      58          10 :         unsetenv("TDSDUMPCONFIG");
      59             : 
      60             :         if (verbose) {
      61             :                 printf("Trying login\n");
      62             :         }
      63          10 :         check_call(try_ctlogin, (&ctx, &conn, &cmd, verbose));
      64             : 
      65             :         /* Create needed tables */
      66          10 :         check_call(run_command, (cmd, "CREATE TABLE #t0010 (id int, col1 varchar(255))"));
      67             : 
      68         110 :         for (i = 0; i < 10; i++) {
      69         100 :                 sprintf(query, "INSERT #t0010 (id, col1) values (%d, 'This is field no %d')", i, i);
      70             : 
      71         100 :                 check_call(run_command, (cmd, query));
      72             :         }
      73             : 
      74             :         /* Set SIGALRM signal handler */
      75          10 :         signal(SIGALRM, catch_alrm);
      76             : 
      77             :         for (;;) {
      78             :                 /* TODO better to use alarm AFTER ct_send ?? */
      79             :                 /* Set timer */
      80          10 :                 timer.it_interval.tv_sec = 0;
      81          10 :                 timer.it_interval.tv_usec = clock;
      82          10 :                 timer.it_value.tv_sec = 0;
      83          10 :                 timer.it_value.tv_usec = clock;
      84          10 :                 if (0 != setitimer(ITIMER_REAL, &timer, NULL)) {
      85           0 :                         fprintf(stderr, "Could not set realtime timer.\n");
      86           0 :                         return 1;
      87             :                 }
      88             : 
      89             :                 /* Issue a command returning many rows */
      90          10 :                 check_call(ct_command, 
      91             :                            (cmd, CS_LANG_CMD, "SELECT * FROM #t0010 t1, #t0010 t2, #t0010 t3, #t0010 t4", CS_NULLTERM, CS_UNUSED));
      92             : 
      93          10 :                 check_call(ct_send, (cmd));
      94             : 
      95             :                 /* Save a global reference for the interrupt handler */
      96          10 :                 g_cmd = cmd;
      97             : 
      98          30 :                 while ((ret = ct_results(cmd, &result_type)) == CS_SUCCEED) {
      99          10 :                         printf("More results?...\n");
     100          10 :                         if (result_type == CS_STATUS_RESULT)
     101           0 :                                 continue;
     102             : 
     103          10 :                         switch ((int) result_type) {
     104          10 :                         case CS_ROW_RESULT:
     105          10 :                                 printf("do_fetch() returned: %d\n", do_fetch(cmd, &cnt));
     106          10 :                                 break;
     107             :                         }
     108             :                 }
     109             : 
     110             :                 /* We should not have received all rows, as the alarm signal cancelled it... */
     111          10 :                 if (cnt < 10000)
     112             :                         break;
     113             : 
     114           0 :                 if (clock <= 5000) {
     115           0 :                         fprintf(stderr, "All rows read, this may not occur.\n");
     116           0 :                         return 1;
     117             :                 }
     118           0 :                 g_cmd = NULL;
     119           0 :                 clock /= 2;
     120             :         }
     121             : 
     122             :         /* Remove timer */
     123          10 :         timer.it_interval.tv_sec = 0;
     124          10 :         timer.it_interval.tv_usec = 0;
     125          10 :         timer.it_value.tv_sec = 0;
     126          10 :         timer.it_value.tv_usec = 0;
     127          10 :         if (0 != setitimer(ITIMER_REAL, &timer, NULL)) {
     128           0 :                 fprintf(stderr, "Could not remove realtime timer.\n");
     129           0 :                 return 1;
     130             :         }
     131             : 
     132             :         /*
     133             :          * Issue another command, this will be executed after a ct_cancel, 
     134             :          * to test if wire state is consistent 
     135             :          */
     136          10 :         check_call(ct_command, (cmd, CS_LANG_CMD, "SELECT * FROM #t0010 t1, #t0010 t2, #t0010 t3", CS_NULLTERM, CS_UNUSED));
     137             : 
     138          10 :         check_call(ct_send, (cmd));
     139             : 
     140          40 :         while ((ret = ct_results(cmd, &result_type)) == CS_SUCCEED) {
     141          20 :                 printf("More results?...\n");
     142          20 :                 if (result_type == CS_STATUS_RESULT)
     143           0 :                         continue;
     144             : 
     145          20 :                 switch ((int) result_type) {
     146          10 :                 case CS_ROW_RESULT:
     147          10 :                         printf("do_fetch() returned: %d\n", do_fetch(cmd, &cnt));
     148          10 :                         break;
     149             :                 }
     150             :         }
     151             : 
     152          10 :         if (1000 != cnt) {
     153             :                 /* This time, all rows must have been received */
     154           0 :                 fprintf(stderr, "Incorrect number of rows read.\n");
     155           0 :                 return 1;
     156             :         }
     157             : 
     158             :         if (verbose) {
     159             :                 printf("Trying logout\n");
     160             :         }
     161          10 :         check_call(try_ctlogout, (ctx, conn, cmd, verbose));
     162             : 
     163          10 :         printf("%s: asynchronous cancel test: PASSED\n", __FILE__);
     164             : 
     165          10 :         return 0;
     166             : }
     167             : 
     168             : static int
     169          20 : do_fetch(CS_COMMAND * cmd, int *cnt)
     170             : {
     171          20 :         CS_INT count, row_count = 0;
     172             :         CS_RETCODE ret;
     173             : 
     174       16395 :         while ((ret = ct_fetch(cmd, CS_UNUSED, CS_UNUSED, CS_UNUSED, &count)) == CS_SUCCEED) {
     175             :                 /* printf ("ct_fetch() == CS_SUCCEED\n"); */
     176       16355 :                 row_count += count;
     177             :         }
     178             : 
     179          20 :         (*cnt) = row_count;
     180          20 :         if (ret == CS_ROW_FAIL) {
     181           0 :                 fprintf(stderr, "ct_fetch() CS_ROW_FAIL on row %d.\n", row_count);
     182           0 :                 return 1;
     183          20 :         } else if (ret == CS_END_DATA) {
     184          10 :                 printf("do_fetch retrieved %d rows\n", row_count);
     185          10 :                 return 0;
     186          10 :         } else if (ret == CS_CMD_FAIL) {
     187           0 :                 printf("do_fetch(): command aborted after receiving %d rows\n", row_count);
     188           0 :                 return 0;
     189             :         } else {
     190          10 :                 fprintf(stderr, "ct_fetch() unexpected return %d on row %d.\n", ret, row_count);
     191          10 :                 return 1;
     192             :         }
     193             : }
     194             : 
     195             : #else
     196             : 
     197             : TEST_MAIN()
     198             : {
     199             :         return 0;
     200             : }
     201             : #endif
     202             : 

Generated by: LCOV version 1.13