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 60 : on_interrupt(CS_CONNECTION *con TDS_UNUSED)
19 : {
20 60 : printf("In on_interrupt, %ld seconds elapsed.\n", (long int) (time(NULL) - start_time));
21 60 : return CS_INT_CONTINUE;
22 : }
23 :
24 : static int
25 35 : on_client_msg(CS_CONTEXT *ctx, CS_CONNECTION *con, CS_CLIENTMSG *errmsg)
26 : {
27 35 : if (errmsg->msgnumber == 20003) { /* TDSETIME */
28 30 : fprintf(stderr, "%d timeout(s) received in %ld seconds; ", ++ntimeouts, (long int) (time(NULL) - start_time));
29 30 : if (ntimeouts > max_timeouts) {
30 10 : 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 10 : fputs("lost patience;"
37 : " cancelling (allowing 10 seconds)\n", stderr);
38 10 : check_call(ct_con_props, (con, CS_SET, CS_TIMEOUT, &cancel_timeout, CS_UNUSED, NULL));
39 10 : return CS_FAIL;
40 : }
41 20 : fputs("continuing to wait.\n", stderr);
42 20 : return CS_SUCCEED;
43 : }
44 5 : return clientmsg_cb(ctx, con, errmsg);
45 : }
46 :
47 : static void
48 10 : test(CS_CONNECTION *con, CS_COMMAND *cmd)
49 : {
50 10 : CS_INT result_type = 0;
51 : CS_RETCODE ret;
52 :
53 10 : ntimeouts = 0;
54 10 : ncancels = 0;
55 :
56 10 : printf("Using %d-second query timeouts.\n", timeout_seconds);
57 :
58 10 : 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 10 : printf("Issuing a query that will take 30 seconds.\n");
62 10 : check_call(ct_command, (cmd, CS_LANG_CMD, (void *) sql, sizeof(sql) - 1, CS_UNUSED));
63 :
64 10 : start_time = time(NULL); /* Track for reporting purposes. */
65 10 : ntimeouts = 0;
66 10 : check_call(ct_callback, (NULL, con, CS_SET, CS_CLIENTMSG_CB, &on_client_msg));
67 10 : check_call(ct_callback, (NULL, con, CS_SET, CS_INTERRUPT_CB, &on_interrupt));
68 :
69 10 : check_call(ct_send,(cmd));
70 :
71 10 : ret = ct_results(cmd, &result_type);
72 10 : if (ret == CS_SUCCEED) {
73 0 : fprintf(stderr, "Query unexpectedly succeeded, with result type %d.\n", result_type);
74 : } else {
75 10 : printf("Query failed as expected, with return code %d.\n", ret);
76 : }
77 10 : }
78 :
79 : int
80 10 : main(int argc, char **argv)
81 : {
82 : CS_CONTEXT *ctx;
83 : CS_CONNECTION *con;
84 : CS_COMMAND *cmd;
85 :
86 10 : 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 10 : test(con, cmd);
91 10 : try_ctlogout(ctx, con, cmd, false);
92 10 : return 0;
93 : }
|