19
19
*/
20
20
21
21
#include <assert.h>
22
- #include <string.h>
23
22
#include <mysql.h>
24
23
#include <sqlite3.h>
24
+ #include <stdarg.h>
25
25
#include <stddef.h>
26
26
#include <stdlib.h>
27
- #include <stdarg .h>
27
+ #include <string .h>
28
28
29
29
#include "database.h"
30
30
#include "lwan-status.h"
31
31
32
+ /* Including "lwan.h" introduces namespace conflicts (linked-list
33
+ * functions from CCAN and MySQL headers.) */
34
+ struct lwan_request ;
35
+ int lwan_request_await_read (struct lwan_request * r , int fd );
36
+ int lwan_request_await_write (struct lwan_request * r , int fd );
37
+ int lwan_request_await_read_write (struct lwan_request * r , int fd );
38
+
32
39
struct db_stmt {
33
- bool (* bind )(const struct db_stmt * stmt ,
34
- struct db_row * rows );
40
+ bool (* bind )(const struct db_stmt * stmt , struct db_row * rows );
35
41
bool (* step )(const struct db_stmt * stmt , va_list ap );
36
42
void (* finalize )(struct db_stmt * stmt );
37
43
const char * param_signature ;
38
44
const char * result_signature ;
45
+ void * ctx ;
39
46
};
40
47
41
48
struct db {
42
49
void (* disconnect )(struct db * db );
43
50
struct db_stmt * (* prepare )(const struct db * db ,
51
+ void * ctx ,
44
52
const char * sql ,
45
53
const char * param_signature ,
46
54
const char * result_signature );
@@ -58,13 +66,13 @@ struct db_stmt_mysql {
58
66
MYSQL_STMT * stmt ;
59
67
MYSQL_BIND * param_bind ;
60
68
MYSQL_BIND * result_bind ;
69
+ int db_fd ;
61
70
bool must_execute_again ;
62
71
bool results_are_bound ;
63
72
MYSQL_BIND param_result_bind [];
64
73
};
65
74
66
- static bool db_stmt_bind_mysql (const struct db_stmt * stmt ,
67
- struct db_row * rows )
75
+ static bool db_stmt_bind_mysql (const struct db_stmt * stmt , struct db_row * rows )
68
76
{
69
77
struct db_stmt_mysql * stmt_mysql = (struct db_stmt_mysql * )stmt ;
70
78
const char * signature = stmt -> param_signature ;
@@ -95,16 +103,55 @@ static bool db_stmt_bind_mysql(const struct db_stmt *stmt,
95
103
return !mysql_stmt_bind_param (stmt_mysql -> stmt , stmt_mysql -> param_bind );
96
104
}
97
105
98
- static bool db_stmt_step_mysql (const struct db_stmt * stmt ,
99
- va_list ap )
106
+ static bool db_stmt_step_mysql (const struct db_stmt * stmt , va_list ap )
100
107
{
101
108
struct db_stmt_mysql * stmt_mysql = (struct db_stmt_mysql * )stmt ;
102
109
103
110
if (stmt_mysql -> must_execute_again ) {
104
111
stmt_mysql -> must_execute_again = false;
105
112
stmt_mysql -> results_are_bound = false;
106
- if (mysql_stmt_execute (stmt_mysql -> stmt ))
107
- return false;
113
+
114
+ int status ;
115
+
116
+ mysql_stmt_execute_start (& status , stmt_mysql -> stmt );
117
+ while (status ) {
118
+ /* FIXME: Handle MYSQL_WAIT_TIMEOUT and MYSQL_WAIT_EXCEPT
119
+ * properly.
120
+ *
121
+ * TIMEOUT is handled by calling mysql_get_timeout_value()
122
+ * and passing it to the await functions; that's not currently
123
+ * supported in Lwan, at least not easily (one could set a
124
+ * timeout by hand, similar to how lwan_request_sleep() does,
125
+ * but instead of yielding with CONN_CORO_SUSPEND, one would
126
+ * forward the arguments to the actual called await function;
127
+ * upon return, one would check what caused the coroutine to
128
+ * be resumed, and return -ETIMEDOUT or something.
129
+ *
130
+ * EXCEPT is handled like EPOLLPRI. Currently unsupported
131
+ * in Lwan too, although it's easier to implement than timeout.
132
+ *
133
+ * For now, ignore both flags. */
134
+ status &= ~(MYSQL_WAIT_TIMEOUT | MYSQL_WAIT_EXCEPT );
135
+
136
+ switch (status ) {
137
+ case MYSQL_WAIT_READ :
138
+ lwan_request_await_read (stmt_mysql -> base .ctx ,
139
+ stmt_mysql -> db_fd );
140
+ break ;
141
+ case MYSQL_WAIT_WRITE :
142
+ lwan_request_await_write (stmt_mysql -> base .ctx ,
143
+ stmt_mysql -> db_fd );
144
+ break ;
145
+ case MYSQL_WAIT_READ | MYSQL_WAIT_WRITE :
146
+ /* FIXME: how do we know what will cause the coroutine
147
+ * to resume, a read or a write? */
148
+ lwan_request_await_read_write (stmt_mysql -> base .ctx ,
149
+ stmt_mysql -> db_fd );
150
+ break ;
151
+ }
152
+
153
+ status = mysql_stmt_execute_cont (& status , stmt_mysql -> stmt , status );
154
+ }
108
155
}
109
156
110
157
if (!stmt_mysql -> results_are_bound ) {
@@ -154,15 +201,16 @@ static void db_stmt_finalize_mysql(struct db_stmt *stmt)
154
201
free (stmt_mysql );
155
202
}
156
203
157
- static struct db_stmt *
158
- db_prepare_mysql ( const struct db * db ,
159
- const char * sql ,
160
- const char * param_signature ,
161
- const char * result_signature )
204
+ static struct db_stmt * db_prepare_mysql ( const struct db * db ,
205
+ void * ctx ,
206
+ const char * sql ,
207
+ const char * param_signature ,
208
+ const char * result_signature )
162
209
{
163
210
const struct db_mysql * db_mysql = (const struct db_mysql * )db ;
164
211
const size_t n_bounds = strlen (param_signature ) + strlen (result_signature );
165
- struct db_stmt_mysql * stmt_mysql = malloc (sizeof (* stmt_mysql ) + n_bounds * sizeof (MYSQL_BIND ));
212
+ struct db_stmt_mysql * stmt_mysql =
213
+ malloc (sizeof (* stmt_mysql ) + n_bounds * sizeof (MYSQL_BIND ));
166
214
167
215
if (!stmt_mysql )
168
216
return NULL ;
@@ -175,19 +223,24 @@ db_prepare_mysql(const struct db *db,
175
223
goto out_close_stmt ;
176
224
177
225
assert (strlen (param_signature ) == mysql_stmt_param_count (stmt_mysql -> stmt ));
178
- assert (strlen (result_signature ) == mysql_stmt_field_count (stmt_mysql -> stmt ));
226
+ assert (strlen (result_signature ) ==
227
+ mysql_stmt_field_count (stmt_mysql -> stmt ));
179
228
180
229
stmt_mysql -> base .bind = db_stmt_bind_mysql ;
181
230
stmt_mysql -> base .step = db_stmt_step_mysql ;
182
231
stmt_mysql -> base .finalize = db_stmt_finalize_mysql ;
183
232
stmt_mysql -> param_bind = & stmt_mysql -> param_result_bind [0 ];
184
- stmt_mysql -> result_bind = & stmt_mysql -> param_result_bind [strlen (param_signature )];
233
+ stmt_mysql -> result_bind =
234
+ & stmt_mysql -> param_result_bind [strlen (param_signature )];
185
235
stmt_mysql -> must_execute_again = true;
186
236
stmt_mysql -> results_are_bound = false;
187
237
188
238
stmt_mysql -> base .param_signature = param_signature ;
189
239
stmt_mysql -> base .result_signature = result_signature ;
190
240
241
+ stmt_mysql -> db_fd = mysql_get_socket (db_mysql -> con );
242
+ stmt_mysql -> base .ctx = ctx ;
243
+
191
244
memset (stmt_mysql -> param_result_bind , 0 , n_bounds * sizeof (MYSQL_BIND ));
192
245
193
246
return (struct db_stmt * )stmt_mysql ;
@@ -231,6 +284,11 @@ struct db *db_connect_mysql(const char *host,
231
284
if (mysql_set_character_set (db_mysql -> con , "utf8" ))
232
285
goto error ;
233
286
287
+ if (mysql_optionsv (db_mysql -> con , MYSQL_OPT_NONBLOCK , 0 )) {
288
+ lwan_status_error ("Could not enable non-blocking mode" );
289
+ goto error ;
290
+ }
291
+
234
292
db_mysql -> base .disconnect = db_disconnect_mysql ;
235
293
db_mysql -> base .prepare = db_prepare_mysql ;
236
294
@@ -254,8 +312,7 @@ struct db_stmt_sqlite {
254
312
sqlite3_stmt * sqlite ;
255
313
};
256
314
257
- static bool db_stmt_bind_sqlite (const struct db_stmt * stmt ,
258
- struct db_row * rows )
315
+ static bool db_stmt_bind_sqlite (const struct db_stmt * stmt , struct db_row * rows )
259
316
{
260
317
const struct db_stmt_sqlite * stmt_sqlite =
261
318
(const struct db_stmt_sqlite * )stmt ;
@@ -270,8 +327,8 @@ static bool db_stmt_bind_sqlite(const struct db_stmt *stmt,
270
327
271
328
switch (signature [row ]) {
272
329
case 's' :
273
- ret = sqlite3_bind_text (stmt_sqlite -> sqlite , (int )row + 1 , r -> u .s , -1 ,
274
- NULL );
330
+ ret = sqlite3_bind_text (stmt_sqlite -> sqlite , (int )row + 1 , r -> u .s ,
331
+ -1 , NULL );
275
332
break ;
276
333
case 'i' :
277
334
ret = sqlite3_bind_int (stmt_sqlite -> sqlite , (int )row + 1 , r -> u .i );
@@ -287,8 +344,7 @@ static bool db_stmt_bind_sqlite(const struct db_stmt *stmt,
287
344
return true;
288
345
}
289
346
290
- static bool db_stmt_step_sqlite (const struct db_stmt * stmt ,
291
- va_list ap )
347
+ static bool db_stmt_step_sqlite (const struct db_stmt * stmt , va_list ap )
292
348
{
293
349
const struct db_stmt_sqlite * stmt_sqlite =
294
350
(const struct db_stmt_sqlite * )stmt ;
@@ -328,11 +384,11 @@ static void db_stmt_finalize_sqlite(struct db_stmt *stmt)
328
384
free (stmt_sqlite );
329
385
}
330
386
331
- static struct db_stmt *
332
- db_prepare_sqlite ( const struct db * db ,
333
- const char * sql ,
334
- const char * param_signature ,
335
- const char * result_signature )
387
+ static struct db_stmt * db_prepare_sqlite ( const struct db * db ,
388
+ void * ctx ,
389
+ const char * sql ,
390
+ const char * param_signature ,
391
+ const char * result_signature )
336
392
{
337
393
const struct db_sqlite * db_sqlite = (const struct db_sqlite * )db ;
338
394
struct db_stmt_sqlite * stmt_sqlite = malloc (sizeof (* stmt_sqlite ));
@@ -354,6 +410,8 @@ db_prepare_sqlite(const struct db *db,
354
410
stmt_sqlite -> base .param_signature = param_signature ;
355
411
stmt_sqlite -> base .result_signature = result_signature ;
356
412
413
+ stmt_sqlite -> base .ctx = ctx ;
414
+
357
415
return (struct db_stmt * )stmt_sqlite ;
358
416
}
359
417
@@ -414,10 +472,11 @@ inline void db_stmt_finalize(struct db_stmt *stmt) { stmt->finalize(stmt); }
414
472
415
473
inline void db_disconnect (struct db * db ) { db -> disconnect (db ); }
416
474
417
- inline struct db_stmt * db_prepare_stmt (const struct db * db ,
418
- const char * sql ,
419
- const char * param_signature ,
420
- const char * result_signature )
475
+ inline struct db_stmt * db_prepare_stmt_ctx (const struct db * db ,
476
+ void * ctx ,
477
+ const char * sql ,
478
+ const char * param_signature ,
479
+ const char * result_signature )
421
480
{
422
- return db -> prepare (db , sql , param_signature , result_signature );
481
+ return db -> prepare (db , ctx , sql , param_signature , result_signature );
423
482
}
0 commit comments