Line data Source code
1 : /*
2 : * Purpose: Test handling of timeouts with callbacks
3 : */
4 :
5 : #include "common.h"
6 : #include <freetds/macros.h>
7 : #include <time.h>
8 :
9 : static int ntimeouts = 0, ncancels = 0;
10 : static int max_timeouts = 2, timeout_seconds = 2, cancel_timeout = 10;
11 : static time_t start_time;
12 : static const char sql[] =
13 : "select getdate() as 'begintime'\n"
14 : "waitfor delay '00:00:30'\n"
15 : "select getdate() as 'endtime'";
16 :
17 : static int
18 48 : on_interrupt(CS_CONNECTION *con TDS_UNUSED)
19 : {
20 48 : printf("In on_interrupt, %ld seconds elapsed.\n", (long int) (time(NULL) - start_time));
21 48 : return CS_INT_CONTINUE;
22 : }
23 :
24 : static int
25 28 : on_client_msg(CS_CONTEXT *ctx, CS_CONNECTION *con, CS_CLIENTMSG *errmsg)
26 : {
27 28 : if (errmsg->msgnumber == 20003) { /* TDSETIME */
28 24 : fprintf(stderr, "%d timeout(s) received in %ld seconds; ", ++ntimeouts, (long int) (time(NULL) - start_time));
29 24 : if (ntimeouts > max_timeouts) {
30 8 : if (++ncancels > 1) {
31 0 : fputs("could not time out cleanly;"
32 : " breaking connection.\n", stderr);
33 0 : ncancels = 0;
34 0 : return CS_FAIL;
35 : }
36 8 : fputs("lost patience;"
37 : " cancelling (allowing 10 seconds)\n", stderr);
38 8 : check_call(ct_con_props, (con, CS_SET, CS_TIMEOUT, &cancel_timeout, CS_UNUSED, NULL));
39 8 : return CS_FAIL;
40 : }
41 16 : fputs("continuing to wait.\n", stderr);
42 16 : return CS_SUCCEED;
43 : }
44 4 : return clientmsg_cb(ctx, con, errmsg);
45 : }
46 :
47 : static void
48 8 : test(CS_CONNECTION *con, CS_COMMAND *cmd)
49 : {
50 8 : CS_INT result_type = 0;
51 : CS_RETCODE ret;
52 :
53 8 : ntimeouts = 0;
54 8 : ncancels = 0;
55 :
56 8 : printf("Using %d-second query timeouts.\n", timeout_seconds);
57 :
58 8 : check_call(ct_con_props, (con, CS_SET, CS_TIMEOUT, &timeout_seconds, CS_UNUSED, NULL));
59 :
60 : /* Send something that will take a while to execute. */
61 8 : printf("Issuing a query that will take 30 seconds.\n");
62 8 : check_call(ct_command, (cmd, CS_LANG_CMD, (void *) sql, sizeof(sql) - 1, CS_UNUSED));
63 :
64 8 : start_time = time(NULL); /* Track for reporting purposes. */
65 8 : ntimeouts = 0;
66 8 : check_call(ct_callback, (NULL, con, CS_SET, CS_CLIENTMSG_CB, &on_client_msg));
67 8 : check_call(ct_callback, (NULL, con, CS_SET, CS_INTERRUPT_CB, &on_interrupt));
68 :
69 8 : check_call(ct_send,(cmd));
70 :
71 8 : ret = ct_results(cmd, &result_type);
72 8 : if (ret == CS_SUCCEED) {
73 0 : fprintf(stderr, "Query unexpectedly succeeded, with result type %d.\n", result_type);
74 : } else {
75 8 : printf("Query failed as expected, with return code %d.\n", ret);
76 : }
77 8 : }
78 :
79 : int
80 8 : main(int argc, char **argv)
81 : {
82 : CS_CONTEXT *ctx;
83 : CS_CONNECTION *con;
84 : CS_COMMAND *cmd;
85 :
86 8 : if (CS_SUCCEED != try_ctlogin_with_options(argc, argv, &ctx, &con, &cmd, false)) {
87 0 : fputs("Customary setup failed.\n", stderr);
88 0 : return 1;
89 : }
90 8 : test(con, cmd);
91 8 : try_ctlogout(ctx, con, cmd, false);
92 8 : return 0;
93 : }
|