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