]>
Commit | Line | Data |
---|---|---|
249639b3 AM |
1 | /* |
2 | Copyright (c) 2003-4, WebThing Ltd | |
3 | Author: Nick Kew <nick@webthing.com> | |
4 | ||
5 | This program is free software; you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License as published by | |
7 | the Free Software Foundation; either version 2 of the License, or | |
8 | (at your option) any later version. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License | |
16 | along with this program; if not, write to the Free Software | |
17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
18 | ||
19 | */ | |
20 | ||
21 | /* | |
22 | The current GPL satisfies MySQL licensing terms without | |
23 | invoking any exceptions. | |
24 | ||
25 | This code is untested, and probably mostly won't work. | |
26 | It's a demo of concept. | |
27 | */ | |
28 | ||
29 | #include "apu.h" | |
30 | ||
31 | #if APU_HAVE_MYSQL | |
32 | ||
33 | #include <ctype.h> | |
34 | #include <stdlib.h> | |
35 | ||
36 | #include <mysql/mysql.h> | |
37 | #include <mysql/errmsg.h> | |
38 | ||
39 | #include "apr_strings.h" | |
40 | ||
41 | #include "apr_dbd_internal.h" | |
42 | ||
43 | ||
44 | struct apr_dbd_prepared_t { | |
45 | MYSQL_STMT* stmt; | |
46 | }; | |
47 | ||
48 | struct apr_dbd_transaction_t { | |
49 | int errnum; | |
50 | apr_dbd_t *handle; | |
51 | }; | |
52 | ||
53 | struct apr_dbd_t { | |
54 | MYSQL* conn ; | |
55 | apr_dbd_transaction_t* trans ; | |
56 | }; | |
57 | ||
58 | struct apr_dbd_results_t { | |
59 | int random; | |
60 | MYSQL_RES *res; | |
61 | MYSQL_STMT *statement; | |
62 | MYSQL_BIND *bind; | |
63 | }; | |
64 | struct apr_dbd_row_t { | |
65 | MYSQL_ROW row; | |
66 | apr_dbd_results_t *res; | |
67 | }; | |
68 | ||
69 | static int dbd_mysql_select(apr_pool_t *pool, apr_dbd_t *sql, | |
70 | apr_dbd_results_t **results, | |
71 | const char *query, int seek) | |
72 | { | |
73 | int sz; | |
74 | int ret; | |
75 | if (sql->trans && sql->trans->errnum) { | |
76 | return sql->trans->errnum; | |
77 | } | |
78 | ret = mysql_query(sql->conn, query); | |
79 | if (!ret) { | |
80 | if (sz = mysql_field_count(sql->conn), sz > 0) { | |
81 | if (!*results) { | |
82 | *results = apr_palloc(pool, sizeof(apr_dbd_results_t)); | |
83 | } | |
84 | (*results)->random = seek; | |
85 | (*results)->statement = NULL; | |
86 | if (seek) { | |
87 | (*results)->res = mysql_store_result(sql->conn); | |
88 | } | |
89 | else { | |
90 | (*results)->res = mysql_use_result(sql->conn); | |
91 | } | |
92 | apr_pool_cleanup_register(pool, (*results)->res, | |
93 | (void*)mysql_free_result, | |
94 | apr_pool_cleanup_null); | |
95 | } | |
96 | } | |
97 | if (sql->trans) { | |
98 | sql->trans->errnum = ret; | |
99 | } | |
100 | return ret; | |
101 | } | |
102 | static int dbd_mysql_get_row(apr_pool_t *pool, apr_dbd_results_t *res, | |
103 | apr_dbd_row_t **row, int rownum) | |
104 | { | |
105 | MYSQL_ROW r; | |
106 | int ret = 0; | |
107 | ||
108 | if (res->statement) { | |
109 | if (res->random) { | |
110 | if (rownum >= 0) { | |
111 | mysql_stmt_data_seek(res->statement, (my_ulonglong)rownum); | |
112 | } | |
113 | } | |
114 | ret = mysql_stmt_fetch(res->statement); | |
115 | } | |
116 | else { | |
117 | if (res->random) { | |
118 | if (rownum >= 0) { | |
119 | mysql_data_seek(res->res, (my_ulonglong) rownum); | |
120 | } | |
121 | } | |
122 | r = mysql_fetch_row(res->res); | |
123 | if (r == NULL) { | |
124 | ret = 1; | |
125 | } | |
126 | } | |
127 | if (ret == 0) { | |
128 | if (!*row) { | |
129 | *row = apr_palloc(pool, sizeof(apr_dbd_row_t)); | |
130 | } | |
131 | (*row)->row = r; | |
132 | (*row)->res = res; | |
133 | } | |
134 | else { | |
135 | mysql_free_result(res->res); | |
136 | apr_pool_cleanup_kill(pool, res->res, (void*)mysql_free_result); | |
137 | ret = -1; | |
138 | } | |
139 | return ret; | |
140 | } | |
141 | #if 0 | |
142 | static int dbd_mysql_get_entry(const apr_dbd_row_t *row, int n, | |
143 | apr_dbd_datum_t *val) | |
144 | { | |
145 | MYSQL_BIND *bind; | |
146 | if (row->res->statement) { | |
147 | bind = &row->res->bind[n]; | |
148 | if (mysql_stmt_fetch_column(row->res->statement, bind, n, 0) != 0) { | |
149 | val->type = APR_DBD_VALUE_NULL; | |
150 | return -1; | |
151 | } | |
152 | if (*bind->is_null) { | |
153 | val->type = APR_DBD_VALUE_NULL; | |
154 | return -1; | |
155 | } | |
156 | else { | |
157 | val->type = APR_DBD_VALUE_STRING; | |
158 | val->value.stringval = bind->buffer; | |
159 | } | |
160 | } | |
161 | else { | |
162 | val->type = APR_DBD_VALUE_STRING; | |
163 | val->value.stringval = row->row[n]; | |
164 | } | |
165 | return 0; | |
166 | } | |
167 | #else | |
168 | static const char *dbd_mysql_get_entry(const apr_dbd_row_t *row, int n) | |
169 | { | |
170 | MYSQL_BIND *bind; | |
171 | if (row->res->statement) { | |
172 | bind = &row->res->bind[n]; | |
173 | if (mysql_stmt_fetch_column(row->res->statement, bind, n, 0) != 0) { | |
174 | return NULL; | |
175 | } | |
176 | if (*bind->is_null) { | |
177 | return NULL; | |
178 | } | |
179 | else { | |
180 | return bind->buffer; | |
181 | } | |
182 | } | |
183 | else { | |
184 | return row->row[n]; | |
185 | } | |
186 | return 0; | |
187 | } | |
188 | #endif | |
189 | static const char *dbd_mysql_error(apr_dbd_t *sql, int n) | |
190 | { | |
191 | return mysql_error(sql->conn); | |
192 | } | |
193 | static int dbd_mysql_query(apr_dbd_t *sql, int *nrows, const char *query) | |
194 | { | |
195 | int ret; | |
196 | if (sql->trans && sql->trans->errnum) { | |
197 | return sql->trans->errnum; | |
198 | } | |
199 | ret = mysql_query(sql->conn, query); | |
200 | *nrows = mysql_affected_rows(sql->conn); | |
201 | if (sql->trans) { | |
202 | sql->trans->errnum = ret; | |
203 | } | |
204 | return ret; | |
205 | } | |
206 | static const char *dbd_mysql_escape(apr_pool_t *pool, const char *arg, | |
207 | apr_dbd_t *sql) | |
208 | { | |
209 | unsigned long len = strlen(arg); | |
210 | char *ret = apr_palloc(pool, 2*len + 1); | |
211 | mysql_real_escape_string(sql->conn, ret, arg, len); | |
212 | return ret; | |
213 | } | |
214 | static int dbd_mysql_prepare(apr_pool_t *pool, apr_dbd_t *sql, | |
215 | const char *query, const char *label, | |
216 | apr_dbd_prepared_t **statement) | |
217 | { | |
218 | /* Translate from apr_dbd to native query format */ | |
219 | char *myquery = apr_pstrdup(pool, query); | |
220 | char *p = myquery; | |
221 | const char *q; | |
222 | for (q = query; *q; ++q) { | |
223 | if (q[0] == '%') { | |
224 | if (isalpha(q[1])) { | |
225 | *p++ = '?'; | |
226 | ++q; | |
227 | } | |
228 | else if (q[1] == '%') { | |
229 | /* reduce %% to % */ | |
230 | *p++ = *q++; | |
231 | } | |
232 | else { | |
233 | *p++ = *q; | |
234 | } | |
235 | } | |
236 | else { | |
237 | *p++ = *q; | |
238 | } | |
239 | } | |
240 | *p = 0; | |
241 | if (!*statement) { | |
242 | *statement = apr_palloc(pool, sizeof(apr_dbd_prepared_t)); | |
243 | } | |
244 | (*statement)->stmt = mysql_stmt_init(sql->conn); | |
245 | apr_pool_cleanup_register(pool, *statement, (void*)mysql_stmt_close, | |
246 | apr_pool_cleanup_null); | |
247 | return mysql_stmt_prepare((*statement)->stmt, myquery, strlen(myquery)); | |
248 | } | |
249 | static int dbd_mysql_pquery(apr_pool_t *pool, apr_dbd_t *sql, | |
250 | int *nrows, apr_dbd_prepared_t *statement, | |
251 | int nargs, const char **values) | |
252 | { | |
253 | MYSQL_BIND *bind; | |
254 | char *arg; | |
255 | int ret; | |
256 | int i; | |
257 | my_bool is_null = FALSE; | |
258 | ||
259 | if (sql->trans && sql->trans->errnum) { | |
260 | return sql->trans->errnum; | |
261 | } | |
262 | nargs = mysql_stmt_param_count(statement->stmt); | |
263 | ||
264 | bind = apr_palloc(pool, nargs*sizeof(MYSQL_BIND)); | |
265 | for (i=0; i < nargs; ++i) { | |
266 | arg = (char*)values[i]; | |
267 | bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; | |
268 | bind[i].buffer = arg; | |
269 | bind[i].buffer_length = strlen(arg); | |
270 | bind[i].length = &bind[i].buffer_length; | |
271 | bind[i].is_null = &is_null; | |
272 | bind[i].is_unsigned = 0; | |
273 | } | |
274 | ||
275 | ret = mysql_stmt_bind_param(statement->stmt, bind); | |
276 | if (ret != 0) { | |
277 | *nrows = 0; | |
278 | } | |
279 | else { | |
280 | ret = mysql_stmt_execute(statement->stmt); | |
281 | *nrows = mysql_stmt_affected_rows(statement->stmt); | |
282 | } | |
283 | if (sql->trans) { | |
284 | sql->trans->errnum = ret; | |
285 | } | |
286 | return ret; | |
287 | } | |
288 | static int dbd_mysql_pvquery(apr_pool_t *pool, apr_dbd_t *sql, int *nrows, | |
289 | apr_dbd_prepared_t *statement, va_list args) | |
290 | { | |
291 | MYSQL_BIND *bind; | |
292 | char *arg; | |
293 | int ret; | |
294 | int nargs = 0; | |
295 | int i; | |
296 | my_bool is_null = FALSE; | |
297 | ||
298 | if (sql->trans && sql->trans->errnum) { | |
299 | return sql->trans->errnum; | |
300 | } | |
301 | nargs = mysql_stmt_param_count(statement->stmt); | |
302 | ||
303 | bind = apr_palloc(pool, nargs*sizeof(MYSQL_BIND)); | |
304 | for (i=0; i < nargs; ++i) { | |
305 | arg = va_arg(args, char*); | |
306 | bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; | |
307 | bind[i].buffer = arg; | |
308 | bind[i].buffer_length = strlen(arg); | |
309 | bind[i].length = &bind[i].buffer_length; | |
310 | bind[i].is_null = &is_null; | |
311 | bind[i].is_unsigned = 0; | |
312 | } | |
313 | ||
314 | ret = mysql_stmt_bind_param(statement->stmt, bind); | |
315 | if (ret != 0) { | |
316 | *nrows = 0; | |
317 | } | |
318 | else { | |
319 | ret = mysql_stmt_execute(statement->stmt); | |
320 | *nrows = mysql_stmt_affected_rows(statement->stmt); | |
321 | } | |
322 | if (sql->trans) { | |
323 | sql->trans->errnum = ret; | |
324 | } | |
325 | return ret; | |
326 | } | |
327 | static int dbd_mysql_pselect(apr_pool_t *pool, apr_dbd_t *sql, | |
328 | apr_dbd_results_t **res, | |
329 | apr_dbd_prepared_t *statement, int random, | |
330 | int nargs, const char **args) | |
331 | { | |
332 | int i; | |
333 | int nfields; | |
334 | char *arg; | |
335 | my_bool is_null = FALSE; | |
336 | my_bool *is_nullr; | |
337 | int ret; | |
338 | const int FIELDSIZE = 255; | |
339 | unsigned long *length; | |
340 | char **data; | |
341 | MYSQL_BIND *bind; | |
342 | ||
343 | if (sql->trans && sql->trans->errnum) { | |
344 | return sql->trans->errnum; | |
345 | } | |
346 | ||
347 | nargs = mysql_stmt_param_count(statement->stmt); | |
348 | bind = apr_palloc(pool, nargs*sizeof(MYSQL_BIND)); | |
349 | ||
350 | for (i=0; i < nargs; ++i) { | |
351 | arg = (char*)args[i]; | |
352 | bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; | |
353 | bind[i].buffer = arg; | |
354 | bind[i].buffer_length = strlen(arg); | |
355 | bind[i].length = &bind[i].buffer_length; | |
356 | bind[i].is_null = &is_null; | |
357 | bind[i].is_unsigned = 0; | |
358 | } | |
359 | ||
360 | ret = mysql_stmt_bind_param(statement->stmt, bind); | |
361 | if (ret == 0) { | |
362 | ret = mysql_stmt_execute(statement->stmt); | |
363 | if (!ret) { | |
364 | if (!*res) { | |
365 | *res = apr_pcalloc(pool, sizeof(apr_dbd_results_t)); | |
366 | if (!*res) { | |
367 | while (!mysql_stmt_fetch(statement->stmt)); | |
368 | return -1; | |
369 | } | |
370 | } | |
371 | (*res)->random = random; | |
372 | (*res)->statement = statement->stmt; | |
373 | (*res)->res = mysql_stmt_result_metadata(statement->stmt); | |
374 | apr_pool_cleanup_register(pool, (*res)->res, | |
375 | (void*)mysql_free_result, apr_pool_cleanup_null); | |
376 | nfields = mysql_num_fields((*res)->res); | |
377 | if (!(*res)->bind) { | |
378 | (*res)->bind = apr_palloc(pool, nfields*sizeof(MYSQL_BIND)); | |
379 | length = apr_pcalloc(pool, nfields*sizeof(unsigned long)); | |
380 | data = apr_palloc(pool, nfields*sizeof(char*)); | |
381 | is_nullr = apr_pcalloc(pool, nfields*sizeof(my_bool)); | |
382 | length = apr_pcalloc(pool, nfields); | |
383 | for ( i = 0; i < nfields; ++i ) { | |
384 | (*res)->bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; | |
385 | (*res)->bind[i].buffer_length = FIELDSIZE; | |
386 | (*res)->bind[i].length = &length[i]; | |
387 | data[i] = apr_palloc(pool, FIELDSIZE*sizeof(char)); | |
388 | (*res)->bind[i].buffer = data[i]; | |
389 | (*res)->bind[i].is_null = is_nullr+i; | |
390 | } | |
391 | } | |
392 | ret = mysql_stmt_bind_result(statement->stmt, (*res)->bind); | |
393 | if (!ret) { | |
394 | ret = mysql_stmt_store_result(statement->stmt); | |
395 | } | |
396 | } | |
397 | } | |
398 | if (sql->trans) { | |
399 | sql->trans->errnum = ret; | |
400 | } | |
401 | return ret; | |
402 | } | |
403 | static int dbd_mysql_pvselect(apr_pool_t *pool, apr_dbd_t *sql, | |
404 | apr_dbd_results_t **res, | |
405 | apr_dbd_prepared_t *statement, int random, | |
406 | va_list args) | |
407 | { | |
408 | int i; | |
409 | int nfields; | |
410 | char *arg; | |
411 | my_bool is_null = FALSE; | |
412 | my_bool *is_nullr; | |
413 | int ret; | |
414 | const int FIELDSIZE = 255; | |
415 | unsigned long *length; | |
416 | char **data; | |
417 | int nargs; | |
418 | MYSQL_BIND *bind; | |
419 | ||
420 | if (sql->trans && sql->trans->errnum) { | |
421 | return sql->trans->errnum; | |
422 | } | |
423 | ||
424 | nargs = mysql_stmt_param_count(statement->stmt); | |
425 | bind = apr_palloc(pool, nargs*sizeof(MYSQL_BIND)); | |
426 | ||
427 | for (i=0; i < nargs; ++i) { | |
428 | arg = va_arg(args, char*); | |
429 | bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; | |
430 | bind[i].buffer = arg; | |
431 | bind[i].buffer_length = strlen(arg); | |
432 | bind[i].length = &bind[i].buffer_length; | |
433 | bind[i].is_null = &is_null; | |
434 | bind[i].is_unsigned = 0; | |
435 | } | |
436 | ||
437 | ret = mysql_stmt_bind_param(statement->stmt, bind); | |
438 | if (ret == 0) { | |
439 | ret = mysql_stmt_execute(statement->stmt); | |
440 | if (!ret) { | |
441 | if (!*res) { | |
442 | *res = apr_pcalloc(pool, sizeof(apr_dbd_results_t)); | |
443 | if (!*res) { | |
444 | while (!mysql_stmt_fetch(statement->stmt)); | |
445 | return -1; | |
446 | } | |
447 | } | |
448 | (*res)->random = random; | |
449 | (*res)->statement = statement->stmt; | |
450 | (*res)->res = mysql_stmt_result_metadata(statement->stmt); | |
451 | apr_pool_cleanup_register(pool, (*res)->res, | |
452 | (void*)mysql_free_result, apr_pool_cleanup_null); | |
453 | nfields = mysql_num_fields((*res)->res); | |
454 | if (!(*res)->bind) { | |
455 | (*res)->bind = apr_palloc(pool, nfields*sizeof(MYSQL_BIND)); | |
456 | length = apr_pcalloc(pool, nfields*sizeof(unsigned long)); | |
457 | data = apr_palloc(pool, nfields*sizeof(char*)); | |
458 | is_nullr = apr_pcalloc(pool, nfields*sizeof(my_bool)); | |
459 | length = apr_pcalloc(pool, nfields); | |
460 | for ( i = 0; i < nfields; ++i ) { | |
461 | (*res)->bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; | |
462 | (*res)->bind[i].buffer_length = FIELDSIZE; | |
463 | (*res)->bind[i].length = &length[i]; | |
464 | data[i] = apr_palloc(pool, FIELDSIZE*sizeof(char)); | |
465 | (*res)->bind[i].buffer = data[i]; | |
466 | (*res)->bind[i].is_null = is_nullr+i; | |
467 | } | |
468 | } | |
469 | ret = mysql_stmt_bind_result(statement->stmt, (*res)->bind); | |
470 | if (!ret) { | |
471 | ret = mysql_stmt_store_result(statement->stmt); | |
472 | } | |
473 | } | |
474 | } | |
475 | if (sql->trans) { | |
476 | sql->trans->errnum = ret; | |
477 | } | |
478 | return ret; | |
479 | } | |
480 | static int dbd_mysql_end_transaction(apr_dbd_transaction_t *trans) | |
481 | { | |
482 | int ret = -1; | |
483 | if (trans) { | |
484 | if (trans->errnum) { | |
485 | trans->errnum = 0; | |
486 | ret = mysql_rollback(trans->handle->conn); | |
487 | } | |
488 | else { | |
489 | ret = mysql_commit(trans->handle->conn); | |
490 | } | |
491 | } | |
492 | ret |= mysql_autocommit(trans->handle->conn, 1); | |
493 | return ret; | |
494 | } | |
495 | /* Whether or not transactions work depends on whether the | |
496 | * underlying DB supports them within MySQL. Unfortunately | |
497 | * it fails silently with the default InnoDB. | |
498 | */ | |
499 | static int dbd_mysql_transaction(apr_pool_t *pool, apr_dbd_t *handle, | |
500 | apr_dbd_transaction_t **trans) | |
501 | { | |
502 | /* Don't try recursive transactions here */ | |
503 | if (handle->trans) { | |
504 | dbd_mysql_end_transaction(handle->trans) ; | |
505 | } | |
506 | if (!*trans) { | |
507 | *trans = apr_pcalloc(pool, sizeof(apr_dbd_transaction_t)); | |
508 | } | |
509 | (*trans)->errnum = mysql_autocommit(handle->conn, 0); | |
510 | (*trans)->handle = handle; | |
511 | handle->trans = *trans; | |
512 | return (*trans)->errnum; | |
513 | } | |
514 | static apr_dbd_t *dbd_mysql_open(apr_pool_t *pool, const char *params) | |
515 | { | |
516 | static const char *const delims = " \r\n\t;|,"; | |
517 | const char *ptr; | |
518 | int i; | |
519 | const char *key; | |
520 | size_t klen; | |
521 | const char *value; | |
522 | size_t vlen; | |
523 | struct { | |
524 | const char *field; | |
525 | const char *value; | |
526 | } fields[] = { | |
527 | {"host", NULL}, | |
528 | {"user", NULL}, | |
529 | {"pass", NULL}, | |
530 | {"dbname", NULL}, | |
531 | {"port", NULL}, | |
532 | {"sock", NULL}, | |
533 | {NULL, NULL} | |
534 | }; | |
535 | unsigned int port = 0; | |
536 | apr_dbd_t *sql = apr_pcalloc(pool, sizeof(apr_dbd_t)); | |
537 | sql->conn = mysql_init(sql->conn); | |
538 | if ( sql->conn == NULL ) { | |
539 | return NULL; | |
540 | } | |
541 | for (ptr = strchr(params, '='); ptr; ptr = strchr(ptr, '=')) { | |
542 | for (key = ptr-1; isspace(*key); --key); | |
543 | klen = 0; | |
544 | while (isalpha(*key)) { | |
545 | --key; | |
546 | ++klen; | |
547 | } | |
548 | ++key; | |
549 | for (value = ptr+1; isspace(*value); ++value); | |
550 | vlen = strcspn(value, delims); | |
551 | for (i=0; fields[i].field != NULL; ++i) { | |
552 | if (!strncasecmp(fields[i].field, key, klen)) { | |
553 | fields[i].value = apr_pstrndup(pool, value, vlen); | |
554 | break; | |
555 | } | |
556 | } | |
557 | ptr = value+vlen; | |
558 | } | |
559 | if (fields[4].value != NULL) { | |
560 | port = atoi(fields[4].value); | |
561 | } | |
562 | sql->conn = mysql_real_connect(sql->conn, fields[0].value, | |
563 | fields[1].value, fields[2].value, | |
564 | fields[3].value, port, | |
565 | fields[5].value, 0); | |
c09ca3c5 | 566 | return sql->conn ? sql : NULL; |
249639b3 AM |
567 | } |
568 | static apr_status_t dbd_mysql_close(apr_dbd_t *handle) | |
569 | { | |
570 | mysql_close(handle->conn); | |
571 | return APR_SUCCESS; | |
572 | } | |
573 | static apr_status_t dbd_mysql_check_conn(apr_pool_t *pool, | |
574 | apr_dbd_t *handle) | |
575 | { | |
576 | return mysql_ping(handle->conn) ? APR_EGENERAL : APR_SUCCESS; | |
577 | } | |
578 | static int dbd_mysql_select_db(apr_pool_t *pool, apr_dbd_t* handle, | |
579 | const char* name) | |
580 | { | |
581 | return mysql_select_db(handle->conn, name); | |
582 | } | |
583 | static void *dbd_mysql_native(apr_dbd_t *handle) | |
584 | { | |
585 | return handle->conn; | |
586 | } | |
587 | static int dbd_mysql_num_cols(apr_dbd_results_t *res) | |
588 | { | |
589 | if (res->statement) { | |
590 | return mysql_stmt_field_count(res->statement); | |
591 | } | |
592 | else { | |
593 | return mysql_num_fields(res->res); | |
594 | } | |
595 | } | |
596 | static int dbd_mysql_num_tuples(apr_dbd_results_t *res) | |
597 | { | |
598 | if (res->random) { | |
599 | if (res->statement) { | |
600 | return (int) mysql_stmt_num_rows(res->statement); | |
601 | } | |
602 | else { | |
603 | return (int) mysql_num_rows(res->res); | |
604 | } | |
605 | } | |
606 | else { | |
607 | return -1; | |
608 | } | |
609 | } | |
610 | static void dbd_mysql_init(apr_pool_t *pool) | |
611 | { | |
612 | my_init(); | |
613 | /* FIXME: this is a guess; find out what it really does */ | |
614 | apr_pool_cleanup_register(pool, NULL, apr_pool_cleanup_null, | |
615 | (void*)mysql_thread_end); | |
616 | } | |
617 | APU_DECLARE_DATA const apr_dbd_driver_t apr_dbd_mysql_driver = { | |
618 | "mysql", | |
619 | dbd_mysql_init, | |
620 | dbd_mysql_native, | |
621 | dbd_mysql_open, | |
622 | dbd_mysql_check_conn, | |
623 | dbd_mysql_close, | |
624 | dbd_mysql_select_db, | |
625 | dbd_mysql_transaction, | |
626 | dbd_mysql_end_transaction, | |
627 | dbd_mysql_query, | |
628 | dbd_mysql_select, | |
629 | dbd_mysql_num_cols, | |
630 | dbd_mysql_num_tuples, | |
631 | dbd_mysql_get_row, | |
632 | dbd_mysql_get_entry, | |
633 | dbd_mysql_error, | |
634 | dbd_mysql_escape, | |
635 | dbd_mysql_prepare, | |
636 | dbd_mysql_pvquery, | |
637 | dbd_mysql_pvselect, | |
638 | dbd_mysql_pquery, | |
639 | dbd_mysql_pselect, | |
640 | }; | |
641 | ||
642 | #endif |