35 #include <mysql/mysql.h>
45 static int db_backend_mysql_transaction_rollback(
void*);
50 static int __mysql_initialized = 0;
122 if (bind->
bind && bind->
bind->buffer) {
123 free(bind->
bind->buffer);
144 unsigned long i, params;
147 MYSQL_BIND* mysql_bind;
148 MYSQL_RES* result_metadata = NULL;
151 if (!backend_mysql) {
154 if (!backend_mysql->
db) {
170 ods_log_debug(
"%s", sql);
172 || !((*statement)->statement = mysql_stmt_init(backend_mysql->
db))
173 || mysql_stmt_prepare((*statement)->statement, sql, size))
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));
179 __db_backend_mysql_finish(*statement);
184 (*statement)->backend_mysql = backend_mysql;
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);
197 for (i = 0; i < params; i++) {
199 __db_backend_mysql_finish(*statement);
204 bind->
bind = &((*statement)->mysql_bind_input[i]);
205 if (!(*statement)->bind_input) {
206 (*statement)->bind_input = bind;
208 if ((*statement)->bind_input_end) {
209 (*statement)->bind_input_end->
next = bind;
211 (*statement)->bind_input_end = bind;
218 if (object_field_list
220 && (result_metadata = mysql_stmt_result_metadata((*statement)->statement)))
223 || !((*statement)->mysql_bind_output = calloc(params,
sizeof(MYSQL_BIND))))
225 mysql_free_result(result_metadata);
226 __db_backend_mysql_finish(*statement);
231 (*statement)->fields = params;
232 field = mysql_fetch_field(result_metadata);
234 for (i = 0; i < params; i++) {
239 mysql_free_result(result_metadata);
240 __db_backend_mysql_finish(*statement);
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;
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;
259 mysql_free_result(result_metadata);
260 __db_backend_mysql_finish(*statement);
265 bind->
length = mysql_bind->buffer_length;
266 mysql_bind->is_unsigned = 1;
269 case MYSQL_TYPE_LONGLONG:
270 mysql_bind->buffer_type = MYSQL_TYPE_LONGLONG;
272 mysql_free_result(result_metadata);
273 __db_backend_mysql_finish(*statement);
278 bind->
length = mysql_bind->buffer_length;
279 mysql_bind->is_unsigned = 1;
282 case MYSQL_TYPE_STRING:
283 case MYSQL_TYPE_VAR_STRING:
284 mysql_bind->buffer_type = MYSQL_TYPE_STRING;
289 bind->
length = field->length + 1;
293 if (!(mysql_bind->buffer = calloc(1, bind->
length))) {
294 mysql_free_result(result_metadata);
295 __db_backend_mysql_finish(*statement);
299 mysql_bind->buffer_length = bind->
length;
300 mysql_bind->is_unsigned = 0;
304 mysql_free_result(result_metadata);
305 __db_backend_mysql_finish(*statement);
319 mysql_bind->buffer_type = MYSQL_TYPE_LONG;
321 mysql_free_result(result_metadata);
322 __db_backend_mysql_finish(*statement);
327 bind->
length = mysql_bind->buffer_length;
328 mysql_bind->is_unsigned = 0;
332 mysql_bind->buffer_type = MYSQL_TYPE_LONG;
334 mysql_free_result(result_metadata);
335 __db_backend_mysql_finish(*statement);
340 bind->
length = mysql_bind->buffer_length;
341 mysql_bind->is_unsigned = 1;
345 mysql_bind->buffer_type = MYSQL_TYPE_LONGLONG;
347 mysql_free_result(result_metadata);
348 __db_backend_mysql_finish(*statement);
353 bind->
length = mysql_bind->buffer_length;
354 mysql_bind->is_unsigned = 0;
358 mysql_bind->buffer_type = MYSQL_TYPE_LONGLONG;
360 mysql_free_result(result_metadata);
361 __db_backend_mysql_finish(*statement);
366 bind->
length = mysql_bind->buffer_length;
367 mysql_bind->is_unsigned = 1;
371 mysql_bind->buffer_type = MYSQL_TYPE_STRING;
376 bind->
length = field->length + 1;
380 if (!(mysql_bind->buffer = calloc(1, bind->
length))) {
381 mysql_free_result(result_metadata);
382 __db_backend_mysql_finish(*statement);
386 mysql_bind->buffer_length = bind->
length;
387 mysql_bind->is_unsigned = 0;
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) {
400 mysql_free_result(result_metadata);
401 __db_backend_mysql_finish(*statement);
406 mysql_bind->is_unsigned = 1;
410 mysql_free_result(result_metadata);
411 __db_backend_mysql_finish(*statement);
416 mysql_bind->is_unsigned = 0;
418 bind->
length = mysql_bind->buffer_length;
421 case MYSQL_TYPE_LONGLONG:
422 mysql_bind->buffer_type = MYSQL_TYPE_LONGLONG;
423 if (field->flags & UNSIGNED_FLAG) {
425 mysql_free_result(result_metadata);
426 __db_backend_mysql_finish(*statement);
431 mysql_bind->is_unsigned = 1;
435 mysql_free_result(result_metadata);
436 __db_backend_mysql_finish(*statement);
441 mysql_bind->is_unsigned = 0;
443 bind->
length = mysql_bind->buffer_length;
446 case MYSQL_TYPE_STRING:
447 case MYSQL_TYPE_VAR_STRING:
448 mysql_bind->buffer_type = MYSQL_TYPE_STRING;
453 bind->
length = field->length + 1;
457 if (!(mysql_bind->buffer = calloc(1, bind->
length))) {
458 mysql_free_result(result_metadata);
459 __db_backend_mysql_finish(*statement);
463 mysql_bind->buffer_length = bind->
length;
464 mysql_bind->is_unsigned = 0;
468 mysql_free_result(result_metadata);
469 __db_backend_mysql_finish(*statement);
479 if (!(*statement)->bind_output) {
480 (*statement)->bind_output = bind;
482 if ((*statement)->bind_output_end) {
483 (*statement)->bind_output_end->
next = bind;
485 (*statement)->bind_output_end = bind;
487 field = mysql_fetch_field(result_metadata);
493 if (object_field || field) {
494 mysql_free_result(result_metadata);
495 __db_backend_mysql_finish(*statement);
500 if (result_metadata) {
501 mysql_free_result(result_metadata);
525 if (!statement->
bound) {
529 ods_log_info(
"DB bind result Err %d: %s", mysql_stmt_errno(statement->
statement), mysql_stmt_error(statement->
statement));
532 statement->
bound = 1;
538 ret = mysql_stmt_fetch(statement->
statement);
540 ods_log_info(
"DB fetch Err %d: %s", mysql_stmt_errno(statement->
statement), mysql_stmt_error(statement->
statement));
543 else if (ret == MYSQL_DATA_TRUNCATED) {
556 for (i = 0, bind = statement->
bind_output; bind; i++, bind = bind->
next) {
561 ods_log_info(
"DB fetch Err data truncated");
568 ods_log_info(
"DB fetch Err data truncated");
576 ods_log_info(
"DB fetch Err data truncated");
582 else if (ret == MYSQL_NO_DATA) {
590 ods_log_info(
"DB fetch UNKNOWN %d Err %d: %s", ret, mysql_stmt_errno(statement->
statement), mysql_stmt_error(statement->
statement));
616 ods_log_info(
"DB bind param Err %d: %s", mysql_stmt_errno(statement->
statement), mysql_stmt_error(statement->
statement));
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));
631 static int db_backend_mysql_initialize(
void* data) {
634 if (!backend_mysql) {
638 if (!__mysql_initialized) {
639 if (mysql_library_init(0, NULL, NULL)) {
642 __mysql_initialized = 1;
647 static int db_backend_mysql_shutdown(
void* data) {
650 if (!backend_mysql) {
654 if (__mysql_initialized) {
656 __mysql_initialized = 0;
670 unsigned int port = 0;
672 if (!__mysql_initialized) {
675 if (!backend_mysql) {
678 if (backend_mysql->
db) {
681 if (!configuration_list) {
690 if (port_configuration) {
701 backend_mysql->
timeout = (
unsigned int)timeout;
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,
715 || mysql_autocommit(backend_mysql->
db, 1))
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;
728 static int db_backend_mysql_disconnect(
void* data) {
731 if (!__mysql_initialized) {
734 if (!backend_mysql) {
737 if (!backend_mysql->
db) {
742 db_backend_mysql_transaction_rollback(backend_mysql);
745 mysql_close(backend_mysql->
db);
746 backend_mysql->
db = NULL;
760 static int __db_backend_mysql_build_clause(
const db_object_t*
object,
const db_clause_list_t* clause_list,
char** sqlp,
int* left) {
789 if ((ret = snprintf(*sqlp, *left,
" AND")) >= *left) {
795 if ((ret = snprintf(*sqlp, *left,
" OR")) >= *left) {
809 if ((ret = snprintf(*sqlp, *left,
" %s.%s = ?",
818 if ((ret = snprintf(*sqlp, *left,
" %s.%s != ?",
827 if ((ret = snprintf(*sqlp, *left,
" %s.%s < ?",
836 if ((ret = snprintf(*sqlp, *left,
" %s.%s <= ?",
845 if ((ret = snprintf(*sqlp, *left,
" %s.%s >= ?",
854 if ((ret = snprintf(*sqlp, *left,
" %s.%s > ?",
863 if ((ret = snprintf(*sqlp, *left,
" %s.%s IS NULL",
872 if ((ret = snprintf(*sqlp, *left,
" %s.%s IS NOT NULL",
881 if ((ret = snprintf(*sqlp, *left,
" (")) >= *left) {
886 if (__db_backend_mysql_build_clause(
object,
db_clause_list(clause), sqlp, left)) {
889 if ((ret = snprintf(*sqlp, *left,
" )")) >= *left) {
934 (*bind)->bind->length = &((*bind)->bind->buffer_length);
935 (*bind)->bind->is_null = (
my_bool*)0;
950 (*bind)->bind->buffer_type = MYSQL_TYPE_LONG;
951 (*bind)->bind->buffer = (
void*)int32;
953 (*bind)->bind->is_unsigned = 0;
960 (*bind)->bind->buffer_type = MYSQL_TYPE_LONG;
961 (*bind)->bind->buffer = (
void*)uint32;
963 (*bind)->bind->is_unsigned = 1;
970 (*bind)->bind->buffer_type = MYSQL_TYPE_LONGLONG;
971 (*bind)->bind->buffer = (
void*)int64;
973 (*bind)->bind->is_unsigned = 0;
980 (*bind)->bind->buffer_type = MYSQL_TYPE_LONGLONG;
981 (*bind)->bind->buffer = (
void*)uint64;
983 (*bind)->bind->is_unsigned = 1;
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;
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;
1020 *bind = (*bind)->
next;
1021 if (__db_backend_mysql_bind_clause(bind,
db_clause_list(clause))) {
1031 *bind = (*bind)->
next;
1054 bind->
bind->length = &(bind->
bind->buffer_length);
1063 bind->
bind->buffer_type = MYSQL_TYPE_LONG;
1064 bind->
bind->buffer = (
void*)int32;
1066 bind->
bind->is_unsigned = 0;
1073 bind->
bind->buffer_type = MYSQL_TYPE_LONG;
1074 bind->
bind->buffer = (
void*)uint32;
1076 bind->
bind->is_unsigned = 1;
1083 bind->
bind->buffer_type = MYSQL_TYPE_LONGLONG;
1084 bind->
bind->buffer = (
void*)int64;
1086 bind->
bind->is_unsigned = 0;
1093 bind->
bind->buffer_type = MYSQL_TYPE_LONGLONG;
1094 bind->
bind->buffer = (
void*)uint64;
1096 bind->
bind->is_unsigned = 1;
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;
1113 bind->
bind->buffer_type = MYSQL_TYPE_LONG;
1115 bind->
bind->buffer_length =
sizeof(int);
1116 bind->
bind->is_unsigned = 0;
1144 if (__db_backend_mysql_bind_value(*bind,
db_value_set_at(value_set, i))) {
1151 static db_result_t* db_backend_mysql_next(
void* data,
int finish) {
1170 __db_backend_mysql_finish(statement);
1174 if (__db_backend_mysql_fetch(statement)) {
1189 while (object_field) {
1190 if (!bind || !bind->
bind || !bind->
bind->buffer) {
1199 switch (bind->
bind->buffer_type) {
1200 case MYSQL_TYPE_LONG:
1201 if ((bind->
bind->is_unsigned
1203 || (!bind->
bind->is_unsigned
1211 case MYSQL_TYPE_LONGLONG:
1212 if ((bind->
bind->is_unsigned
1214 || (!bind->
bind->is_unsigned
1222 case MYSQL_TYPE_STRING:
1252 if (bind->
bind->buffer_type != MYSQL_TYPE_LONG
1253 || (bind->
bind->is_unsigned
1255 || (!bind->
bind->is_unsigned
1265 if (bind->
bind->buffer_type != MYSQL_TYPE_LONGLONG
1266 || (bind->
bind->is_unsigned
1268 || (!bind->
bind->is_unsigned
1277 if (bind->
bind->buffer_type != MYSQL_TYPE_STRING
1306 int ret, left, first;
1311 if (!__mysql_initialized) {
1314 if (!backend_mysql) {
1320 if (!object_field_list) {
1331 while (object_field) {
1333 if (revision_field) {
1340 revision_field = object_field;
1347 memset(sql, 0, left);
1353 if ((ret = snprintf(sqlp, left,
"INSERT INTO %s () VALUES ()",
db_object_table(
object))) >= left) {
1360 if ((ret = snprintf(sqlp, left,
"INSERT INTO %s (",
db_object_table(
object))) >= left) {
1371 while (object_field) {
1392 if (revision_field) {
1408 if ((ret = snprintf(sqlp, left,
" ) VALUES (")) >= left) {
1419 while (object_field) {
1421 if ((ret = snprintf(sqlp, left,
" ?")) >= left) {
1427 if ((ret = snprintf(sqlp, left,
", ?")) >= left) {
1440 if (revision_field) {
1442 if ((ret = snprintf(sqlp, left,
" ?")) >= left) {
1448 if ((ret = snprintf(sqlp, left,
", ?")) >= left) {
1456 if ((ret = snprintf(sqlp, left,
" )")) >= left) {
1470 __db_backend_mysql_finish(statement);
1477 if (__db_backend_mysql_bind_value_set(&bind, value_set)) {
1478 __db_backend_mysql_finish(statement);
1485 if (revision_field) {
1487 || __db_backend_mysql_bind_value(bind, &revision))
1490 __db_backend_mysql_finish(statement);
1499 if (__db_backend_mysql_execute(statement)
1500 || mysql_stmt_affected_rows(statement->
statement) != 1)
1502 __db_backend_mysql_finish(statement);
1505 __db_backend_mysql_finish(statement);
1516 int ret, left, first;
1521 if (!__mysql_initialized) {
1524 if (!backend_mysql) {
1533 memset(sql, 0, left);
1535 if ((ret = snprintf(sqlp, left,
"SELECT")) >= left) {
1543 while (object_field) {
1561 if ((ret = snprintf(sqlp, left,
" FROM %s",
db_object_table(
object))) >= left) {
1570 if ((ret = snprintf(sqlp, left,
" INNER JOIN %s ON %s.%s = %s.%s",
1587 if ((ret = snprintf(sqlp, left,
" WHERE")) >= left) {
1593 if (__db_backend_mysql_build_clause(
object, clause_list, &sqlp, &left)) {
1601 __db_backend_mysql_finish(statement);
1608 if (__db_backend_mysql_bind_clause(&bind, clause_list)) {
1609 __db_backend_mysql_finish(statement);
1617 if (__db_backend_mysql_execute(statement)) {
1618 __db_backend_mysql_finish(statement);
1626 __db_backend_mysql_finish(statement);
1641 int ret, left, first;
1650 if (!__mysql_initialized) {
1653 if (!backend_mysql) {
1659 if (!object_field_list) {
1670 while (object_field) {
1672 if (revision_field) {
1679 revision_field = object_field;
1683 if (revision_field) {
1691 revision_clause = clause;
1696 if (!revision_clause) {
1704 revision_number = int32;
1711 revision_number = uint32;
1718 revision_number = int64;
1725 revision_number = uint64;
1735 memset(sql, 0, left);
1737 if ((ret = snprintf(sqlp, left,
"UPDATE %s SET",
db_object_table(
object))) >= left) {
1748 while (object_field) {
1769 if (revision_field) {
1790 if ((ret = snprintf(sqlp, left,
" WHERE")) >= left) {
1796 if (__db_backend_mysql_build_clause(
object, clause_list, &sqlp, &left)) {
1807 __db_backend_mysql_finish(statement);
1817 if (__db_backend_mysql_bind_value_set(&bind, value_set)) {
1818 __db_backend_mysql_finish(statement);
1826 if (revision_field) {
1828 || __db_backend_mysql_bind_value(bind, &revision))
1831 __db_backend_mysql_finish(statement);
1844 if (__db_backend_mysql_bind_clause(&bind, clause_list)) {
1845 __db_backend_mysql_finish(statement);
1853 if (__db_backend_mysql_execute(statement)) {
1854 __db_backend_mysql_finish(statement);
1862 if (revision_field) {
1863 if (mysql_stmt_affected_rows(statement->
statement) < 1) {
1864 __db_backend_mysql_finish(statement);
1869 __db_backend_mysql_finish(statement);
1884 if (!__mysql_initialized) {
1887 if (!backend_mysql) {
1898 while (object_field) {
1900 if (revision_field) {
1907 revision_field = object_field;
1911 if (revision_field) {
1930 memset(sql, 0, left);
1932 if ((ret = snprintf(sqlp, left,
"DELETE FROM %s",
db_object_table(
object))) >= left) {
1940 if ((ret = snprintf(sqlp, left,
" WHERE")) >= left) {
1946 if (__db_backend_mysql_build_clause(
object, clause_list, &sqlp, &left)) {
1954 __db_backend_mysql_finish(statement);
1961 if (__db_backend_mysql_bind_clause(&bind, clause_list)) {
1962 __db_backend_mysql_finish(statement);
1967 if (__db_backend_mysql_execute(statement)) {
1968 __db_backend_mysql_finish(statement);
1976 if (revision_field) {
1977 if (mysql_stmt_affected_rows(statement->
statement) < 1) {
1978 __db_backend_mysql_finish(statement);
1983 __db_backend_mysql_finish(statement);
1998 if (!__mysql_initialized) {
2001 if (!backend_mysql) {
2013 memset(sql, 0, left);
2015 if ((ret = snprintf(sqlp, left,
"SELECT COUNT(*)")) >= left) {
2021 if ((ret = snprintf(sqlp, left,
" FROM %s",
db_object_table(
object))) >= left) {
2030 if ((ret = snprintf(sqlp, left,
" INNER JOIN %s ON %s.%s = %s.%s",
2047 if ((ret = snprintf(sqlp, left,
" WHERE")) >= left) {
2053 if (__db_backend_mysql_build_clause(
object, clause_list, &sqlp, &left)) {
2069 if (__db_backend_mysql_prepare(backend_mysql, &statement, sql, strlen(sql), object_field_list)
2073 __db_backend_mysql_finish(statement);
2081 if (__db_backend_mysql_bind_clause(&bind, clause_list)) {
2082 __db_backend_mysql_finish(statement);
2087 if (__db_backend_mysql_execute(statement)) {
2088 __db_backend_mysql_finish(statement);
2092 if (__db_backend_mysql_fetch(statement)) {
2093 __db_backend_mysql_finish(statement);
2098 if (!bind || !bind->
bind || !bind->
bind->buffer
2099 || bind->
bind->buffer_type != MYSQL_TYPE_LONG
2100 || !bind->
bind->is_unsigned
2103 __db_backend_mysql_finish(statement);
2108 __db_backend_mysql_finish(statement);
2113 static void db_backend_mysql_free(
void* data) {
2116 if (backend_mysql) {
2117 if (backend_mysql->
db) {
2118 (void)db_backend_mysql_disconnect(backend_mysql);
2120 free(backend_mysql);
2124 static int db_backend_mysql_transaction_begin(
void* data) {
2126 static const char* sql =
"BEGIN TRANSACTION";
2129 if (!__mysql_initialized) {
2132 if (!backend_mysql) {
2139 if (__db_backend_mysql_prepare(backend_mysql, &statement, sql, strlen(sql), NULL)) {
2143 if (__db_backend_mysql_execute(statement)) {
2144 __db_backend_mysql_finish(statement);
2147 __db_backend_mysql_finish(statement);
2153 static int db_backend_mysql_transaction_commit(
void* data) {
2155 static const char* sql =
"COMMIT TRANSACTION";
2158 if (!__mysql_initialized) {
2161 if (!backend_mysql) {
2168 if (__db_backend_mysql_prepare(backend_mysql, &statement, sql, strlen(sql), NULL)) {
2172 if (__db_backend_mysql_execute(statement)) {
2173 __db_backend_mysql_finish(statement);
2176 __db_backend_mysql_finish(statement);
2182 static int db_backend_mysql_transaction_rollback(
void* data) {
2184 static const char* sql =
"ROLLBACK TRANSACTION";
2187 if (!__mysql_initialized) {
2190 if (!backend_mysql) {
2197 if (__db_backend_mysql_prepare(backend_mysql, &statement, sql, strlen(sql), NULL)) {
2201 if (__db_backend_mysql_execute(statement)) {
2202 __db_backend_mysql_finish(statement);
2205 __db_backend_mysql_finish(statement);
2233 free(backend_mysql);
2237 return backend_handle;