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