OpenDNSSEC-enforcer  2.1.9
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
39 typedef 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 
50 static int db_backend_mysql_transaction_rollback(void*);
51 
55 static int __mysql_initialized = 0;
56 
60 typedef 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;
68  int db_port;
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;
100  int fields;
101  int bound;
103 
104 
105 
111 static 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 
148 static 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 
174 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) {
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)) {
284  case DB_TYPE_PRIMARY_KEY:
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 
545 static 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 
635 static 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 
664 static 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 
680 static 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 
694 static 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 
727  backend_mysql->timeout = DB_BACKEND_MYSQL_DEFAULT_TIMEOUT;
728  if ((timeout_configuration = db_configuration_list_find(configuration_list, "timeout"))) {
729  timeout = atoi(db_configuration_value(timeout_configuration));
730  if (timeout < 1) {
731  backend_mysql->timeout = DB_BACKEND_MYSQL_DEFAULT_TIMEOUT;
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 
761 static 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 
793 static 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 
850  case DB_CLAUSE_NOT_EQUAL:
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 
859  case DB_CLAUSE_LESS_THEN:
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 
895  case DB_CLAUSE_IS_NULL:
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 
943 static 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:
972  case DB_CLAUSE_NOT_EQUAL:
973  case DB_CLAUSE_LESS_THEN:
977  switch (db_value_type(db_clause_value(clause))) {
978  case DB_TYPE_PRIMARY_KEY:
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 
1048  case DB_CLAUSE_IS_NOT_NULL:
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 
1070 static 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)) {
1091  case DB_TYPE_PRIMARY_KEY:
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 
1159 static 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 
1184 static 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)) {
1229  case DB_TYPE_PRIMARY_KEY:
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 
1333 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) {
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 
1543 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) {
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 
1665 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) {
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 
1906 static 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 
2020 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) {
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")
2094  || db_object_field_set_type(object_field, DB_TYPE_UINT32)
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 
2146 static 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 
2157 static 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 
2186 static 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 
2215 static 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
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
db_backend_handle_t * db_backend_handle_new(void)
Definition: db_backend.c:49
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
struct db_backend_mysql_statement db_backend_mysql_statement_t
char my_bool
struct db_backend_mysql db_backend_mysql_t
db_backend_handle_t * db_backend_mysql_new_handle(void)
#define DB_BACKEND_MYSQL_STRING_MIN_SIZE
#define DB_BACKEND_MYSQL_DEFAULT_TIMEOUT
db_clause_operator_t db_clause_operator(const db_clause_t *clause)
Definition: db_clause.c:93
const char * db_clause_field(const db_clause_t *clause)
Definition: db_clause.c:69
db_clause_type_t db_clause_type(const db_clause_t *clause)
Definition: db_clause.c:77
const db_clause_t * db_clause_list_begin(const db_clause_list_t *clause_list)
Definition: db_clause.c:255
const db_value_t * db_clause_value(const db_clause_t *clause)
Definition: db_clause.c:85
const db_clause_list_t * db_clause_list(const db_clause_t *clause)
Definition: db_clause.c:101
const db_clause_t * db_clause_next(const db_clause_t *clause)
Definition: db_clause.c:179
@ 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_to_table(const db_join_t *join)
Definition: db_join.c:57
const char * db_join_to_field(const db_join_t *join)
Definition: db_join.c:65
const char * db_join_from_table(const db_join_t *join)
Definition: db_join.c:41
const db_join_t * db_join_next(const db_join_t *join)
Definition: db_join.c:73
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 db_object_field_t * db_object_field_next(const db_object_field_t *object_field)
Definition: db_object.c:162
db_type_t db_object_field_type(const db_object_field_t *object_field)
Definition: db_object.c:102
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
const char * db_object_field_name(const db_object_field_t *object_field)
Definition: db_object.c:94
db_object_field_t * db_object_field_new(void)
Definition: db_object.c:40
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_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
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 char * db_object_table(const db_object_t *object)
Definition: db_object.c:327
size_t db_object_field_list_size(const db_object_field_list_t *object_field_list)
Definition: db_object.c:292
db_object_field_list_t * db_object_field_list_new(void)
Definition: db_object.c:174
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_list_t * db_object_object_field_list(const db_object_t *object)
Definition: db_object.c:334
db_result_list_t * db_result_list_new(void)
Definition: db_result.c:134
db_result_t * db_result_new(void)
Definition: db_result.c:38
int db_result_set_value_set(db_result_t *result, db_value_set_t *value_set)
Definition: db_result.c:105
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
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
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_type_uint32_t * db_value_uint32(const db_value_t *value)
Definition: db_value.c:288
int db_value_set_primary_key(db_value_t *value)
Definition: db_value.c:595
void db_value_set_free(db_value_set_t *value_set)
Definition: db_value.c:697
const char * db_value_text(const db_value_t *value)
Definition: db_value.c:321
int db_value_from_uint32(db_value_t *value, db_type_uint32_t from_uint32)
Definition: db_value.c:492
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_uint64_t * db_value_uint64(const db_value_t *value)
Definition: db_value.c:310
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
const db_type_int32_t * db_value_int32(const db_value_t *value)
Definition: db_value.c:277
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_enum_value(const db_value_t *value, int *enum_value)
Definition: db_value.c:332
db_value_set_t * db_value_set_new(size_t size)
Definition: db_value.c:622
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
db_value_t * db_value_set_get(db_value_set_t *value_set, size_t at)
Definition: db_value.c:756
const db_type_int64_t * db_value_int64(const db_value_t *value)
Definition: db_value.c:299
int db_value_from_uint64(db_value_t *value, db_type_uint64_t from_uint64)
Definition: db_value.c:518
#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