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 :
|