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