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

Generated by: LCOV version 1.13