1 /* Testing SQLCancel() */
2
3 #include "common.h"
4
5 #include <signal.h>
6
7 #if HAVE_UNISTD_H
8 #include <unistd.h>
9 #endif /* HAVE_UNISTD_H */
10
11 #include <freetds/thread.h>
12 #include <freetds/utils.h>
13 #include <freetds/replacements.h>
14
15 #if TDS_HAVE_MUTEX
16
17 #ifdef _WIN32
18 #undef HAVE_ALARM
19 #endif
20
21 static SQLTCHAR sqlstate[SQL_SQLSTATE_SIZE + 1];
22 static tds_mutex mtx;
23
24 static void
getErrorInfo(SQLSMALLINT sqlhdltype,SQLHANDLE sqlhandle)25 getErrorInfo(SQLSMALLINT sqlhdltype, SQLHANDLE sqlhandle)
26 {
27 SQLINTEGER naterror = 0;
28 SQLTCHAR msgtext[SQL_MAX_MESSAGE_LENGTH + 1];
29 SQLSMALLINT msgtextl = 0;
30
31 msgtext[0] = 0;
32 SQLGetDiagRec(sqlhdltype,
33 (SQLHANDLE) sqlhandle,
34 1,
35 sqlstate,
36 &naterror,
37 msgtext, (SQLSMALLINT) TDS_VECTOR_SIZE(msgtext), &msgtextl);
38 sqlstate[TDS_VECTOR_SIZE(sqlstate)-1] = 0;
39 fprintf(stderr, "Diagnostic info:\n");
40 fprintf(stderr, " SQL State: %s\n", C(sqlstate));
41 fprintf(stderr, " SQL code : %d\n", (int) naterror);
42 fprintf(stderr, " Message : %s\n", C(msgtext));
43 }
44
45 static void
exit_forced(int s)46 exit_forced(int s)
47 {
48 exit(1);
49 }
50
51 #if HAVE_ALARM
52 static void
sigalrm_handler(int s)53 sigalrm_handler(int s)
54 {
55 printf(">>>> SQLCancel() ...\n");
56 CHKCancel("S");
57 printf(">>>> ... SQLCancel done\n");
58
59 alarm(4);
60 signal(SIGALRM, exit_forced);
61 }
62 #else
63 #define alarm(x) return;
64 #define signal(sig,h)
65 #endif
66
67 volatile int exit_thread;
68
TDS_THREAD_PROC_DECLARE(wait_thread_proc,arg)69 static TDS_THREAD_PROC_DECLARE(wait_thread_proc, arg)
70 {
71 int n;
72
73 tds_sleep_s(4);
74
75 printf(">>>> SQLCancel() ...\n");
76 CHKCancel("S");
77 printf(">>>> ... SQLCancel done\n");
78
79 for (n = 0; n < 4; ++n) {
80 tds_sleep_s(1);
81 tds_mutex_lock(&mtx);
82 if (exit_thread) {
83 tds_mutex_unlock(&mtx);
84 return TDS_THREAD_RESULT(0);
85 }
86 tds_mutex_unlock(&mtx);
87 }
88
89 exit_forced(0);
90 return TDS_THREAD_RESULT(0);
91 }
92
93 static void
Test(int use_threads,int return_data)94 Test(int use_threads, int return_data)
95 {
96 tds_thread wait_thread;
97
98 #if !HAVE_ALARM
99 if (!use_threads) return;
100 #endif
101
102 printf("testing with %s\n", use_threads ? "threads" : "signals");
103 printf(">> Wait 5 minutes...\n");
104 if (!use_threads) {
105 alarm(4);
106 signal(SIGALRM, sigalrm_handler);
107 } else {
108 int err;
109
110 exit_thread = 0;
111 err = tds_thread_create(&wait_thread, wait_thread_proc, NULL);
112 if (err != 0) {
113 perror("tds_thread_create");
114 exit(1);
115 }
116 }
117 if (!return_data)
118 CHKExecDirect(T("WAITFOR DELAY '000:05:00'"), SQL_NTS, "E");
119 else
120 odbc_command2("SELECT MAX(p1.k + p2.k * p3.k ^ p4.k) FROM tab1 p1, tab1 p2, tab1 p3, tab1 p4", "E");
121
122 tds_mutex_lock(&mtx);
123 exit_thread = 1;
124 tds_mutex_unlock(&mtx);
125 if (!use_threads) {
126 alarm(0);
127 } else {
128 tds_thread_join(wait_thread, NULL);
129 }
130 getErrorInfo(SQL_HANDLE_STMT, odbc_stmt);
131 if (strcmp(C(sqlstate), "HY008") != 0) {
132 fprintf(stderr, "Unexpected sql state returned\n");
133 odbc_disconnect();
134 exit(1);
135 }
136
137 odbc_reset_statement();
138
139 odbc_command("SELECT name FROM sysobjects WHERE 0=1");
140 }
141
142 int
main(int argc,char ** argv)143 main(int argc, char **argv)
144 {
145 if (tds_mutex_init(&mtx))
146 return 1;
147
148 if (odbc_read_login_info())
149 exit(1);
150
151 /*
152 * prepare our odbcinst.ini
153 * is better to do it before connect cause uniODBC cache INIs
154 * the name must be odbcinst.ini cause unixODBC accept only this name
155 */
156 if (odbc_driver[0]) {
157 FILE *f = fopen("odbcinst.ini", "w");
158
159 if (f) {
160 fprintf(f, "[FreeTDS]\nDriver = %s\nThreading = 0\n", odbc_driver);
161 fclose(f);
162 /* force iODBC */
163 setenv("ODBCINSTINI", "./odbcinst.ini", 1);
164 setenv("SYSODBCINSTINI", "./odbcinst.ini", 1);
165 /* force unixODBC (only directory) */
166 setenv("ODBCSYSINI", ".", 1);
167 }
168 }
169
170 odbc_use_version3 = 1;
171 odbc_connect();
172
173 odbc_command("IF OBJECT_ID('tab1') IS NOT NULL DROP TABLE tab1");
174 odbc_command("CREATE TABLE tab1 ( k INT, vc VARCHAR(200) )");
175
176 printf(">> Creating tab1...\n");
177 odbc_command("DECLARE @i INT\n"
178 "SET @i = 1\n"
179 "WHILE @i <= 2000 BEGIN\n"
180 "INSERT INTO tab1 VALUES ( @i, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' )\n"
181 "SET @i = @i + 1\n"
182 "END");
183 while (CHKMoreResults("SNo") == SQL_SUCCESS)
184 continue;
185 printf(">> ...done.\n");
186
187 odbc_reset_statement();
188
189 Test(0, 0);
190 Test(1, 0);
191 Test(0, 1);
192 Test(1, 1);
193
194 odbc_command("DROP TABLE tab1");
195
196 odbc_disconnect();
197 return 0;
198 }
199
200 #else
201 int
main(void)202 main(void)
203 {
204 printf("Not possible for this platform.\n");
205 return 0;
206 }
207 #endif
208
209