OpenDNSSEC-enforcer 2.1.12
db_backend_mysql.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2014 Jerry Lundström <lundstrom.jerry@gmail.com>
3 * Copyright (c) 2014 .SE (The Internet Infrastructure Foundation).
4 * Copyright (c) 2014 OpenDNSSEC AB (svb)
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
22 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
24 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29
30#include "db_backend_mysql.h"
31#include "db_error.h"
32
33#include "log.h"
34
35#include <mysql/mysql.h>
36
37/* Support building against MySQL. */
38#ifndef LIBMARIADB
39typedef char my_bool;
40#endif
41
42#include <stdlib.h>
43#include <stdio.h>
44#include <unistd.h>
45#include <string.h>
46#include <time.h>
47#include <pthread.h>
48#include <errno.h>
49
50static int db_backend_mysql_transaction_rollback(void*);
51
55static int __mysql_initialized = 0;
56
60typedef struct db_backend_mysql {
61 MYSQL* db;
63 unsigned int timeout;
64 const char* db_host;
65 const char* db_user;
66 const char* db_pass;
67 const char* db_name;
70
71
72
79 MYSQL_BIND* bind;
80 unsigned long length;
83};
84
85
86
92 MYSQL_STMT* statement;
93 MYSQL_BIND* mysql_bind_input;
96 MYSQL_BIND* mysql_bind_output;
101 int bound;
103
104
105
111static inline void __db_backend_mysql_finish(db_backend_mysql_statement_t* statement) {
113
114 if (!statement) {
115 return;
116 }
117
118 if (statement->statement) {
119 mysql_stmt_close(statement->statement);
120 }
121 if (statement->mysql_bind_input) {
122 free(statement->mysql_bind_input);
123 }
124 while (statement->bind_input) {
125 bind = statement->bind_input;
126 statement->bind_input = bind->next;
127 free(bind);
128 }
129 while (statement->bind_output) {
130 bind = statement->bind_output;
131 statement->bind_output = bind->next;
132 if (bind->bind && bind->bind->buffer) {
133 free(bind->bind->buffer);
134 }
135 free(bind);
136 }
137 if (statement->mysql_bind_output) {
138 free(statement->mysql_bind_output);
139 }
140 if (statement->object_field_list) {
142 }
143
144 free(statement);
145}
146
147
148static inline void checkconnection(db_backend_mysql_t* backend_mysql)
149{
150 MYSQL_RES *result;
151 if(mysql_query(backend_mysql->db, "SELECT 1")) {
152 ods_log_warning("db_backend_mysql: connection lost, trying to reconnect");
153 if(!mysql_real_connect(backend_mysql->db, backend_mysql->db_host, backend_mysql->db_user, backend_mysql->db_pass,
154 backend_mysql->db_name, backend_mysql->db_port, NULL, 0) ||
155 mysql_autocommit(backend_mysql->db, 1)) {
156 if (backend_mysql->db) {
157 ods_log_error("db_backend_mysql: reconnect failed %d: %s", mysql_errno(backend_mysql->db), mysql_error(backend_mysql->db));
158 mysql_close(backend_mysql->db);
159 backend_mysql->db = NULL;
160 }
161 }
162 } else {
163 result = mysql_store_result(backend_mysql->db);
164 mysql_free_result(result);
165 }
166}
167
174static inline int __db_backend_mysql_prepare(db_backend_mysql_t* backend_mysql, db_backend_mysql_statement_t** statement, const char* sql, size_t size, const db_object_field_list_t* object_field_list) {
175 unsigned long i, params;
177 const db_object_field_t* object_field;
178 MYSQL_BIND* mysql_bind;
179 MYSQL_RES* result_metadata = NULL;
180 MYSQL_FIELD* field;
181
182 if (!backend_mysql) {
183 return DB_ERROR_UNKNOWN;
184 }
185 if (!backend_mysql->db) {
186 return DB_ERROR_UNKNOWN;
187 }
188 if (!statement) {
189 return DB_ERROR_UNKNOWN;
190 }
191 if (*statement) {
192 return DB_ERROR_UNKNOWN;
193 }
194 if (!sql) {
195 return DB_ERROR_UNKNOWN;
196 }
197
198 checkconnection(backend_mysql);
199
200 /*
201 * Prepare the statement.
202 */
203 ods_log_debug("%s", sql);
204 if (!(*statement = calloc(1, sizeof(db_backend_mysql_statement_t)))
205 || !((*statement)->statement = mysql_stmt_init(backend_mysql->db))
206 || mysql_stmt_prepare((*statement)->statement, sql, size))
207 {
208 if ((*statement)->statement) {
209 ods_log_info("DB prepare SQL %s", sql);
210 ods_log_info("DB prepare Err %d: %s", mysql_stmt_errno((*statement)->statement), mysql_stmt_error((*statement)->statement));
211 }
212 __db_backend_mysql_finish(*statement);
213 *statement = NULL;
214 return DB_ERROR_UNKNOWN;
215 }
216
217 (*statement)->backend_mysql = backend_mysql;
218
219 /*
220 * Create the input binding based on the number of parameters in the SQL
221 * statement.
222 */
223 if ((params = mysql_stmt_param_count((*statement)->statement)) > 0) {
224 if (!((*statement)->mysql_bind_input = calloc(params, sizeof(MYSQL_BIND)))) {
225 __db_backend_mysql_finish(*statement);
226 *statement = NULL;
227 return DB_ERROR_UNKNOWN;
228 }
229
230 for (i = 0; i < params; i++) {
231 if (!(bind = calloc(1, sizeof(db_backend_mysql_bind_t)))) {
232 __db_backend_mysql_finish(*statement);
233 *statement = NULL;
234 return DB_ERROR_UNKNOWN;
235 }
236
237 bind->bind = &((*statement)->mysql_bind_input[i]);
238 if (!(*statement)->bind_input) {
239 (*statement)->bind_input = bind;
240 }
241 if ((*statement)->bind_input_end) {
242 (*statement)->bind_input_end->next = bind;
243 }
244 (*statement)->bind_input_end = bind;
245 }
246 }
247
248 /*
249 * Create the output binding based on the object field list given.
250 */
251 if (object_field_list
252 && (params = db_object_field_list_size(object_field_list)) > 0
253 && (result_metadata = mysql_stmt_result_metadata((*statement)->statement)))
254 {
255 if (!((*statement)->object_field_list = db_object_field_list_new_copy(object_field_list))
256 || !((*statement)->mysql_bind_output = calloc(params, sizeof(MYSQL_BIND))))
257 {
258 mysql_free_result(result_metadata);
259 __db_backend_mysql_finish(*statement);
260 *statement = NULL;
261 return DB_ERROR_UNKNOWN;
262 }
263
264 (*statement)->fields = params;
265 field = mysql_fetch_field(result_metadata);
266 object_field = db_object_field_list_begin(object_field_list);
267 for (i = 0; i < params; i++) {
268 if (!field
269 || !object_field
270 || !(bind = calloc(1, sizeof(db_backend_mysql_bind_t))))
271 {
272 mysql_free_result(result_metadata);
273 __db_backend_mysql_finish(*statement);
274 *statement = NULL;
275 return DB_ERROR_UNKNOWN;
276 }
277
278 bind->bind = (mysql_bind = &((*statement)->mysql_bind_output[i]));
279 mysql_bind->is_null = (my_bool*)0;
280 mysql_bind->error = &bind->error;
281 mysql_bind->length = &bind->length;
282
283 switch (db_object_field_type(object_field)) {
285 switch (field->type) {
286 case MYSQL_TYPE_TINY:
287 case MYSQL_TYPE_SHORT:
288 case MYSQL_TYPE_LONG:
289 case MYSQL_TYPE_INT24:
290 mysql_bind->buffer_type = MYSQL_TYPE_LONG;
291 if (!(mysql_bind->buffer = calloc(1, sizeof(db_type_uint32_t)))) {
292 mysql_free_result(result_metadata);
293 __db_backend_mysql_finish(*statement);
294 *statement = NULL;
295 return DB_ERROR_UNKNOWN;
296 }
297 mysql_bind->buffer_length = sizeof(db_type_uint32_t);
298 bind->length = mysql_bind->buffer_length;
299 mysql_bind->is_unsigned = 1;
300 break;
301
302 case MYSQL_TYPE_LONGLONG:
303 mysql_bind->buffer_type = MYSQL_TYPE_LONGLONG;
304 if (!(mysql_bind->buffer = calloc(1, sizeof(db_type_uint64_t)))) {
305 mysql_free_result(result_metadata);
306 __db_backend_mysql_finish(*statement);
307 *statement = NULL;
308 return DB_ERROR_UNKNOWN;
309 }
310 mysql_bind->buffer_length = sizeof(db_type_uint64_t);
311 bind->length = mysql_bind->buffer_length;
312 mysql_bind->is_unsigned = 1;
313 break;
314
315 case MYSQL_TYPE_STRING:
316 case MYSQL_TYPE_VAR_STRING:
317 mysql_bind->buffer_type = MYSQL_TYPE_STRING;
318 /*
319 * field->length does not include ending NULL character so
320 * we increase it by one.
321 */
322 bind->length = field->length + 1;
325 }
326 if (!(mysql_bind->buffer = calloc(1, bind->length))) {
327 mysql_free_result(result_metadata);
328 __db_backend_mysql_finish(*statement);
329 *statement = NULL;
330 return DB_ERROR_UNKNOWN;
331 }
332 mysql_bind->buffer_length = bind->length;
333 mysql_bind->is_unsigned = 0;
334 break;
335
336 default:
337 mysql_free_result(result_metadata);
338 __db_backend_mysql_finish(*statement);
339 *statement = NULL;
340 return DB_ERROR_UNKNOWN;
341 }
342 break;
343
344 case DB_TYPE_ENUM:
345 /*
346 * Enum needs to be handled elsewhere since we don't know the
347 * enum_set_t here.
348 *
349 * TODO: can something be done here?
350 */
351 case DB_TYPE_INT32:
352 mysql_bind->buffer_type = MYSQL_TYPE_LONG;
353 if (!(mysql_bind->buffer = calloc(1, sizeof(db_type_int32_t)))) {
354 mysql_free_result(result_metadata);
355 __db_backend_mysql_finish(*statement);
356 *statement = NULL;
357 return DB_ERROR_UNKNOWN;
358 }
359 mysql_bind->buffer_length = sizeof(db_type_int32_t);
360 bind->length = mysql_bind->buffer_length;
361 mysql_bind->is_unsigned = 0;
362 break;
363
364 case DB_TYPE_UINT32:
365 mysql_bind->buffer_type = MYSQL_TYPE_LONG;
366 if (!(mysql_bind->buffer = calloc(1, sizeof(db_type_uint32_t)))) {
367 mysql_free_result(result_metadata);
368 __db_backend_mysql_finish(*statement);
369 *statement = NULL;
370 return DB_ERROR_UNKNOWN;
371 }
372 mysql_bind->buffer_length = sizeof(db_type_uint32_t);
373 bind->length = mysql_bind->buffer_length;
374 mysql_bind->is_unsigned = 1;
375 break;
376
377 case DB_TYPE_INT64:
378 mysql_bind->buffer_type = MYSQL_TYPE_LONGLONG;
379 if (!(mysql_bind->buffer = calloc(1, sizeof(db_type_int64_t)))) {
380 mysql_free_result(result_metadata);
381 __db_backend_mysql_finish(*statement);
382 *statement = NULL;
383 return DB_ERROR_UNKNOWN;
384 }
385 mysql_bind->buffer_length = sizeof(db_type_int64_t);
386 bind->length = mysql_bind->buffer_length;
387 mysql_bind->is_unsigned = 0;
388 break;
389
390 case DB_TYPE_UINT64:
391 mysql_bind->buffer_type = MYSQL_TYPE_LONGLONG;
392 if (!(mysql_bind->buffer = calloc(1, sizeof(db_type_uint64_t)))) {
393 mysql_free_result(result_metadata);
394 __db_backend_mysql_finish(*statement);
395 *statement = NULL;
396 return DB_ERROR_UNKNOWN;
397 }
398 mysql_bind->buffer_length = sizeof(db_type_uint64_t);
399 bind->length = mysql_bind->buffer_length;
400 mysql_bind->is_unsigned = 1;
401 break;
402
403 case DB_TYPE_TEXT:
404 mysql_bind->buffer_type = MYSQL_TYPE_STRING;
405 /*
406 * field->length does not include ending NULL character so
407 * we increase it by one.
408 */
409 bind->length = field->length + 1;
412 }
413 if (!(mysql_bind->buffer = calloc(1, bind->length))) {
414 mysql_free_result(result_metadata);
415 __db_backend_mysql_finish(*statement);
416 *statement = NULL;
417 return DB_ERROR_UNKNOWN;
418 }
419 mysql_bind->buffer_length = bind->length;
420 mysql_bind->is_unsigned = 0;
421 break;
422
423 case DB_TYPE_ANY:
424 case DB_TYPE_REVISION:
425 switch (field->type) {
426 case MYSQL_TYPE_TINY:
427 case MYSQL_TYPE_SHORT:
428 case MYSQL_TYPE_LONG:
429 case MYSQL_TYPE_INT24:
430 mysql_bind->buffer_type = MYSQL_TYPE_LONG;
431 if (field->flags & UNSIGNED_FLAG) {
432 if (!(mysql_bind->buffer = calloc(1, sizeof(db_type_uint32_t)))) {
433 mysql_free_result(result_metadata);
434 __db_backend_mysql_finish(*statement);
435 *statement = NULL;
436 return DB_ERROR_UNKNOWN;
437 }
438 mysql_bind->buffer_length = sizeof(db_type_uint32_t);
439 mysql_bind->is_unsigned = 1;
440 }
441 else {
442 if (!(mysql_bind->buffer = calloc(1, sizeof(db_type_int32_t)))) {
443 mysql_free_result(result_metadata);
444 __db_backend_mysql_finish(*statement);
445 *statement = NULL;
446 return DB_ERROR_UNKNOWN;
447 }
448 mysql_bind->buffer_length = sizeof(db_type_int32_t);
449 mysql_bind->is_unsigned = 0;
450 }
451 bind->length = mysql_bind->buffer_length;
452 break;
453
454 case MYSQL_TYPE_LONGLONG:
455 mysql_bind->buffer_type = MYSQL_TYPE_LONGLONG;
456 if (field->flags & UNSIGNED_FLAG) {
457 if (!(mysql_bind->buffer = calloc(1, sizeof(db_type_uint64_t)))) {
458 mysql_free_result(result_metadata);
459 __db_backend_mysql_finish(*statement);
460 *statement = NULL;
461 return DB_ERROR_UNKNOWN;
462 }
463 mysql_bind->buffer_length = sizeof(db_type_uint64_t);
464 mysql_bind->is_unsigned = 1;
465 }
466 else {
467 if (!(mysql_bind->buffer = calloc(1, sizeof(db_type_int64_t)))) {
468 mysql_free_result(result_metadata);
469 __db_backend_mysql_finish(*statement);
470 *statement = NULL;
471 return DB_ERROR_UNKNOWN;
472 }
473 mysql_bind->buffer_length = sizeof(db_type_int64_t);
474 mysql_bind->is_unsigned = 0;
475 }
476 bind->length = mysql_bind->buffer_length;
477 break;
478
479 case MYSQL_TYPE_STRING:
480 case MYSQL_TYPE_VAR_STRING:
481 mysql_bind->buffer_type = MYSQL_TYPE_STRING;
482 /*
483 * field->length does not include ending NULL character so
484 * we increase it by one.
485 */
486 bind->length = field->length + 1;
489 }
490 if (!(mysql_bind->buffer = calloc(1, bind->length))) {
491 mysql_free_result(result_metadata);
492 __db_backend_mysql_finish(*statement);
493 *statement = NULL;
494 return DB_ERROR_UNKNOWN;
495 }
496 mysql_bind->buffer_length = bind->length;
497 mysql_bind->is_unsigned = 0;
498 break;
499
500 default:
501 mysql_free_result(result_metadata);
502 __db_backend_mysql_finish(*statement);
503 *statement = NULL;
504 return DB_ERROR_UNKNOWN;
505 }
506 break;
507
508 default:
509 return DB_ERROR_UNKNOWN;
510 }
511
512 if (!(*statement)->bind_output) {
513 (*statement)->bind_output = bind;
514 }
515 if ((*statement)->bind_output_end) {
516 (*statement)->bind_output_end->next = bind;
517 }
518 (*statement)->bind_output_end = bind;
519 object_field = db_object_field_next(object_field);
520 field = mysql_fetch_field(result_metadata);
521 }
522 /*
523 * If we still have an object field or a MySQL field then the number of
524 * fields in both is mismatching and we should return an error.
525 */
526 if (object_field || field) {
527 mysql_free_result(result_metadata);
528 __db_backend_mysql_finish(*statement);
529 *statement = NULL;
530 return DB_ERROR_UNKNOWN;
531 }
532 }
533 if (result_metadata) {
534 mysql_free_result(result_metadata);
535 }
536
537 return DB_OK;
538}
539
545static inline int __db_backend_mysql_fetch(db_backend_mysql_statement_t* statement) {
546 int ret;
547
548 if (!statement) {
549 return DB_ERROR_UNKNOWN;
550 }
551 if (!statement->statement) {
552 return DB_ERROR_UNKNOWN;
553 }
554
555 /*
556 * Handle output binding if not already done.
557 */
558 if (!statement->bound) {
559 if (statement->mysql_bind_output
560 && mysql_stmt_bind_result(statement->statement, statement->mysql_bind_output))
561 {
562 ods_log_info("DB bind result Err %d: %s", mysql_stmt_errno(statement->statement), mysql_stmt_error(statement->statement));
563 return DB_ERROR_UNKNOWN;
564 }
565 statement->bound = 1;
566 }
567
568 /*
569 * Fetch the next row.
570 */
571 ret = mysql_stmt_fetch(statement->statement);
572 if (ret == 1) {
573 ods_log_info("DB fetch Err %d: %s", mysql_stmt_errno(statement->statement), mysql_stmt_error(statement->statement));
574 return DB_ERROR_UNKNOWN;
575 }
576 else if (ret == MYSQL_DATA_TRUNCATED) {
577 int i;
579
580 /*
581 * Scan through all of the output binds and check where the data was
582 * truncated and reallocate the buffer and try again. MySQL should have
583 * updated bind->length with the required buffer size.
584 *
585 * We can really only retry fetch on string columns, if another type had
586 * a too small buffer its more a programmable error in the prepare
587 * function.
588 */
589 for (i = 0, bind = statement->bind_output; bind; i++, bind = bind->next) {
590 if (bind->error) {
591 if (statement->mysql_bind_output[i].buffer_type != MYSQL_TYPE_STRING
592 || bind->length <= statement->mysql_bind_output[i].buffer_length)
593 {
594 ods_log_info("DB fetch Err data truncated");
595 return DB_ERROR_UNKNOWN;
596 }
597
598 free(statement->mysql_bind_output[i].buffer);
599 statement->mysql_bind_output[i].buffer = NULL;
600 if (!(statement->mysql_bind_output[i].buffer = calloc(1, bind->length))) {
601 ods_log_info("DB fetch Err data truncated");
602 return DB_ERROR_UNKNOWN;
603 }
604 statement->mysql_bind_output[i].buffer_length = bind->length;
605 bind->error = 0;
606 if (mysql_stmt_fetch_column(statement->statement, &(statement->mysql_bind_output[i]), i, 0)
607 || bind->error)
608 {
609 ods_log_info("DB fetch Err data truncated");
610 return DB_ERROR_UNKNOWN;
611 }
612 }
613 }
614 }
615 else if (ret == MYSQL_NO_DATA) {
616 /*
617 * Not really an error but we need to indicate that there is no more
618 * data some how.
619 */
620 return DB_ERROR_UNKNOWN;
621 }
622 else if (ret) {
623 ods_log_info("DB fetch UNKNOWN %d Err %d: %s", ret, mysql_stmt_errno(statement->statement), mysql_stmt_error(statement->statement));
624 return DB_ERROR_UNKNOWN;
625 }
626
627 return DB_OK;
628}
629
635static inline int __db_backend_mysql_execute(db_backend_mysql_statement_t* statement) {
636 if (!statement) {
637 return DB_ERROR_UNKNOWN;
638 }
639 if (!statement->statement) {
640 return DB_ERROR_UNKNOWN;
641 }
642
643 /*
644 * Bind the input parameters.
645 */
646 if (statement->mysql_bind_input
647 && mysql_stmt_bind_param(statement->statement, statement->mysql_bind_input))
648 {
649 ods_log_info("DB bind param Err %d: %s", mysql_stmt_errno(statement->statement), mysql_stmt_error(statement->statement));
650 return DB_ERROR_UNKNOWN;
651 }
652
653 /*
654 * Execute the statement.
655 */
656 if (mysql_stmt_execute(statement->statement)) {
657 ods_log_info("DB execute Err %d: %s", mysql_stmt_errno(statement->statement), mysql_stmt_error(statement->statement));
658 return DB_ERROR_UNKNOWN;
659 }
660
661 return DB_OK;
662}
663
664static int db_backend_mysql_initialize(void* data) {
665 db_backend_mysql_t* backend_mysql = (db_backend_mysql_t*)data;
666
667 if (!backend_mysql) {
668 return DB_ERROR_UNKNOWN;
669 }
670
671 if (!__mysql_initialized) {
672 if (mysql_library_init(0, NULL, NULL)) {
673 return DB_ERROR_UNKNOWN;
674 }
675 __mysql_initialized = 1;
676 }
677 return DB_OK;
678}
679
680static int db_backend_mysql_shutdown(void* data) {
681 db_backend_mysql_t* backend_mysql = (db_backend_mysql_t*)data;
682
683 if (!backend_mysql) {
684 return DB_ERROR_UNKNOWN;
685 }
686
687 if (__mysql_initialized) {
688 mysql_library_end();
689 __mysql_initialized = 0;
690 }
691 return DB_OK;
692}
693
694static int db_backend_mysql_connect(void* data, const db_configuration_list_t* configuration_list) {
695 db_backend_mysql_t* backend_mysql = (db_backend_mysql_t*)data;
696 const db_configuration_t* host;
697 const db_configuration_t* user;
698 const db_configuration_t* pass;
699 const db_configuration_t* db;
700 const db_configuration_t* port_configuration;
701 const db_configuration_t* timeout_configuration;
702 int timeout;
703 unsigned int port = 0;
704
705 if (!__mysql_initialized) {
706 return DB_ERROR_UNKNOWN;
707 }
708 if (!backend_mysql) {
709 return DB_ERROR_UNKNOWN;
710 }
711 if (backend_mysql->db) {
712 return DB_ERROR_UNKNOWN;
713 }
714 if (!configuration_list) {
715 return DB_ERROR_UNKNOWN;
716 }
717
718 host = db_configuration_list_find(configuration_list, "host");
719 user = db_configuration_list_find(configuration_list, "user");
720 pass = db_configuration_list_find(configuration_list, "pass");
721 db = db_configuration_list_find(configuration_list, "db");
722 port_configuration = db_configuration_list_find(configuration_list, "port");
723 if (port_configuration) {
724 port = atoi(db_configuration_value(port_configuration));
725 }
726
728 if ((timeout_configuration = db_configuration_list_find(configuration_list, "timeout"))) {
729 timeout = atoi(db_configuration_value(timeout_configuration));
730 if (timeout < 1) {
732 }
733 else {
734 backend_mysql->timeout = (unsigned int)timeout;
735 }
736 }
737
738 backend_mysql->db_host = (host ? db_configuration_value(host) : NULL);
739 backend_mysql->db_user = (user ? db_configuration_value(user) : NULL);
740 backend_mysql->db_pass = (pass ? db_configuration_value(pass) : NULL);
741 backend_mysql->db_port = port;
742 backend_mysql->db_name = (db ? db_configuration_value(db) : NULL);
743 if (!(backend_mysql->db = mysql_init(NULL))
744 || mysql_options(backend_mysql->db, MYSQL_OPT_CONNECT_TIMEOUT, &backend_mysql->timeout)
745 || !mysql_real_connect(backend_mysql->db,
746 backend_mysql->db_host, backend_mysql->db_user, backend_mysql->db_pass,
747 backend_mysql->db_name, backend_mysql->db_port, NULL, 0)
748 || mysql_autocommit(backend_mysql->db, 1))
749 {
750 if (backend_mysql->db) {
751 ods_log_error("db_backend_mysql: connect failed %d: %s", mysql_errno(backend_mysql->db), mysql_error(backend_mysql->db));
752 mysql_close(backend_mysql->db);
753 backend_mysql->db = NULL;
754 }
755 return DB_ERROR_UNKNOWN;
756 }
757
758 return DB_OK;
759}
760
761static int db_backend_mysql_disconnect(void* data) {
762 db_backend_mysql_t* backend_mysql = (db_backend_mysql_t*)data;
763
764 if (!__mysql_initialized) {
765 return DB_ERROR_UNKNOWN;
766 }
767 if (!backend_mysql) {
768 return DB_ERROR_UNKNOWN;
769 }
770 if (!backend_mysql->db) {
771 return DB_ERROR_UNKNOWN;
772 }
773
774 if (backend_mysql->transaction) {
775 db_backend_mysql_transaction_rollback(backend_mysql);
776 }
777
778 mysql_close(backend_mysql->db);
779 backend_mysql->db = NULL;
780
781 return DB_OK;
782}
783
793static int __db_backend_mysql_build_clause(const db_object_t* object, const db_clause_list_t* clause_list, char** sqlp, int* left) {
794 const db_clause_t* clause;
795 int first, ret;
796
797 if (!clause_list) {
798 return DB_ERROR_UNKNOWN;
799 }
800 if (!sqlp) {
801 return DB_ERROR_UNKNOWN;
802 }
803 if (!*sqlp) {
804 return DB_ERROR_UNKNOWN;
805 }
806 if (!left) {
807 return DB_ERROR_UNKNOWN;
808 }
809 if (*left < 1) {
810 return DB_ERROR_UNKNOWN;
811 }
812
813 clause = db_clause_list_begin(clause_list);
814 first = 1;
815 while (clause) {
816 if (first) {
817 first = 0;
818 }
819 else {
820 switch (db_clause_operator(clause)) {
822 if ((ret = snprintf(*sqlp, *left, " AND")) >= *left) {
823 return DB_ERROR_UNKNOWN;
824 }
825 break;
826
828 if ((ret = snprintf(*sqlp, *left, " OR")) >= *left) {
829 return DB_ERROR_UNKNOWN;
830 }
831 break;
832
833 default:
834 return DB_ERROR_UNKNOWN;
835 }
836 *sqlp += ret;
837 *left -= ret;
838 }
839
840 switch (db_clause_type(clause)) {
841 case DB_CLAUSE_EQUAL:
842 if ((ret = snprintf(*sqlp, *left, " %s.%s = ?",
843 db_object_table(object),
844 db_clause_field(clause))) >= *left)
845 {
846 return DB_ERROR_UNKNOWN;
847 }
848 break;
849
851 if ((ret = snprintf(*sqlp, *left, " %s.%s != ?",
852 db_object_table(object),
853 db_clause_field(clause))) >= *left)
854 {
855 return DB_ERROR_UNKNOWN;
856 }
857 break;
858
860 if ((ret = snprintf(*sqlp, *left, " %s.%s < ?",
861 db_object_table(object),
862 db_clause_field(clause))) >= *left)
863 {
864 return DB_ERROR_UNKNOWN;
865 }
866 break;
867
869 if ((ret = snprintf(*sqlp, *left, " %s.%s <= ?",
870 db_object_table(object),
871 db_clause_field(clause))) >= *left)
872 {
873 return DB_ERROR_UNKNOWN;
874 }
875 break;
876
878 if ((ret = snprintf(*sqlp, *left, " %s.%s >= ?",
879 db_object_table(object),
880 db_clause_field(clause))) >= *left)
881 {
882 return DB_ERROR_UNKNOWN;
883 }
884 break;
885
887 if ((ret = snprintf(*sqlp, *left, " %s.%s > ?",
888 db_object_table(object),
889 db_clause_field(clause))) >= *left)
890 {
891 return DB_ERROR_UNKNOWN;
892 }
893 break;
894
896 if ((ret = snprintf(*sqlp, *left, " %s.%s IS NULL",
897 db_object_table(object),
898 db_clause_field(clause))) >= *left)
899 {
900 return DB_ERROR_UNKNOWN;
901 }
902 break;
903
905 if ((ret = snprintf(*sqlp, *left, " %s.%s IS NOT NULL",
906 db_object_table(object),
907 db_clause_field(clause))) >= *left)
908 {
909 return DB_ERROR_UNKNOWN;
910 }
911 break;
912
913 case DB_CLAUSE_NESTED:
914 if ((ret = snprintf(*sqlp, *left, " (")) >= *left) {
915 return DB_ERROR_UNKNOWN;
916 }
917 *sqlp += ret;
918 *left -= ret;
919 if (__db_backend_mysql_build_clause(object, db_clause_list(clause), sqlp, left)) {
920 return DB_ERROR_UNKNOWN;
921 }
922 if ((ret = snprintf(*sqlp, *left, " )")) >= *left) {
923 return DB_ERROR_UNKNOWN;
924 }
925 break;
926
927 default:
928 return DB_ERROR_UNKNOWN;
929 }
930 *sqlp += ret;
931 *left -= ret;
932
933 clause = db_clause_next(clause);
934 }
935 return DB_OK;
936}
937
943static int __db_backend_mysql_bind_clause(db_backend_mysql_bind_t** bind, const db_clause_list_t* clause_list) {
944 const db_clause_t* clause;
945 const db_type_int32_t* int32;
946 const db_type_uint32_t* uint32;
947 const db_type_int64_t* int64;
948 const db_type_uint64_t* uint64;
949 const char* text;
950
951 if (!bind) {
952 return DB_ERROR_UNKNOWN;
953 }
954 if (!*bind) {
955 return DB_ERROR_UNKNOWN;
956 }
957 if (!clause_list) {
958 return DB_ERROR_UNKNOWN;
959 }
960
961 clause = db_clause_list_begin(clause_list);
962 while (clause) {
963 if (!*bind) {
964 return DB_ERROR_UNKNOWN;
965 }
966
967 (*bind)->bind->length = &((*bind)->bind->buffer_length);
968 (*bind)->bind->is_null = (my_bool*)0;
969
970 switch (db_clause_type(clause)) {
971 case DB_CLAUSE_EQUAL:
977 switch (db_value_type(db_clause_value(clause))) {
979 case DB_TYPE_INT32:
980 if (!(int32 = db_value_int32(db_clause_value(clause)))) {
981 return DB_ERROR_UNKNOWN;
982 }
983 (*bind)->bind->buffer_type = MYSQL_TYPE_LONG;
984 (*bind)->bind->buffer = (void*)int32;
985 (*bind)->bind->buffer_length = sizeof(db_type_int32_t);
986 (*bind)->bind->is_unsigned = 0;
987 break;
988
989 case DB_TYPE_UINT32:
990 if (!(uint32 = db_value_uint32(db_clause_value(clause)))) {
991 return DB_ERROR_UNKNOWN;
992 }
993 (*bind)->bind->buffer_type = MYSQL_TYPE_LONG;
994 (*bind)->bind->buffer = (void*)uint32;
995 (*bind)->bind->buffer_length = sizeof(db_type_uint32_t);
996 (*bind)->bind->is_unsigned = 1;
997 break;
998
999 case DB_TYPE_INT64:
1000 if (!(int64 = db_value_int64(db_clause_value(clause)))) {
1001 return DB_ERROR_UNKNOWN;
1002 }
1003 (*bind)->bind->buffer_type = MYSQL_TYPE_LONGLONG;
1004 (*bind)->bind->buffer = (void*)int64;
1005 (*bind)->bind->buffer_length = sizeof(db_type_int64_t);
1006 (*bind)->bind->is_unsigned = 0;
1007 break;
1008
1009 case DB_TYPE_UINT64:
1010 if (!(uint64 = db_value_uint64(db_clause_value(clause)))) {
1011 return DB_ERROR_UNKNOWN;
1012 }
1013 (*bind)->bind->buffer_type = MYSQL_TYPE_LONGLONG;
1014 (*bind)->bind->buffer = (void*)uint64;
1015 (*bind)->bind->buffer_length = sizeof(db_type_uint64_t);
1016 (*bind)->bind->is_unsigned = 1;
1017 break;
1018
1019 case DB_TYPE_TEXT:
1020 if (!(text = db_value_text(db_clause_value(clause)))) {
1021 return DB_ERROR_UNKNOWN;
1022 }
1023 (*bind)->bind->buffer_type = MYSQL_TYPE_STRING;
1024 (*bind)->bind->buffer = (void*)text;
1025 (*bind)->bind->buffer_length = strlen(text);
1026 (*bind)->bind->is_unsigned = 0;
1027 break;
1028
1029 case DB_TYPE_ENUM:
1030 if (db_value_enum_value(db_clause_value(clause), &((*bind)->value_enum))) {
1031 return DB_ERROR_UNKNOWN;
1032 }
1033 (*bind)->bind->buffer_type = MYSQL_TYPE_LONG;
1034 (*bind)->bind->buffer = (void*)&((*bind)->value_enum);
1035 (*bind)->bind->buffer_length = sizeof(int);
1036 (*bind)->bind->is_unsigned = 0;
1037 break;
1038
1039 default:
1040 return DB_ERROR_UNKNOWN;
1041 }
1042 break;
1043
1044 case DB_CLAUSE_IS_NULL:
1045 /* TODO: is null */
1046 break;
1047
1049 /* TODO: is not null */
1050 break;
1051
1052 case DB_CLAUSE_NESTED:
1053 *bind = (*bind)->next;
1054 if (__db_backend_mysql_bind_clause(bind, db_clause_list(clause))) {
1055 return DB_ERROR_UNKNOWN;
1056 }
1057 clause = db_clause_next(clause);
1058 continue;
1059
1060 default:
1061 return DB_ERROR_UNKNOWN;
1062 }
1063
1064 *bind = (*bind)->next;
1065 clause = db_clause_next(clause);
1066 }
1067 return DB_OK;
1068}
1069
1070static int __db_backend_mysql_bind_value(db_backend_mysql_bind_t* bind, const db_value_t* value) {
1071 const db_type_int32_t* int32;
1072 const db_type_uint32_t* uint32;
1073 const db_type_int64_t* int64;
1074 const db_type_uint64_t* uint64;
1075 const char* text;
1076
1077 if (!bind) {
1078 return DB_ERROR_UNKNOWN;
1079 }
1080 if (!bind->bind) {
1081 return DB_ERROR_UNKNOWN;
1082 }
1083 if (!value) {
1084 return DB_ERROR_UNKNOWN;
1085 }
1086
1087 bind->bind->length = &(bind->bind->buffer_length);
1088 bind->bind->is_null = (my_bool*)0;
1089
1090 switch (db_value_type(value)) {
1092 case DB_TYPE_INT32:
1093 if (!(int32 = db_value_int32(value))) {
1094 return DB_ERROR_UNKNOWN;
1095 }
1096 bind->bind->buffer_type = MYSQL_TYPE_LONG;
1097 bind->bind->buffer = (void*)int32;
1098 bind->bind->buffer_length = sizeof(db_type_int32_t);
1099 bind->bind->is_unsigned = 0;
1100 break;
1101
1102 case DB_TYPE_UINT32:
1103 if (!(uint32 = db_value_uint32(value))) {
1104 return DB_ERROR_UNKNOWN;
1105 }
1106 bind->bind->buffer_type = MYSQL_TYPE_LONG;
1107 bind->bind->buffer = (void*)uint32;
1108 bind->bind->buffer_length = sizeof(db_type_uint32_t);
1109 bind->bind->is_unsigned = 1;
1110 break;
1111
1112 case DB_TYPE_INT64:
1113 if (!(int64 = db_value_int64(value))) {
1114 return DB_ERROR_UNKNOWN;
1115 }
1116 bind->bind->buffer_type = MYSQL_TYPE_LONGLONG;
1117 bind->bind->buffer = (void*)int64;
1118 bind->bind->buffer_length = sizeof(db_type_int64_t);
1119 bind->bind->is_unsigned = 0;
1120 break;
1121
1122 case DB_TYPE_UINT64:
1123 if (!(uint64 = db_value_uint64(value))) {
1124 return DB_ERROR_UNKNOWN;
1125 }
1126 bind->bind->buffer_type = MYSQL_TYPE_LONGLONG;
1127 bind->bind->buffer = (void*)uint64;
1128 bind->bind->buffer_length = sizeof(db_type_uint64_t);
1129 bind->bind->is_unsigned = 1;
1130 break;
1131
1132 case DB_TYPE_TEXT:
1133 if (!(text = db_value_text(value))) {
1134 return DB_ERROR_UNKNOWN;
1135 }
1136 bind->bind->buffer_type = MYSQL_TYPE_STRING;
1137 bind->bind->buffer = (void*)text;
1138 bind->bind->buffer_length = strlen(text);
1139 bind->bind->is_unsigned = 0;
1140 break;
1141
1142 case DB_TYPE_ENUM:
1143 if (db_value_enum_value(value, &(bind->value_enum))) {
1144 return DB_ERROR_UNKNOWN;
1145 }
1146 bind->bind->buffer_type = MYSQL_TYPE_LONG;
1147 bind->bind->buffer = (void*)&(bind->value_enum);
1148 bind->bind->buffer_length = sizeof(int);
1149 bind->bind->is_unsigned = 0;
1150 break;
1151
1152 default:
1153 return DB_ERROR_UNKNOWN;
1154 }
1155
1156 return DB_OK;
1157}
1158
1159static int __db_backend_mysql_bind_value_set(db_backend_mysql_bind_t** bind, const db_value_set_t* value_set) {
1160 size_t i;
1161
1162 if (!bind) {
1163 return DB_ERROR_UNKNOWN;
1164 }
1165 if (!*bind) {
1166 return DB_ERROR_UNKNOWN;
1167 }
1168 if (!value_set) {
1169 return DB_ERROR_UNKNOWN;
1170 }
1171
1172 for (i = 0; i < db_value_set_size(value_set); i++, *bind = (*bind)->next) {
1173 if (!*bind) {
1174 return DB_ERROR_UNKNOWN;
1175 }
1176
1177 if (__db_backend_mysql_bind_value(*bind, db_value_set_at(value_set, i))) {
1178 return DB_ERROR_UNKNOWN;
1179 }
1180 }
1181 return DB_OK;
1182}
1183
1184static db_result_t* db_backend_mysql_next(void* data, int finish) {
1186 db_result_t* result = NULL;
1187 db_value_set_t* value_set = NULL;
1188 const db_object_field_t* object_field;
1190 int value;
1191
1192 if (!statement) {
1193 return NULL;
1194 }
1195 if (!statement->object_field_list) {
1196 return NULL;
1197 }
1198 if (!statement->statement) {
1199 return NULL;
1200 }
1201
1202 if (finish) {
1203 __db_backend_mysql_finish(statement);
1204 return NULL;
1205 }
1206
1207 if (__db_backend_mysql_fetch(statement)) {
1208 return NULL;
1209 }
1210
1211 if (!(result = db_result_new())
1212 || !(value_set = db_value_set_new(statement->fields))
1213 || db_result_set_value_set(result, value_set))
1214 {
1215 db_result_free(result);
1216 db_value_set_free(value_set);
1217 return NULL;
1218 }
1219 object_field = db_object_field_list_begin(statement->object_field_list);
1220 bind = statement->bind_output;
1221 value = 0;
1222 while (object_field) {
1223 if (!bind || !bind->bind || !bind->bind->buffer) {
1224 db_result_free(result);
1225 return NULL;
1226 }
1227
1228 switch (db_object_field_type(object_field)) {
1230 case DB_TYPE_ANY:
1231 case DB_TYPE_REVISION:
1232 switch (bind->bind->buffer_type) {
1233 case MYSQL_TYPE_LONG:
1234 if ((bind->bind->is_unsigned
1235 && db_value_from_uint32(db_value_set_get(value_set, value), *((db_type_uint32_t*)bind->bind->buffer)))
1236 || (!bind->bind->is_unsigned
1237 && db_value_from_int32(db_value_set_get(value_set, value), *((db_type_int32_t*)bind->bind->buffer))))
1238 {
1239 db_result_free(result);
1240 return NULL;
1241 }
1242 break;
1243
1244 case MYSQL_TYPE_LONGLONG:
1245 if ((bind->bind->is_unsigned
1246 && db_value_from_uint64(db_value_set_get(value_set, value), *((db_type_uint64_t*)bind->bind->buffer)))
1247 || (!bind->bind->is_unsigned
1248 && db_value_from_int64(db_value_set_get(value_set, value), *((db_type_int64_t*)bind->bind->buffer))))
1249 {
1250 db_result_free(result);
1251 return NULL;
1252 }
1253 break;
1254
1255 case MYSQL_TYPE_STRING:
1256 if ((!bind->length
1257 && db_value_from_text(db_value_set_get(value_set, value), ""))
1258 || (bind->length
1259 && db_value_from_text2(db_value_set_get(value_set, value), (char*)bind->bind->buffer, bind->length)))
1260 {
1261 db_result_free(result);
1262 return NULL;
1263 }
1264 break;
1265
1266 default:
1267 db_result_free(result);
1268 return NULL;
1269 }
1270 if (db_object_field_type(object_field) == DB_TYPE_PRIMARY_KEY
1271 && db_value_set_primary_key(db_value_set_get(value_set, value)))
1272 {
1273 db_result_free(result);
1274 return NULL;
1275 }
1276 break;
1277
1278 case DB_TYPE_ENUM:
1279 /*
1280 * Enum needs to be handled elsewhere since we don't know the
1281 * enum_set_t here.
1282 */
1283 case DB_TYPE_INT32:
1284 case DB_TYPE_UINT32:
1285 if (bind->bind->buffer_type != MYSQL_TYPE_LONG
1286 || (bind->bind->is_unsigned
1287 && db_value_from_uint32(db_value_set_get(value_set, value), *((db_type_uint32_t*)bind->bind->buffer)))
1288 || (!bind->bind->is_unsigned
1289 && db_value_from_int32(db_value_set_get(value_set, value), *((db_type_int32_t*)bind->bind->buffer))))
1290 {
1291 db_result_free(result);
1292 return NULL;
1293 }
1294 break;
1295
1296 case DB_TYPE_INT64:
1297 case DB_TYPE_UINT64:
1298 if (bind->bind->buffer_type != MYSQL_TYPE_LONGLONG
1299 || (bind->bind->is_unsigned
1300 && db_value_from_uint64(db_value_set_get(value_set, value), *((db_type_uint64_t*)bind->bind->buffer)))
1301 || (!bind->bind->is_unsigned
1302 && db_value_from_int64(db_value_set_get(value_set, value), *((db_type_int64_t*)bind->bind->buffer))))
1303 {
1304 db_result_free(result);
1305 return NULL;
1306 }
1307 break;
1308
1309 case DB_TYPE_TEXT:
1310 if (bind->bind->buffer_type != MYSQL_TYPE_STRING
1311 || (!bind->length
1312 && db_value_from_text(db_value_set_get(value_set, value), ""))
1313 || (bind->length
1314 && db_value_from_text2(db_value_set_get(value_set, value), (char*)bind->bind->buffer, bind->length)))
1315 {
1316 db_result_free(result);
1317 return NULL;
1318 }
1319 break;
1320
1321 default:
1322 db_result_free(result);
1323 return NULL;
1324 }
1325
1326 object_field = db_object_field_next(object_field);
1327 value++;
1328 bind = bind->next;
1329 }
1330 return result;
1331}
1332
1333static int db_backend_mysql_create(void* data, const db_object_t* object, const db_object_field_list_t* object_field_list, const db_value_set_t* value_set) {
1334 db_backend_mysql_t* backend_mysql = (db_backend_mysql_t*)data;
1335 const db_object_field_t* object_field;
1336 const db_object_field_t* revision_field = NULL;
1337 char sql[4*1024];
1338 char* sqlp;
1339 int ret, left, first;
1340 db_backend_mysql_statement_t* statement = NULL;
1342 db_value_t revision = DB_VALUE_EMPTY;
1343
1344 if (!__mysql_initialized) {
1345 return DB_ERROR_UNKNOWN;
1346 }
1347 if (!backend_mysql) {
1348 return DB_ERROR_UNKNOWN;
1349 }
1350 if (!object) {
1351 return DB_ERROR_UNKNOWN;
1352 }
1353 if (!object_field_list) {
1354 return DB_ERROR_UNKNOWN;
1355 }
1356 if (!value_set) {
1357 return DB_ERROR_UNKNOWN;
1358 }
1359
1360 /*
1361 * Check if the object has a revision field and keep it for later use.
1362 */
1364 while (object_field) {
1365 if (db_object_field_type(object_field) == DB_TYPE_REVISION) {
1366 if (revision_field) {
1367 /*
1368 * We do not support multiple revision fields.
1369 */
1370 return DB_ERROR_UNKNOWN;
1371 }
1372
1373 revision_field = object_field;
1374 }
1375 object_field = db_object_field_next(object_field);
1376 }
1377
1378 left = sizeof(sql);
1379 sqlp = sql;
1380 memset(sql, 0, left);
1381
1382 if (!db_object_field_list_begin(object_field_list) && !revision_field) {
1383 /*
1384 * Special case when tables has no fields except maybe a primary key.
1385 */
1386 if ((ret = snprintf(sqlp, left, "INSERT INTO %s () VALUES ()", db_object_table(object))) >= left) {
1387 return DB_ERROR_UNKNOWN;
1388 }
1389 sqlp += ret;
1390 left -= ret;
1391 }
1392 else {
1393 if ((ret = snprintf(sqlp, left, "INSERT INTO %s (", db_object_table(object))) >= left) {
1394 return DB_ERROR_UNKNOWN;
1395 }
1396 sqlp += ret;
1397 left -= ret;
1398
1399 /*
1400 * Add the fields from the given object_field_list.
1401 */
1402 object_field = db_object_field_list_begin(object_field_list);
1403 first = 1;
1404 while (object_field) {
1405 if (first) {
1406 if ((ret = snprintf(sqlp, left, " %s", db_object_field_name(object_field))) >= left) {
1407 return DB_ERROR_UNKNOWN;
1408 }
1409 first = 0;
1410 }
1411 else {
1412 if ((ret = snprintf(sqlp, left, ", %s", db_object_field_name(object_field))) >= left) {
1413 return DB_ERROR_UNKNOWN;
1414 }
1415 }
1416 sqlp += ret;
1417 left -= ret;
1418
1419 object_field = db_object_field_next(object_field);
1420 }
1421
1422 /*
1423 * Add the revision field if we have one.
1424 */
1425 if (revision_field) {
1426 if (first) {
1427 if ((ret = snprintf(sqlp, left, " %s", db_object_field_name(revision_field))) >= left) {
1428 return DB_ERROR_UNKNOWN;
1429 }
1430 first = 0;
1431 }
1432 else {
1433 if ((ret = snprintf(sqlp, left, ", %s", db_object_field_name(revision_field))) >= left) {
1434 return DB_ERROR_UNKNOWN;
1435 }
1436 }
1437 sqlp += ret;
1438 left -= ret;
1439 }
1440
1441 if ((ret = snprintf(sqlp, left, " ) VALUES (")) >= left) {
1442 return DB_ERROR_UNKNOWN;
1443 }
1444 sqlp += ret;
1445 left -= ret;
1446
1447 /*
1448 * Mark all the fields for binding from the object_field_list.
1449 */
1450 object_field = db_object_field_list_begin(object_field_list);
1451 first = 1;
1452 while (object_field) {
1453 if (first) {
1454 if ((ret = snprintf(sqlp, left, " ?")) >= left) {
1455 return DB_ERROR_UNKNOWN;
1456 }
1457 first = 0;
1458 }
1459 else {
1460 if ((ret = snprintf(sqlp, left, ", ?")) >= left) {
1461 return DB_ERROR_UNKNOWN;
1462 }
1463 }
1464 sqlp += ret;
1465 left -= ret;
1466
1467 object_field = db_object_field_next(object_field);
1468 }
1469
1470 /*
1471 * Mark revision field for binding if we have one.
1472 */
1473 if (revision_field) {
1474 if (first) {
1475 if ((ret = snprintf(sqlp, left, " ?")) >= left) {
1476 return DB_ERROR_UNKNOWN;
1477 }
1478 first = 0;
1479 }
1480 else {
1481 if ((ret = snprintf(sqlp, left, ", ?")) >= left) {
1482 return DB_ERROR_UNKNOWN;
1483 }
1484 }
1485 sqlp += ret;
1486 left -= ret;
1487 }
1488
1489 if ((ret = snprintf(sqlp, left, " )")) >= left) {
1490 return DB_ERROR_UNKNOWN;
1491 }
1492 sqlp += ret;
1493 left -= ret;
1494 }
1495
1496 /*
1497 * Prepare the SQL, create a MySQL statement.
1498 */
1499 if (__db_backend_mysql_prepare(backend_mysql, &statement, sql, strlen(sql), db_object_object_field_list(object))
1500 || !statement
1501 || !(bind = statement->bind_input))
1502 {
1503 __db_backend_mysql_finish(statement);
1504 return DB_ERROR_UNKNOWN;
1505 }
1506
1507 /*
1508 * Bind all the values from value_set.
1509 */
1510 if (__db_backend_mysql_bind_value_set(&bind, value_set)) {
1511 __db_backend_mysql_finish(statement);
1512 return DB_ERROR_UNKNOWN;
1513 }
1514
1515 /*
1516 * Bind the revision field value if we have one.
1517 */
1518 if (revision_field) {
1519 if (db_value_from_int64(&revision, 1)
1520 || __db_backend_mysql_bind_value(bind, &revision))
1521 {
1522 db_value_reset(&revision);
1523 __db_backend_mysql_finish(statement);
1524 return DB_ERROR_UNKNOWN;
1525 }
1526 db_value_reset(&revision);
1527 }
1528
1529 /*
1530 * Execute the SQL.
1531 */
1532 if (__db_backend_mysql_execute(statement)
1533 || mysql_stmt_affected_rows(statement->statement) != 1)
1534 {
1535 __db_backend_mysql_finish(statement);
1536 return DB_ERROR_UNKNOWN;
1537 }
1538 __db_backend_mysql_finish(statement);
1539
1540 return DB_OK;
1541}
1542
1543static db_result_list_t* db_backend_mysql_read(void* data, const db_object_t* object, const db_join_list_t* join_list, const db_clause_list_t* clause_list) {
1544 db_backend_mysql_t* backend_mysql = (db_backend_mysql_t*)data;
1545 const db_object_field_t* object_field;
1546 const db_join_t* join;
1547 char sql[4*1024];
1548 char* sqlp;
1549 int ret, left, first;
1550 db_result_list_t* result_list;
1551 db_backend_mysql_statement_t* statement = NULL;
1553
1554 if (!__mysql_initialized) {
1555 return NULL;
1556 }
1557 if (!backend_mysql) {
1558 return NULL;
1559 }
1560 if (!object) {
1561 return NULL;
1562 }
1563
1564 left = sizeof(sql);
1565 sqlp = sql;
1566 memset(sql, 0, left);
1567
1568 if ((ret = snprintf(sqlp, left, "SELECT")) >= left) {
1569 return NULL;
1570 }
1571 sqlp += ret;
1572 left -= ret;
1573
1575 first = 1;
1576 while (object_field) {
1577 if (first) {
1578 if ((ret = snprintf(sqlp, left, " %s.%s", db_object_table(object), db_object_field_name(object_field))) >= left) {
1579 return NULL;
1580 }
1581 first = 0;
1582 }
1583 else {
1584 if ((ret = snprintf(sqlp, left, ", %s.%s", db_object_table(object), db_object_field_name(object_field))) >= left) {
1585 return NULL;
1586 }
1587 }
1588 sqlp += ret;
1589 left -= ret;
1590
1591 object_field = db_object_field_next(object_field);
1592 }
1593
1594 if ((ret = snprintf(sqlp, left, " FROM %s", db_object_table(object))) >= left) {
1595 return NULL;
1596 }
1597 sqlp += ret;
1598 left -= ret;
1599
1600 if (join_list) {
1601 join = db_join_list_begin(join_list);
1602 while (join) {
1603 if ((ret = snprintf(sqlp, left, " INNER JOIN %s ON %s.%s = %s.%s",
1604 db_join_to_table(join),
1605 db_join_to_table(join),
1606 db_join_to_field(join),
1607 db_join_from_table(join),
1608 db_join_from_field(join))) >= left)
1609 {
1610 return NULL;
1611 }
1612 sqlp += ret;
1613 left -= ret;
1614 join = db_join_next(join);
1615 }
1616 }
1617
1618 if (clause_list) {
1619 if (db_clause_list_begin(clause_list)) {
1620 if ((ret = snprintf(sqlp, left, " WHERE")) >= left) {
1621 return NULL;
1622 }
1623 sqlp += ret;
1624 left -= ret;
1625 }
1626 if (__db_backend_mysql_build_clause(object, clause_list, &sqlp, &left)) {
1627 return NULL;
1628 }
1629 }
1630
1631 if (__db_backend_mysql_prepare(backend_mysql, &statement, sql, strlen(sql), db_object_object_field_list(object))
1632 || !statement)
1633 {
1634 __db_backend_mysql_finish(statement);
1635 return NULL;
1636 }
1637
1638 bind = statement->bind_input;
1639
1640 if (clause_list) {
1641 if (__db_backend_mysql_bind_clause(&bind, clause_list)) {
1642 __db_backend_mysql_finish(statement);
1643 return NULL;
1644 }
1645 }
1646
1647 /*
1648 * Execute the SQL.
1649 */
1650 if (__db_backend_mysql_execute(statement)) {
1651 __db_backend_mysql_finish(statement);
1652 return NULL;
1653 }
1654
1655 if (!(result_list = db_result_list_new())
1656 || db_result_list_set_next(result_list, db_backend_mysql_next, statement, mysql_stmt_affected_rows(statement->statement)))
1657 {
1658 db_result_list_free(result_list);
1659 __db_backend_mysql_finish(statement);
1660 return NULL;
1661 }
1662 return result_list;
1663}
1664
1665static int db_backend_mysql_update(void* data, const db_object_t* object, const db_object_field_list_t* object_field_list, const db_value_set_t* value_set, const db_clause_list_t* clause_list) {
1666 db_backend_mysql_t* backend_mysql = (db_backend_mysql_t*)data;
1667 const db_object_field_t* object_field;
1668 const db_object_field_t* revision_field = NULL;
1669 const db_clause_t* clause;
1670 const db_clause_t* revision_clause = NULL;
1671 db_type_int64_t revision_number = -1;
1672 char sql[4*1024];
1673 char* sqlp;
1674 int ret, left, first;
1675 db_backend_mysql_statement_t* statement = NULL;
1677 db_value_t revision = DB_VALUE_EMPTY;
1678 db_type_int32_t int32;
1679 db_type_uint32_t uint32;
1680 db_type_int64_t int64;
1681 db_type_uint64_t uint64;
1682
1683 if (!__mysql_initialized) {
1684 return DB_ERROR_UNKNOWN;
1685 }
1686 if (!backend_mysql) {
1687 return DB_ERROR_UNKNOWN;
1688 }
1689 if (!object) {
1690 return DB_ERROR_UNKNOWN;
1691 }
1692 if (!object_field_list) {
1693 return DB_ERROR_UNKNOWN;
1694 }
1695 if (!value_set) {
1696 return DB_ERROR_UNKNOWN;
1697 }
1698
1699 /*
1700 * Check if the object has a revision field and keep it for later use.
1701 */
1703 while (object_field) {
1704 if (db_object_field_type(object_field) == DB_TYPE_REVISION) {
1705 if (revision_field) {
1706 /*
1707 * We do not support multiple revision fields.
1708 */
1709 return DB_ERROR_UNKNOWN;
1710 }
1711
1712 revision_field = object_field;
1713 }
1714 object_field = db_object_field_next(object_field);
1715 }
1716 if (revision_field) {
1717 /*
1718 * If we have a revision field we should also have it in the clause,
1719 * find it and get the value for later use or return error if not found.
1720 */
1721 clause = db_clause_list_begin(clause_list);
1722 while (clause) {
1723 if (!strcmp(db_clause_field(clause), db_object_field_name(revision_field))) {
1724 revision_clause = clause;
1725 break;
1726 }
1727 clause = db_clause_next(clause);
1728 }
1729 if (!revision_clause) {
1730 return DB_ERROR_UNKNOWN;
1731 }
1732 switch (db_value_type(db_clause_value(revision_clause))) {
1733 case DB_TYPE_INT32:
1734 if (db_value_to_int32(db_clause_value(revision_clause), &int32)) {
1735 return DB_ERROR_UNKNOWN;
1736 }
1737 revision_number = int32;
1738 break;
1739
1740 case DB_TYPE_UINT32:
1741 if (db_value_to_uint32(db_clause_value(revision_clause), &uint32)) {
1742 return DB_ERROR_UNKNOWN;
1743 }
1744 revision_number = uint32;
1745 break;
1746
1747 case DB_TYPE_INT64:
1748 if (db_value_to_int64(db_clause_value(revision_clause), &int64)) {
1749 return DB_ERROR_UNKNOWN;
1750 }
1751 revision_number = int64;
1752 break;
1753
1754 case DB_TYPE_UINT64:
1755 if (db_value_to_uint64(db_clause_value(revision_clause), &uint64)) {
1756 return DB_ERROR_UNKNOWN;
1757 }
1758 revision_number = uint64;
1759 break;
1760
1761 default:
1762 return DB_ERROR_UNKNOWN;
1763 }
1764 }
1765
1766 left = sizeof(sql);
1767 sqlp = sql;
1768 memset(sql, 0, left);
1769
1770 if ((ret = snprintf(sqlp, left, "UPDATE %s SET", db_object_table(object))) >= left) {
1771 return DB_ERROR_UNKNOWN;
1772 }
1773 sqlp += ret;
1774 left -= ret;
1775
1776 /*
1777 * Build the update SQL from the object_field_list.
1778 */
1779 object_field = db_object_field_list_begin(object_field_list);
1780 first = 1;
1781 while (object_field) {
1782 if (first) {
1783 if ((ret = snprintf(sqlp, left, " %s = ?", db_object_field_name(object_field))) >= left) {
1784 return DB_ERROR_UNKNOWN;
1785 }
1786 first = 0;
1787 }
1788 else {
1789 if ((ret = snprintf(sqlp, left, ", %s = ?", db_object_field_name(object_field))) >= left) {
1790 return DB_ERROR_UNKNOWN;
1791 }
1792 }
1793 sqlp += ret;
1794 left -= ret;
1795
1796 object_field = db_object_field_next(object_field);
1797 }
1798
1799 /*
1800 * Add a new revision if we have any.
1801 */
1802 if (revision_field) {
1803 if (first) {
1804 if ((ret = snprintf(sqlp, left, " %s = ?", db_object_field_name(revision_field))) >= left) {
1805 return DB_ERROR_UNKNOWN;
1806 }
1807 first = 0;
1808 }
1809 else {
1810 if ((ret = snprintf(sqlp, left, ", %s = ?", db_object_field_name(revision_field))) >= left) {
1811 return DB_ERROR_UNKNOWN;
1812 }
1813 }
1814 sqlp += ret;
1815 left -= ret;
1816 }
1817
1818 /*
1819 * Build the clauses.
1820 */
1821 if (clause_list) {
1822 if (db_clause_list_begin(clause_list)) {
1823 if ((ret = snprintf(sqlp, left, " WHERE")) >= left) {
1824 return DB_ERROR_UNKNOWN;
1825 }
1826 sqlp += ret;
1827 left -= ret;
1828 }
1829 if (__db_backend_mysql_build_clause(object, clause_list, &sqlp, &left)) {
1830 return DB_ERROR_UNKNOWN;
1831 }
1832 }
1833
1834 /*
1835 * Prepare the SQL.
1836 */
1837 if (__db_backend_mysql_prepare(backend_mysql, &statement, sql, strlen(sql), db_object_object_field_list(object))
1838 || !statement)
1839 {
1840 __db_backend_mysql_finish(statement);
1841 return DB_ERROR_UNKNOWN;
1842 }
1843
1844 bind = statement->bind_input;
1845
1846 /*
1847 * Bind all the values from value_set.
1848 */
1849 if (value_set) {
1850 if (__db_backend_mysql_bind_value_set(&bind, value_set)) {
1851 __db_backend_mysql_finish(statement);
1852 return DB_ERROR_UNKNOWN;
1853 }
1854 }
1855
1856 /*
1857 * Bind the new revision if we have any.
1858 */
1859 if (revision_field) {
1860 if (db_value_from_int64(&revision, revision_number + 1)
1861 || __db_backend_mysql_bind_value(bind, &revision))
1862 {
1863 db_value_reset(&revision);
1864 __db_backend_mysql_finish(statement);
1865 return DB_ERROR_UNKNOWN;
1866 }
1867
1868 if (bind) {
1869 bind = bind->next;
1870 }
1871 }
1872
1873 /*
1874 * Bind the clauses values.
1875 */
1876 if (clause_list) {
1877 if (__db_backend_mysql_bind_clause(&bind, clause_list)) {
1878 __db_backend_mysql_finish(statement);
1879 return DB_ERROR_UNKNOWN;
1880 }
1881 }
1882
1883 /*
1884 * Execute the SQL.
1885 */
1886 if (__db_backend_mysql_execute(statement)) {
1887 __db_backend_mysql_finish(statement);
1888 return DB_ERROR_UNKNOWN;
1889 }
1890
1891 /*
1892 * If we are using revision we have to have a positive number of changes
1893 * otherwise its a failure.
1894 */
1895 if (revision_field) {
1896 if (mysql_stmt_affected_rows(statement->statement) < 1) {
1897 __db_backend_mysql_finish(statement);
1898 return DB_ERROR_UNKNOWN;
1899 }
1900 }
1901
1902 __db_backend_mysql_finish(statement);
1903 return DB_OK;
1904}
1905
1906static int db_backend_mysql_delete(void* data, const db_object_t* object, const db_clause_list_t* clause_list) {
1907 db_backend_mysql_t* backend_mysql = (db_backend_mysql_t*)data;
1908 char sql[4*1024];
1909 char* sqlp;
1910 int ret, left;
1911 const db_object_field_t* revision_field = NULL;
1912 const db_object_field_t* object_field;
1913 const db_clause_t* clause;
1914 db_backend_mysql_statement_t* statement = NULL;
1916
1917 if (!__mysql_initialized) {
1918 return DB_ERROR_UNKNOWN;
1919 }
1920 if (!backend_mysql) {
1921 return DB_ERROR_UNKNOWN;
1922 }
1923 if (!object) {
1924 return DB_ERROR_UNKNOWN;
1925 }
1926
1927 /*
1928 * Check if the object has a revision field and keep it for later use.
1929 */
1931 while (object_field) {
1932 if (db_object_field_type(object_field) == DB_TYPE_REVISION) {
1933 if (revision_field) {
1934 /*
1935 * We do not support multiple revision fields.
1936 */
1937 return DB_ERROR_UNKNOWN;
1938 }
1939
1940 revision_field = object_field;
1941 }
1942 object_field = db_object_field_next(object_field);
1943 }
1944 if (revision_field) {
1945 /*
1946 * If we have a revision field we should also have it in the clause,
1947 * find it or return error if not found.
1948 */
1949 clause = db_clause_list_begin(clause_list);
1950 while (clause) {
1951 if (!strcmp(db_clause_field(clause), db_object_field_name(revision_field))) {
1952 break;
1953 }
1954 clause = db_clause_next(clause);
1955 }
1956 if (!clause) {
1957 return DB_ERROR_UNKNOWN;
1958 }
1959 }
1960
1961 left = sizeof(sql);
1962 sqlp = sql;
1963 memset(sql, 0, left);
1964
1965 if ((ret = snprintf(sqlp, left, "DELETE FROM %s", db_object_table(object))) >= left) {
1966 return DB_ERROR_UNKNOWN;
1967 }
1968 sqlp += ret;
1969 left -= ret;
1970
1971 if (clause_list) {
1972 if (db_clause_list_begin(clause_list)) {
1973 if ((ret = snprintf(sqlp, left, " WHERE")) >= left) {
1974 return DB_ERROR_UNKNOWN;
1975 }
1976 sqlp += ret;
1977 left -= ret;
1978 }
1979 if (__db_backend_mysql_build_clause(object, clause_list, &sqlp, &left)) {
1980 return DB_ERROR_UNKNOWN;
1981 }
1982 }
1983
1984 if (__db_backend_mysql_prepare(backend_mysql, &statement, sql, strlen(sql), db_object_object_field_list(object))
1985 || !statement)
1986 {
1987 __db_backend_mysql_finish(statement);
1988 return DB_ERROR_UNKNOWN;
1989 }
1990
1991 bind = statement->bind_input;
1992
1993 if (clause_list) {
1994 if (__db_backend_mysql_bind_clause(&bind, clause_list)) {
1995 __db_backend_mysql_finish(statement);
1996 return DB_ERROR_UNKNOWN;
1997 }
1998 }
1999
2000 if (__db_backend_mysql_execute(statement)) {
2001 __db_backend_mysql_finish(statement);
2002 return DB_ERROR_UNKNOWN;
2003 }
2004
2005 /*
2006 * If we are using revision we have to have a positive number of changes
2007 * otherwise its a failure.
2008 */
2009 if (revision_field) {
2010 if (mysql_stmt_affected_rows(statement->statement) < 1) {
2011 __db_backend_mysql_finish(statement);
2012 return DB_ERROR_UNKNOWN;
2013 }
2014 }
2015
2016 __db_backend_mysql_finish(statement);
2017 return DB_OK;
2018}
2019
2020static int db_backend_mysql_count(void* data, const db_object_t* object, const db_join_list_t* join_list, const db_clause_list_t* clause_list, size_t* count) {
2021 db_backend_mysql_t* backend_mysql = (db_backend_mysql_t*)data;
2022 const db_join_t* join;
2023 char sql[4*1024];
2024 char* sqlp;
2025 int ret, left;
2026 db_backend_mysql_statement_t* statement = NULL;
2028 db_object_field_list_t* object_field_list;
2029 db_object_field_t* object_field = NULL;
2030
2031 if (!__mysql_initialized) {
2032 return DB_ERROR_UNKNOWN;
2033 }
2034 if (!backend_mysql) {
2035 return DB_ERROR_UNKNOWN;
2036 }
2037 if (!object) {
2038 return DB_ERROR_UNKNOWN;
2039 }
2040 if (!count) {
2041 return DB_ERROR_UNKNOWN;
2042 }
2043
2044 left = sizeof(sql);
2045 sqlp = sql;
2046 memset(sql, 0, left);
2047
2048 if ((ret = snprintf(sqlp, left, "SELECT COUNT(*)")) >= left) {
2049 return DB_ERROR_UNKNOWN;
2050 }
2051 sqlp += ret;
2052 left -= ret;
2053
2054 if ((ret = snprintf(sqlp, left, " FROM %s", db_object_table(object))) >= left) {
2055 return DB_ERROR_UNKNOWN;
2056 }
2057 sqlp += ret;
2058 left -= ret;
2059
2060 if (join_list) {
2061 join = db_join_list_begin(join_list);
2062 while (join) {
2063 if ((ret = snprintf(sqlp, left, " INNER JOIN %s ON %s.%s = %s.%s",
2064 db_join_to_table(join),
2065 db_join_to_table(join),
2066 db_join_to_field(join),
2067 db_join_from_table(join),
2068 db_join_from_field(join))) >= left)
2069 {
2070 return DB_ERROR_UNKNOWN;
2071 }
2072 sqlp += ret;
2073 left -= ret;
2074 join = db_join_next(join);
2075 }
2076 }
2077
2078 if (clause_list) {
2079 if (db_clause_list_begin(clause_list)) {
2080 if ((ret = snprintf(sqlp, left, " WHERE")) >= left) {
2081 return DB_ERROR_UNKNOWN;
2082 }
2083 sqlp += ret;
2084 left -= ret;
2085 }
2086 if (__db_backend_mysql_build_clause(object, clause_list, &sqlp, &left)) {
2087 return DB_ERROR_UNKNOWN;
2088 }
2089 }
2090
2091 if (!(object_field_list = db_object_field_list_new())
2092 || !(object_field = db_object_field_new())
2093 || db_object_field_set_name(object_field, "countField")
2095 || db_object_field_list_add(object_field_list, object_field))
2096 {
2097 db_object_field_free(object_field);
2098 db_object_field_list_free(object_field_list);
2099 return DB_ERROR_UNKNOWN;
2100 }
2101
2102 if (__db_backend_mysql_prepare(backend_mysql, &statement, sql, strlen(sql), object_field_list)
2103 || !statement)
2104 {
2105 db_object_field_list_free(object_field_list);
2106 __db_backend_mysql_finish(statement);
2107 return DB_ERROR_UNKNOWN;
2108 }
2109 db_object_field_list_free(object_field_list);
2110
2111 bind = statement->bind_input;
2112
2113 if (clause_list) {
2114 if (__db_backend_mysql_bind_clause(&bind, clause_list)) {
2115 __db_backend_mysql_finish(statement);
2116 return DB_ERROR_UNKNOWN;
2117 }
2118 }
2119
2120 if (__db_backend_mysql_execute(statement)) {
2121 __db_backend_mysql_finish(statement);
2122 return DB_ERROR_UNKNOWN;
2123 }
2124
2125 if (__db_backend_mysql_fetch(statement)) {
2126 __db_backend_mysql_finish(statement);
2127 return DB_ERROR_UNKNOWN;
2128 }
2129
2130 bind = statement->bind_output;
2131 if (!bind || !bind->bind || !bind->bind->buffer
2132 || bind->bind->buffer_type != MYSQL_TYPE_LONG
2133 || !bind->bind->is_unsigned
2134 || bind->length != sizeof(db_type_uint32_t))
2135 {
2136 __db_backend_mysql_finish(statement);
2137 return DB_ERROR_UNKNOWN;
2138 }
2139
2140 *count = *((db_type_uint32_t*)bind->bind->buffer);
2141 __db_backend_mysql_finish(statement);
2142
2143 return DB_OK;
2144}
2145
2146static void db_backend_mysql_free(void* data) {
2147 db_backend_mysql_t* backend_mysql = (db_backend_mysql_t*)data;
2148
2149 if (backend_mysql) {
2150 if (backend_mysql->db) {
2151 (void)db_backend_mysql_disconnect(backend_mysql);
2152 }
2153 free(backend_mysql);
2154 }
2155}
2156
2157static int db_backend_mysql_transaction_begin(void* data) {
2158 db_backend_mysql_t* backend_mysql = (db_backend_mysql_t*)data;
2159 static const char* sql = "BEGIN TRANSACTION";
2160 db_backend_mysql_statement_t* statement = NULL;
2161
2162 if (!__mysql_initialized) {
2163 return DB_ERROR_UNKNOWN;
2164 }
2165 if (!backend_mysql) {
2166 return DB_ERROR_UNKNOWN;
2167 }
2168 if (backend_mysql->transaction) {
2169 return DB_ERROR_UNKNOWN;
2170 }
2171
2172 if (__db_backend_mysql_prepare(backend_mysql, &statement, sql, strlen(sql), NULL)) {
2173 return DB_ERROR_UNKNOWN;
2174 }
2175
2176 if (__db_backend_mysql_execute(statement)) {
2177 __db_backend_mysql_finish(statement);
2178 return DB_ERROR_UNKNOWN;
2179 }
2180 __db_backend_mysql_finish(statement);
2181
2182 backend_mysql->transaction = 1;
2183 return DB_OK;
2184}
2185
2186static int db_backend_mysql_transaction_commit(void* data) {
2187 db_backend_mysql_t* backend_mysql = (db_backend_mysql_t*)data;
2188 static const char* sql = "COMMIT TRANSACTION";
2189 db_backend_mysql_statement_t* statement = NULL;
2190
2191 if (!__mysql_initialized) {
2192 return DB_ERROR_UNKNOWN;
2193 }
2194 if (!backend_mysql) {
2195 return DB_ERROR_UNKNOWN;
2196 }
2197 if (!backend_mysql->transaction) {
2198 return DB_ERROR_UNKNOWN;
2199 }
2200
2201 if (__db_backend_mysql_prepare(backend_mysql, &statement, sql, strlen(sql), NULL)) {
2202 return DB_ERROR_UNKNOWN;
2203 }
2204
2205 if (__db_backend_mysql_execute(statement)) {
2206 __db_backend_mysql_finish(statement);
2207 return DB_ERROR_UNKNOWN;
2208 }
2209 __db_backend_mysql_finish(statement);
2210
2211 backend_mysql->transaction = 0;
2212 return DB_OK;
2213}
2214
2215static int db_backend_mysql_transaction_rollback(void* data) {
2216 db_backend_mysql_t* backend_mysql = (db_backend_mysql_t*)data;
2217 static const char* sql = "ROLLBACK TRANSACTION";
2218 db_backend_mysql_statement_t* statement = NULL;
2219
2220 if (!__mysql_initialized) {
2221 return DB_ERROR_UNKNOWN;
2222 }
2223 if (!backend_mysql) {
2224 return DB_ERROR_UNKNOWN;
2225 }
2226 if (!backend_mysql->transaction) {
2227 return DB_ERROR_UNKNOWN;
2228 }
2229
2230 if (__db_backend_mysql_prepare(backend_mysql, &statement, sql, strlen(sql), NULL)) {
2231 return DB_ERROR_UNKNOWN;
2232 }
2233
2234 if (__db_backend_mysql_execute(statement)) {
2235 __db_backend_mysql_finish(statement);
2236 return DB_ERROR_UNKNOWN;
2237 }
2238 __db_backend_mysql_finish(statement);
2239
2240 backend_mysql->transaction = 0;
2241 return DB_OK;
2242}
2243
2245 db_backend_handle_t* backend_handle = NULL;
2246 db_backend_mysql_t* backend_mysql =
2247 (db_backend_mysql_t*)calloc(1, sizeof(db_backend_mysql_t));
2248
2249 if (backend_mysql && (backend_handle = db_backend_handle_new())) {
2250 if (db_backend_handle_set_data(backend_handle, (void*)backend_mysql)
2251 || db_backend_handle_set_initialize(backend_handle, db_backend_mysql_initialize)
2252 || db_backend_handle_set_shutdown(backend_handle, db_backend_mysql_shutdown)
2253 || db_backend_handle_set_connect(backend_handle, db_backend_mysql_connect)
2254 || db_backend_handle_set_disconnect(backend_handle, db_backend_mysql_disconnect)
2255 || db_backend_handle_set_create(backend_handle, db_backend_mysql_create)
2256 || db_backend_handle_set_read(backend_handle, db_backend_mysql_read)
2257 || db_backend_handle_set_update(backend_handle, db_backend_mysql_update)
2258 || db_backend_handle_set_delete(backend_handle, db_backend_mysql_delete)
2259 || db_backend_handle_set_count(backend_handle, db_backend_mysql_count)
2260 || db_backend_handle_set_free(backend_handle, db_backend_mysql_free)
2261 || db_backend_handle_set_transaction_begin(backend_handle, db_backend_mysql_transaction_begin)
2262 || db_backend_handle_set_transaction_commit(backend_handle, db_backend_mysql_transaction_commit)
2263 || db_backend_handle_set_transaction_rollback(backend_handle, db_backend_mysql_transaction_rollback))
2264 {
2265 db_backend_handle_free(backend_handle);
2266 free(backend_mysql);
2267 return NULL;
2268 }
2269 }
2270 return backend_handle;
2271}
int db_backend_handle_set_count(db_backend_handle_t *backend_handle, db_backend_handle_count_t count_function)
Definition: db_backend.c:250
int db_backend_handle_set_update(db_backend_handle_t *backend_handle, db_backend_handle_update_t update_function)
Definition: db_backend.c:232
db_backend_handle_t * db_backend_handle_new(void)
Definition: db_backend.c:49
int db_backend_handle_set_shutdown(db_backend_handle_t *backend_handle, db_backend_handle_shutdown_t shutdown_function)
Definition: db_backend.c:187
int db_backend_handle_set_initialize(db_backend_handle_t *backend_handle, db_backend_handle_initialize_t initialize_function)
Definition: db_backend.c:178
void db_backend_handle_free(db_backend_handle_t *backend_handle)
Definition: db_backend.c:56
int db_backend_handle_set_disconnect(db_backend_handle_t *backend_handle, db_backend_handle_disconnect_t disconnect_function)
Definition: db_backend.c:205
int db_backend_handle_set_delete(db_backend_handle_t *backend_handle, db_backend_handle_delete_t delete_function)
Definition: db_backend.c:241
int db_backend_handle_set_transaction_rollback(db_backend_handle_t *backend_handle, db_backend_handle_transaction_rollback_t transaction_rollback_function)
Definition: db_backend.c:286
int db_backend_handle_set_transaction_commit(db_backend_handle_t *backend_handle, db_backend_handle_transaction_commit_t transaction_commit_function)
Definition: db_backend.c:277
int db_backend_handle_set_transaction_begin(db_backend_handle_t *backend_handle, db_backend_handle_transaction_begin_t transaction_begin_function)
Definition: db_backend.c:268
int db_backend_handle_set_read(db_backend_handle_t *backend_handle, db_backend_handle_read_t read_function)
Definition: db_backend.c:223
int db_backend_handle_set_create(db_backend_handle_t *backend_handle, db_backend_handle_create_t create_function)
Definition: db_backend.c:214
int db_backend_handle_set_data(db_backend_handle_t *backend_handle, void *data)
Definition: db_backend.c:295
int db_backend_handle_set_free(db_backend_handle_t *backend_handle, db_backend_handle_free_t free_function)
Definition: db_backend.c:259
int db_backend_handle_set_connect(db_backend_handle_t *backend_handle, db_backend_handle_connect_t connect_function)
Definition: db_backend.c:196
db_backend_handle_t * db_backend_mysql_new_handle(void)
struct db_backend_mysql_statement db_backend_mysql_statement_t
char my_bool
struct db_backend_mysql db_backend_mysql_t
#define DB_BACKEND_MYSQL_STRING_MIN_SIZE
#define DB_BACKEND_MYSQL_DEFAULT_TIMEOUT
const db_clause_list_t * db_clause_list(const db_clause_t *clause)
Definition: db_clause.c:101
db_clause_operator_t db_clause_operator(const db_clause_t *clause)
Definition: db_clause.c:93
const db_value_t * db_clause_value(const db_clause_t *clause)
Definition: db_clause.c:85
db_clause_type_t db_clause_type(const db_clause_t *clause)
Definition: db_clause.c:77
const db_clause_t * db_clause_next(const db_clause_t *clause)
Definition: db_clause.c:179
const char * db_clause_field(const db_clause_t *clause)
Definition: db_clause.c:69
const db_clause_t * db_clause_list_begin(const db_clause_list_t *clause_list)
Definition: db_clause.c:255
@ DB_CLAUSE_OPERATOR_AND
Definition: db_clause.h:97
@ DB_CLAUSE_OPERATOR_OR
Definition: db_clause.h:101
@ DB_CLAUSE_NESTED
Definition: db_clause.h:76
@ DB_CLAUSE_GREATER_THEN
Definition: db_clause.h:64
@ DB_CLAUSE_NOT_EQUAL
Definition: db_clause.h:48
@ DB_CLAUSE_IS_NOT_NULL
Definition: db_clause.h:72
@ DB_CLAUSE_GREATER_OR_EQUAL
Definition: db_clause.h:60
@ DB_CLAUSE_IS_NULL
Definition: db_clause.h:68
@ DB_CLAUSE_EQUAL
Definition: db_clause.h:44
@ DB_CLAUSE_LESS_OR_EQUAL
Definition: db_clause.h:56
@ DB_CLAUSE_LESS_THEN
Definition: db_clause.h:52
const char * db_configuration_value(const db_configuration_t *configuration)
const db_configuration_t * db_configuration_list_find(const db_configuration_list_t *configuration_list, const char *name)
#define DB_ERROR_UNKNOWN
Definition: db_error.h:40
#define DB_OK
Definition: db_error.h:36
const char * db_join_from_table(const db_join_t *join)
Definition: db_join.c:41
const char * db_join_from_field(const db_join_t *join)
Definition: db_join.c:49
const db_join_t * db_join_list_begin(const db_join_list_t *join_list)
Definition: db_join.c:85
const char * db_join_to_table(const db_join_t *join)
Definition: db_join.c:57
const db_join_t * db_join_next(const db_join_t *join)
Definition: db_join.c:73
const char * db_join_to_field(const db_join_t *join)
Definition: db_join.c:65
db_object_field_list_t * db_object_field_list_new_copy(const db_object_field_list_t *from_object_field_list)
Definition: db_object.c:182
const db_object_field_t * db_object_field_list_begin(const db_object_field_list_t *object_field_list)
Definition: db_object.c:284
db_type_t db_object_field_type(const db_object_field_t *object_field)
Definition: db_object.c:102
db_object_field_t * db_object_field_new(void)
Definition: db_object.c:40
int db_object_field_list_add(db_object_field_list_t *object_field_list, db_object_field_t *object_field)
Definition: db_object.c:254
int db_object_field_set_name(db_object_field_t *object_field, const char *name)
Definition: db_object.c:110
int db_object_field_set_type(db_object_field_t *object_field, db_type_t type)
Definition: db_object.c:122
const db_object_field_list_t * db_object_object_field_list(const db_object_t *object)
Definition: db_object.c:334
size_t db_object_field_list_size(const db_object_field_list_t *object_field_list)
Definition: db_object.c:292
const char * db_object_table(const db_object_t *object)
Definition: db_object.c:327
db_object_field_list_t * db_object_field_list_new(void)
Definition: db_object.c:174
const char * db_object_field_name(const db_object_field_t *object_field)
Definition: db_object.c:94
void db_object_field_free(db_object_field_t *object_field)
Definition: db_object.c:69
void db_object_field_list_free(db_object_field_list_t *object_field_list)
Definition: db_object.c:199
const db_object_field_t * db_object_field_next(const db_object_field_t *object_field)
Definition: db_object.c:162
int db_result_set_value_set(db_result_t *result, db_value_set_t *value_set)
Definition: db_result.c:105
db_result_list_t * db_result_list_new(void)
Definition: db_result.c:134
int db_result_list_set_next(db_result_list_t *result_list, db_result_list_next_t next_function, void *next_data, size_t size)
Definition: db_result.c:234
db_result_t * db_result_new(void)
Definition: db_result.c:38
void db_result_free(db_result_t *result)
Definition: db_result.c:63
void db_result_list_free(db_result_list_t *result_list)
Definition: db_result.c:160
@ DB_TYPE_INT64
Definition: db_type.h:74
@ DB_TYPE_UINT64
Definition: db_type.h:78
@ DB_TYPE_PRIMARY_KEY
Definition: db_type.h:62
@ DB_TYPE_REVISION
Definition: db_type.h:97
@ DB_TYPE_TEXT
Definition: db_type.h:82
@ DB_TYPE_INT32
Definition: db_type.h:66
@ DB_TYPE_ENUM
Definition: db_type.h:86
@ DB_TYPE_UINT32
Definition: db_type.h:70
@ DB_TYPE_ANY
Definition: db_type.h:90
uint64_t db_type_uint64_t
Definition: db_type.h:50
uint32_t db_type_uint32_t
Definition: db_type.h:42
int64_t db_type_int64_t
Definition: db_type.h:46
int32_t db_type_int32_t
Definition: db_type.h:38
const db_type_int64_t * db_value_int64(const db_value_t *value)
Definition: db_value.c:299
const db_type_int32_t * db_value_int32(const db_value_t *value)
Definition: db_value.c:277
int db_value_to_int32(const db_value_t *value, db_type_int32_t *to_int32)
Definition: db_value.c:357
db_type_t db_value_type(const db_value_t *value)
Definition: db_value.c:269
const db_value_t * db_value_set_at(const db_value_set_t *value_set, size_t at)
Definition: db_value.c:742
int db_value_set_primary_key(db_value_t *value)
Definition: db_value.c:595
db_value_t * db_value_set_get(db_value_set_t *value_set, size_t at)
Definition: db_value.c:756
void db_value_set_free(db_value_set_t *value_set)
Definition: db_value.c:697
int db_value_from_uint32(db_value_t *value, db_type_uint32_t from_uint32)
Definition: db_value.c:492
db_value_set_t * db_value_set_new(size_t size)
Definition: db_value.c:622
int db_value_to_int64(const db_value_t *value, db_type_int64_t *to_int64)
Definition: db_value.c:387
int db_value_from_text(db_value_t *value, const char *from_text)
Definition: db_value.c:531
int db_value_from_int32(db_value_t *value, db_type_int32_t from_int32)
Definition: db_value.c:479
int db_value_from_int64(db_value_t *value, db_type_int64_t from_int64)
Definition: db_value.c:505
const db_type_uint32_t * db_value_uint32(const db_value_t *value)
Definition: db_value.c:288
size_t db_value_set_size(const db_value_set_t *value_set)
Definition: db_value.c:734
int db_value_to_uint32(const db_value_t *value, db_type_uint32_t *to_uint32)
Definition: db_value.c:372
int db_value_from_text2(db_value_t *value, const char *from_text, size_t size)
Definition: db_value.c:550
int db_value_enum_value(const db_value_t *value, int *enum_value)
Definition: db_value.c:332
const db_type_uint64_t * db_value_uint64(const db_value_t *value)
Definition: db_value.c:310
int db_value_to_uint64(const db_value_t *value, db_type_uint64_t *to_uint64)
Definition: db_value.c:402
void db_value_reset(db_value_t *value)
Definition: db_value.c:60
int db_value_from_uint64(db_value_t *value, db_type_uint64_t from_uint64)
Definition: db_value.c:518
const char * db_value_text(const db_value_t *value)
Definition: db_value.c:321
#define DB_VALUE_EMPTY
Definition: db_value.h:60
db_backend_mysql_bind_t * next
db_backend_mysql_bind_t * bind_input
db_backend_mysql_bind_t * bind_output_end
db_backend_mysql_bind_t * bind_input_end
db_backend_mysql_bind_t * bind_output
db_backend_mysql_t * backend_mysql
db_object_field_list_t * object_field_list
const char * db_user
const char * db_host
unsigned int timeout
const char * db_pass
const char * db_name