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