1 | /* |
2 | Copyright 2011 Kristian Nielsen and Monty Program Ab. |
3 | |
4 | This file is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Lesser General Public |
6 | License as published by the Free Software Foundation; either |
7 | version 2.1 of the License, or (at your option) any later version. |
8 | |
9 | This library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU General Public License |
15 | along with this. If not, see <http://www.gnu.org/licenses/>. |
16 | */ |
17 | |
18 | |
19 | #ifndef __WIN__ |
20 | #include <poll.h> |
21 | #else |
22 | #include <WinSock2.h> |
23 | #endif |
24 | |
25 | #include <stdlib.h> |
26 | #include <stdio.h> |
27 | #include <mysql.h> |
28 | |
29 | #define SL(s) (s), sizeof(s) |
30 | |
31 | static const char *my_groups[]= { "client" , NULL }; |
32 | |
33 | static int |
34 | wait_for_mysql(MYSQL *mysql, int status) |
35 | { |
36 | #ifdef __WIN__ |
37 | fd_set rs, ws, es; |
38 | int res; |
39 | struct timeval tv, *timeout; |
40 | my_socket s= mysql_get_socket(mysql); |
41 | FD_ZERO(&rs); |
42 | FD_ZERO(&ws); |
43 | FD_ZERO(&es); |
44 | if (status & MYSQL_WAIT_READ) |
45 | FD_SET(s, &rs); |
46 | if (status & MYSQL_WAIT_WRITE) |
47 | FD_SET(s, &ws); |
48 | if (status & MYSQL_WAIT_EXCEPT) |
49 | FD_SET(s, &es); |
50 | if (status & MYSQL_WAIT_TIMEOUT) |
51 | { |
52 | tv.tv_sec= mysql_get_timeout_value(mysql); |
53 | tv.tv_usec= 0; |
54 | timeout= &tv; |
55 | } |
56 | else |
57 | timeout= NULL; |
58 | res= select(1, &rs, &ws, &es, timeout); |
59 | if (res == 0) |
60 | return MYSQL_WAIT_TIMEOUT; |
61 | else if (res == SOCKET_ERROR) |
62 | { |
63 | /* |
64 | In a real event framework, we should handle errors and re-try the select. |
65 | */ |
66 | return MYSQL_WAIT_TIMEOUT; |
67 | } |
68 | else |
69 | { |
70 | int status= 0; |
71 | if (FD_ISSET(s, &rs)) |
72 | status|= MYSQL_WAIT_READ; |
73 | if (FD_ISSET(s, &ws)) |
74 | status|= MYSQL_WAIT_WRITE; |
75 | if (FD_ISSET(s, &es)) |
76 | status|= MYSQL_WAIT_EXCEPT; |
77 | return status; |
78 | } |
79 | #else |
80 | struct pollfd pfd; |
81 | int timeout; |
82 | int res; |
83 | |
84 | pfd.fd= mysql_get_socket(mysql); |
85 | pfd.events= |
86 | (status & MYSQL_WAIT_READ ? POLLIN : 0) | |
87 | (status & MYSQL_WAIT_WRITE ? POLLOUT : 0) | |
88 | (status & MYSQL_WAIT_EXCEPT ? POLLPRI : 0); |
89 | if (status & MYSQL_WAIT_TIMEOUT) |
90 | timeout= 1000*mysql_get_timeout_value(mysql); |
91 | else |
92 | timeout= -1; |
93 | res= poll(&pfd, 1, timeout); |
94 | if (res == 0) |
95 | return MYSQL_WAIT_TIMEOUT; |
96 | else if (res < 0) |
97 | { |
98 | /* |
99 | In a real event framework, we should handle EINTR and re-try the poll. |
100 | */ |
101 | return MYSQL_WAIT_TIMEOUT; |
102 | } |
103 | else |
104 | { |
105 | int status= 0; |
106 | if (pfd.revents & POLLIN) |
107 | status|= MYSQL_WAIT_READ; |
108 | if (pfd.revents & POLLOUT) |
109 | status|= MYSQL_WAIT_WRITE; |
110 | if (pfd.revents & POLLPRI) |
111 | status|= MYSQL_WAIT_EXCEPT; |
112 | return status; |
113 | } |
114 | #endif |
115 | } |
116 | |
117 | static void |
118 | fatal(MYSQL *mysql, const char *msg) |
119 | { |
120 | fprintf(stderr, "%s: %s\n" , msg, mysql_error(mysql)); |
121 | exit(1); |
122 | } |
123 | |
124 | static void |
125 | doit(const char *host, const char *user, const char *password) |
126 | { |
127 | int err; |
128 | MYSQL mysql, *ret; |
129 | MYSQL_RES *res; |
130 | MYSQL_ROW row; |
131 | int status; |
132 | |
133 | mysql_init(&mysql); |
134 | mysql_options(&mysql, MYSQL_OPT_NONBLOCK, 0); |
135 | mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "myapp" ); |
136 | |
137 | /* Returns 0 when done, else flag for what to wait for when need to block. */ |
138 | status= mysql_real_connect_start(&ret, &mysql, host, user, password, NULL, |
139 | 0, NULL, 0); |
140 | while (status) |
141 | { |
142 | status= wait_for_mysql(&mysql, status); |
143 | status= mysql_real_connect_cont(&ret, &mysql, status); |
144 | } |
145 | |
146 | if (!ret) |
147 | fatal(&mysql, "Failed to mysql_real_connect()" ); |
148 | |
149 | status= mysql_real_query_start(&err, &mysql, SL("SHOW STATUS" )); |
150 | while (status) |
151 | { |
152 | status= wait_for_mysql(&mysql, status); |
153 | status= mysql_real_query_cont(&err, &mysql, status); |
154 | } |
155 | if (err) |
156 | fatal(&mysql, "mysql_real_query() returns error" ); |
157 | |
158 | /* This method cannot block. */ |
159 | res= mysql_use_result(&mysql); |
160 | if (!res) |
161 | fatal(&mysql, "mysql_use_result() returns error" ); |
162 | |
163 | for (;;) |
164 | { |
165 | status= mysql_fetch_row_start(&row, res); |
166 | while (status) |
167 | { |
168 | status= wait_for_mysql(&mysql, status); |
169 | status= mysql_fetch_row_cont(&row, res, status); |
170 | } |
171 | if (!row) |
172 | break; |
173 | printf("%s: %s\n" , row[0], row[1]); |
174 | } |
175 | if (mysql_errno(&mysql)) |
176 | fatal(&mysql, "Got error while retrieving rows" ); |
177 | mysql_free_result(res); |
178 | |
179 | /* |
180 | mysql_close() sends a COM_QUIT packet, and so in principle could block |
181 | waiting for the socket to accept the data. |
182 | In practise, for many applications it will probably be fine to use the |
183 | blocking mysql_close(). |
184 | */ |
185 | status= mysql_close_start(&mysql); |
186 | while (status) |
187 | { |
188 | status= wait_for_mysql(&mysql, status); |
189 | status= mysql_close_cont(&mysql, status); |
190 | } |
191 | } |
192 | |
193 | int |
194 | main(int argc, char *argv[]) |
195 | { |
196 | int err; |
197 | |
198 | if (argc != 4) |
199 | { |
200 | fprintf(stderr, "Usage: %s <host> <user> <password>\n" , argv[0]); |
201 | exit(1); |
202 | } |
203 | |
204 | err= mysql_library_init(argc, argv, (char **)my_groups); |
205 | if (err) |
206 | { |
207 | fprintf(stderr, "Fatal: mysql_library_init() returns error: %d\n" , err); |
208 | exit(1); |
209 | } |
210 | |
211 | doit(argv[1], argv[2], argv[3]); |
212 | |
213 | mysql_library_end(); |
214 | |
215 | return 0; |
216 | } |
217 | |