Line data Source code
1 : #include "common.h"
2 :
3 : #if HAVE_UNISTD_H
4 : #include <unistd.h>
5 : #endif
6 :
7 : #include <freetds/replacements.h>
8 : #include <freetds/macros.h>
9 :
10 : #ifdef TDS_STATIC_CAST
11 : #include "ctlib.h"
12 : #endif
13 :
14 : static const char *BASENAME = NULL;
15 :
16 : static const char *PWD = DEFAULT_PWD_PATH;
17 :
18 : int cslibmsg_cb_invoked = 0;
19 : int clientmsg_cb_invoked = 0;
20 : int servermsg_cb_invoked = 0;
21 : bool error_to_stdout = false;
22 :
23 : ct_message ct_last_message;
24 :
25 : static CS_RETCODE continue_logging_in(CS_CONTEXT ** ctx, CS_CONNECTION ** conn, CS_COMMAND ** cmd, int verbose);
26 :
27 : CS_RETCODE
28 10 : read_login_info(void)
29 : {
30 1340 : const char *s = read_login_info_base(&common_pwd, DEFAULT_PWD_PATH);
31 :
32 1310 : return s ? CS_SUCCEED : CS_FAIL;
33 : }
34 :
35 : static CS_RETCODE
36 30 : establish_login(int argc, char **argv)
37 : {
38 : extern char *optarg;
39 : extern int optind;
40 : int ch;
41 :
42 30 : BASENAME = basename((char *)argv[0]);
43 :
44 : /* process command line options (handy for manual testing) */
45 60 : while ((ch = getopt(argc, argv, "U:P:S:D:f:m:v")) != -1) {
46 0 : switch (ch) {
47 0 : case 'U':
48 0 : strlcpy(common_pwd.user, optarg, sizeof(common_pwd.user));
49 0 : break;
50 0 : case 'P':
51 0 : strlcpy(common_pwd.password, optarg, sizeof(common_pwd.password));
52 0 : break;
53 0 : case 'S':
54 0 : strlcpy(common_pwd.server, optarg, sizeof(common_pwd.server));
55 0 : break;
56 0 : case 'D':
57 0 : strlcpy(common_pwd.database, optarg, sizeof(common_pwd.database));
58 0 : break;
59 0 : case 'f': /* override default PWD file */
60 0 : PWD = strdup(optarg);
61 0 : break;
62 0 : case 'm':
63 0 : common_pwd.maxlength = (CS_INT) strtol(optarg, NULL, 10);
64 0 : case 'v':
65 0 : common_pwd.fverbose = 1;
66 0 : break;
67 0 : case '?':
68 : default:
69 0 : fprintf(stderr, "usage: %s [-v] [-f PWD]\n"
70 : " [-U username] [-P password]\n"
71 : " [-S servername] [-D database]\n"
72 : , BASENAME);
73 0 : exit(1);
74 : }
75 : }
76 30 : read_login_info();
77 :
78 60 : return (*common_pwd.user && *common_pwd.server && *common_pwd.database)
79 60 : ? CS_SUCCEED : CS_FAIL;
80 : }
81 :
82 : CS_RETCODE
83 30 : try_ctlogin_with_options(int argc, char **argv, CS_CONTEXT ** ctx, CS_CONNECTION ** conn, CS_COMMAND ** cmd, int verbose)
84 : {
85 : CS_RETCODE ret;
86 :
87 30 : if ((ret = establish_login(argc, argv)) != CS_SUCCEED) {
88 0 : if (verbose) {
89 0 : fprintf(stderr, "read_login_info() failed!\n");
90 : }
91 : return ret;
92 : }
93 30 : return continue_logging_in(ctx, conn, cmd, verbose);
94 : }
95 :
96 : /* old way: because I'm too lazy to change every unit test */
97 : CS_RETCODE
98 1300 : try_ctlogin(CS_CONTEXT ** ctx, CS_CONNECTION ** conn, CS_COMMAND ** cmd, int verbose)
99 : {
100 : CS_RETCODE ret;
101 :
102 1300 : if ((ret = read_login_info()) != CS_SUCCEED) {
103 0 : if (verbose) {
104 0 : fprintf(stderr, "read_login_info() failed!\n");
105 : }
106 : return ret;
107 : }
108 1300 : return continue_logging_in(ctx, conn, cmd, verbose);
109 : }
110 :
111 : CS_RETCODE
112 1330 : continue_logging_in(CS_CONTEXT ** ctx, CS_CONNECTION ** conn, CS_COMMAND ** cmd, int verbose)
113 : {
114 : CS_RETCODE ret;
115 : char query[512+10];
116 1330 : CS_INT bulk_enabled = CS_TRUE;
117 : #ifdef TDS_STATIC_CAST
118 : TDSCONTEXT *tds_ctx;
119 : #endif
120 :
121 1330 : ret = cs_ctx_alloc(CS_VERSION_100, ctx);
122 1330 : if (ret != CS_SUCCEED) {
123 0 : if (verbose) {
124 0 : fprintf(stderr, "Context Alloc failed!\n");
125 : }
126 : return ret;
127 : }
128 :
129 : #ifdef TDS_STATIC_CAST
130 : /* Force default date format, some tests rely on it */
131 1330 : tds_ctx = (TDSCONTEXT *) (*ctx)->tds_ctx;
132 1330 : if (tds_ctx && tds_ctx->locale && tds_ctx->locale->datetime_fmt) {
133 1330 : free(tds_ctx->locale->datetime_fmt);
134 1330 : tds_ctx->locale->datetime_fmt = strdup("%b %d %Y %I:%M%p");
135 : }
136 : #endif
137 :
138 1330 : ret = ct_init(*ctx, CS_VERSION_100);
139 1330 : if (ret != CS_SUCCEED) {
140 0 : if (verbose) {
141 0 : fprintf(stderr, "Library Init failed!\n");
142 : }
143 : return ret;
144 : }
145 1330 : if ((ret = ct_callback(*ctx, NULL, CS_SET, CS_CLIENTMSG_CB,
146 : (CS_VOID*) clientmsg_cb)) != CS_SUCCEED) {
147 0 : fprintf(stderr, "ct_callback() failed\n");
148 0 : return ret;
149 : }
150 1330 : if ((ret = ct_callback(*ctx, NULL, CS_SET, CS_SERVERMSG_CB, servermsg_cb)) != CS_SUCCEED) {
151 0 : fprintf(stderr, "ct_callback() failed\n");
152 0 : return ret;
153 : }
154 1330 : ret = ct_con_alloc(*ctx, conn);
155 1330 : if (ret != CS_SUCCEED) {
156 0 : if (verbose) {
157 0 : fprintf(stderr, "Connect Alloc failed!\n");
158 : }
159 : return ret;
160 : }
161 1330 : ret = ct_con_props(*conn, CS_SET, CS_USERNAME, common_pwd.user, CS_NULLTERM, NULL);
162 1330 : if (ret != CS_SUCCEED) {
163 0 : if (verbose) {
164 0 : fprintf(stderr, "ct_con_props() SET USERNAME failed!\n");
165 : }
166 : return ret;
167 : }
168 1330 : ret = ct_con_props(*conn, CS_SET, CS_PASSWORD, common_pwd.password, CS_NULLTERM, NULL);
169 1330 : if (ret != CS_SUCCEED) {
170 0 : if (verbose) {
171 0 : fprintf(stderr, "ct_con_props() SET PASSWORD failed!\n");
172 : }
173 : return ret;
174 : }
175 1330 : ret = ct_con_props(*conn, CS_SET, CS_BULK_LOGIN, &bulk_enabled, CS_UNUSED, NULL);
176 1330 : if (ret != CS_SUCCEED) {
177 0 : if (verbose) {
178 0 : fprintf(stderr, "ct_con_props() SET BULK failed!\n");
179 : }
180 : return ret;
181 : }
182 :
183 1330 : printf("connecting as %s to %s.%s\n", common_pwd.user, common_pwd.server, common_pwd.database);
184 :
185 1330 : ret = ct_connect(*conn, common_pwd.server, CS_NULLTERM);
186 1330 : if (ret != CS_SUCCEED) {
187 0 : if (verbose) {
188 0 : fprintf(stderr, "Connection failed!\n");
189 : }
190 0 : ct_con_drop(*conn);
191 0 : *conn = NULL;
192 0 : ct_exit(*ctx, CS_UNUSED);
193 0 : cs_ctx_drop(*ctx);
194 0 : *ctx = NULL;
195 0 : return ret;
196 : }
197 1330 : ret = ct_cmd_alloc(*conn, cmd);
198 1330 : if (ret != CS_SUCCEED) {
199 0 : if (verbose) {
200 0 : fprintf(stderr, "Command Alloc failed!\n");
201 : }
202 0 : ct_con_drop(*conn);
203 0 : *conn = NULL;
204 0 : ct_exit(*ctx, CS_UNUSED);
205 0 : cs_ctx_drop(*ctx);
206 0 : *ctx = NULL;
207 0 : return ret;
208 : }
209 :
210 1330 : sprintf(query, "use %s", common_pwd.database);
211 :
212 1330 : ret = run_command(*cmd, query);
213 1330 : if (ret != CS_SUCCEED)
214 : return ret;
215 :
216 1330 : return CS_SUCCEED;
217 : }
218 :
219 :
220 : CS_RETCODE
221 1330 : try_ctlogout(CS_CONTEXT * ctx, CS_CONNECTION * conn, CS_COMMAND * cmd, int verbose)
222 : {
223 : CS_RETCODE ret;
224 :
225 1330 : ret = ct_cancel(conn, NULL, CS_CANCEL_ALL);
226 1330 : if (ret != CS_SUCCEED) {
227 0 : if (verbose) {
228 0 : fprintf(stderr, "ct_cancel() failed!\n");
229 : }
230 : return ret;
231 : }
232 1330 : ct_cmd_drop(cmd);
233 1330 : ct_close(conn, CS_UNUSED);
234 1330 : ct_con_drop(conn);
235 1330 : ct_exit(ctx, CS_UNUSED);
236 1330 : cs_ctx_drop(ctx);
237 :
238 1330 : return CS_SUCCEED;
239 : }
240 :
241 : /* Run commands from which we expect no results returned */
242 : CS_RETCODE
243 2456 : run_command(CS_COMMAND * cmd, const char *sql)
244 : {
245 : CS_RETCODE ret, results_ret;
246 : CS_INT result_type;
247 :
248 2456 : if (cmd == NULL) {
249 : return CS_FAIL;
250 : }
251 :
252 2456 : ret = ct_command(cmd, CS_LANG_CMD, (void *) sql, CS_NULLTERM, CS_UNUSED);
253 2456 : if (ret != CS_SUCCEED) {
254 0 : fprintf(stderr, "ct_command() failed\n");
255 0 : return ret;
256 : }
257 2456 : ret = ct_send(cmd);
258 2456 : if (ret != CS_SUCCEED) {
259 2 : fprintf(stderr, "ct_send() failed\n");
260 2 : return ret;
261 : }
262 : ret = CS_SUCCEED;
263 7556 : while ((results_ret = ct_results(cmd, &result_type)) == CS_SUCCEED) {
264 5102 : switch (result_type) {
265 : case CS_CMD_SUCCEED:
266 : break;
267 : case CS_CMD_DONE:
268 : break;
269 66 : case CS_CMD_FAIL:
270 66 : fprintf(stderr, "ct_results() result_type CS_CMD_FAIL.\n");
271 66 : ret = CS_FAIL;
272 66 : break;
273 0 : default:
274 0 : fprintf(stderr, "ct_results() unexpected result_type.\n");
275 0 : return CS_FAIL;
276 : }
277 : }
278 2454 : switch (results_ret) {
279 : case CS_END_RESULTS:
280 : break;
281 0 : case CS_FAIL:
282 0 : fprintf(stderr, "ct_results() failed.\n");
283 0 : return CS_FAIL;
284 : break;
285 0 : default:
286 0 : fprintf(stderr, "ct_results() unexpected return.\n");
287 0 : return CS_FAIL;
288 : }
289 :
290 : return ret;
291 : }
292 :
293 : CS_INT
294 250 : cslibmsg_cb(CS_CONTEXT * connection TDS_UNUSED, CS_CLIENTMSG * errmsg)
295 : {
296 250 : cslibmsg_cb_invoked++;
297 :
298 : ct_reset_last_message();
299 250 : ct_last_message.type = CTMSG_CSLIB;
300 250 : ct_last_message.number = errmsg->msgnumber;
301 250 : strlcpy(ct_last_message.text, errmsg->msgstring, sizeof(ct_last_message.text));
302 :
303 250 : fprintf(stderr, "\nCS-Library Message:\n");
304 1000 : fprintf(stderr, "number %#x layer %d origin %d severity %d number %d\n",
305 : errmsg->msgnumber,
306 500 : (int) CS_LAYER(errmsg->msgnumber), (int) CS_ORIGIN(errmsg->msgnumber),
307 500 : (int) CS_SEVERITY(errmsg->msgnumber), (int) CS_NUMBER(errmsg->msgnumber));
308 250 : fprintf(stderr, "msgstring: %s\n", errmsg->msgstring);
309 250 : fprintf(stderr, "osstring: %s\n", (errmsg->osstringlen > 0)
310 : ? errmsg->osstring : "(null)");
311 250 : return CS_SUCCEED;
312 : }
313 :
314 :
315 :
316 : static CS_RETCODE
317 539 : clientmsg_gen_cb(CS_CONTEXT * context, CS_CONNECTION * connection, CS_CLIENTMSG * errmsg,
318 : ct_message_type msg_type)
319 : {
320 539 : FILE *out = error_to_stdout ? stdout: stderr;
321 :
322 539 : clientmsg_cb_invoked++;
323 :
324 : ct_reset_last_message();
325 539 : ct_last_message.type = msg_type;
326 539 : ct_last_message.number = errmsg->msgnumber;
327 539 : strlcpy(ct_last_message.text, errmsg->msgstring, sizeof(ct_last_message.text));
328 :
329 539 : fprintf(out, "\nOpen Client Message%s: %p %p\n",
330 : msg_type == CTMSG_CLIENT ? "" : " #2", context, connection);
331 2156 : fprintf(out, "number %#x layer %d origin %d severity %d number %d\n",
332 : errmsg->msgnumber,
333 1078 : (int) CS_LAYER(errmsg->msgnumber), (int) CS_ORIGIN(errmsg->msgnumber),
334 1078 : (int) CS_SEVERITY(errmsg->msgnumber), (int) CS_NUMBER(errmsg->msgnumber));
335 539 : fprintf(out, "msgstring: %s\n", errmsg->msgstring);
336 539 : fprintf(out, "osstring: %s\n", (errmsg->osstringlen > 0)
337 : ? errmsg->osstring : "(null)");
338 539 : fflush(out);
339 539 : return CS_SUCCEED;
340 : }
341 :
342 : CS_RETCODE
343 89 : clientmsg_cb(CS_CONTEXT * context, CS_CONNECTION * connection, CS_CLIENTMSG * errmsg)
344 : {
345 89 : return clientmsg_gen_cb(context, connection, errmsg, CTMSG_CLIENT);
346 : }
347 :
348 : CS_RETCODE
349 450 : clientmsg_cb2(CS_CONTEXT * context, CS_CONNECTION * connection, CS_CLIENTMSG * errmsg)
350 : {
351 450 : return clientmsg_gen_cb(context, connection, errmsg, CTMSG_CLIENT2);
352 : }
353 :
354 : CS_RETCODE
355 4114 : servermsg_cb(CS_CONTEXT * context TDS_UNUSED, CS_CONNECTION * connection TDS_UNUSED, CS_SERVERMSG * srvmsg)
356 : {
357 4114 : FILE *out = error_to_stdout ? stdout: stderr;
358 :
359 4114 : servermsg_cb_invoked++;
360 :
361 : ct_reset_last_message();
362 4114 : ct_last_message.type = CTMSG_SERVER;
363 4114 : ct_last_message.number = srvmsg->msgnumber;
364 4114 : strlcpy(ct_last_message.text, srvmsg->text, sizeof(ct_last_message.text));
365 :
366 4114 : if (srvmsg->msgnumber == 5701 || srvmsg->msgnumber == 5703) {
367 3724 : fprintf(out, "%s\n", srvmsg->text);
368 3724 : fflush(out);
369 3724 : return CS_SUCCEED;
370 : }
371 :
372 390 : fprintf(out, "\nServer message:\n");
373 780 : fprintf(out, "%s Message %d severity %d state %d line %d:\n",
374 390 : srvmsg->svrnlen > 0? srvmsg->svrname : "Server",
375 : srvmsg->msgnumber, srvmsg->severity, srvmsg->state, srvmsg->line);
376 390 : if (srvmsg->proclen > 0)
377 24 : fprintf(out, "proc %s: ", srvmsg->proc);
378 390 : fprintf(out, "\t\"%s\"\n", srvmsg->text);
379 :
380 390 : fflush(out);
381 390 : return CS_SUCCEED;
382 : }
383 :
384 : const char *
385 488 : res_type_str(CS_RETCODE ret)
386 : {
387 : static char str[64];
388 :
389 : #define S(s) case s: return #s;
390 488 : switch ((int) ret) {
391 : S(CS_ROW_RESULT)
392 0 : S(CS_PARAM_RESULT)
393 82 : S(CS_STATUS_RESULT)
394 0 : S(CS_MSG_RESULT)
395 80 : S(CS_CMD_SUCCEED)
396 186 : S(CS_CMD_DONE)
397 12 : S(CS_CMD_FAIL)
398 24 : S(CS_COMPUTE_RESULT)
399 : #undef S
400 : }
401 :
402 0 : sprintf(str, "?? (%d)", (int) ret);
403 0 : return str;
404 : }
405 :
406 : void
407 9996 : _check_ret(const char *name, CS_RETCODE ret, int line)
408 : {
409 9996 : if (ret != CS_SUCCEED) {
410 0 : fprintf(stderr, "%s():%d: failed\n", name, line);
411 0 : exit(1);
412 : }
413 9996 : }
414 :
415 : void
416 770 : ct_reset_last_message(void)
417 : {
418 5673 : memset(&ct_last_message, 0, sizeof(ct_last_message));
419 770 : }
|