35 #include <mysql/mysql.h>
44 static int db_backend_mysql_transaction_rollback(
void*);
49 static int __mysql_initialized = 0;
121 if (bind->
bind && bind->
bind->buffer) {
122 free(bind->
bind->buffer);
143 unsigned long i, params;
146 MYSQL_BIND* mysql_bind;
147 MYSQL_RES* result_metadata = NULL;
150 if (!backend_mysql) {
153 if (!backend_mysql->
db) {
169 ods_log_debug(
"%s", sql);
171 || !((*statement)->statement = mysql_stmt_init(backend_mysql->
db))
172 || mysql_stmt_prepare((*statement)->statement, sql, size))
174 if ((*statement)->statement) {
175 ods_log_info(
"DB prepare SQL %s", sql);
176 ods_log_info(
"DB prepare Err %d: %s", mysql_stmt_errno((*statement)->statement), mysql_stmt_error((*statement)->statement));
178 __db_backend_mysql_finish(*statement);
183 (*statement)->backend_mysql = backend_mysql;
189 if ((params = mysql_stmt_param_count((*statement)->statement)) > 0) {
190 if (!((*statement)->mysql_bind_input = calloc(params,
sizeof(MYSQL_BIND)))) {
191 __db_backend_mysql_finish(*statement);
196 for (i = 0; i < params; i++) {
198 __db_backend_mysql_finish(*statement);
203 bind->
bind = &((*statement)->mysql_bind_input[i]);
204 if (!(*statement)->bind_input) {
205 (*statement)->bind_input = bind;
207 if ((*statement)->bind_input_end) {
208 (*statement)->bind_input_end->
next = bind;
210 (*statement)->bind_input_end = bind;
217 if (object_field_list
219 && (result_metadata = mysql_stmt_result_metadata((*statement)->statement)))
222 || !((*statement)->mysql_bind_output = calloc(params,
sizeof(MYSQL_BIND))))
224 mysql_free_result(result_metadata);
225 __db_backend_mysql_finish(*statement);
230 (*statement)->fields = params;
231 field = mysql_fetch_field(result_metadata);
233 for (i = 0; i < params; i++) {
238 mysql_free_result(result_metadata);
239 __db_backend_mysql_finish(*statement);
244 bind->
bind = (mysql_bind = &((*statement)->mysql_bind_output[i]));
245 mysql_bind->is_null = (my_bool*)0;
246 mysql_bind->error = &bind->
error;
247 mysql_bind->length = &bind->
length;
251 switch (field->type) {
252 case MYSQL_TYPE_TINY:
253 case MYSQL_TYPE_SHORT:
254 case MYSQL_TYPE_LONG:
255 case MYSQL_TYPE_INT24:
256 mysql_bind->buffer_type = MYSQL_TYPE_LONG;
258 mysql_free_result(result_metadata);
259 __db_backend_mysql_finish(*statement);
264 bind->
length = mysql_bind->buffer_length;
265 mysql_bind->is_unsigned = 1;
268 case MYSQL_TYPE_LONGLONG:
269 mysql_bind->buffer_type = MYSQL_TYPE_LONGLONG;
271 mysql_free_result(result_metadata);
272 __db_backend_mysql_finish(*statement);
277 bind->
length = mysql_bind->buffer_length;
278 mysql_bind->is_unsigned = 1;
281 case MYSQL_TYPE_STRING:
282 case MYSQL_TYPE_VAR_STRING:
283 mysql_bind->buffer_type = MYSQL_TYPE_STRING;
288 bind->
length = field->length + 1;
292 if (!(mysql_bind->buffer = calloc(1, bind->
length))) {
293 mysql_free_result(result_metadata);
294 __db_backend_mysql_finish(*statement);
298 mysql_bind->buffer_length = bind->
length;
299 mysql_bind->is_unsigned = 0;
303 mysql_free_result(result_metadata);
304 __db_backend_mysql_finish(*statement);
318 mysql_bind->buffer_type = MYSQL_TYPE_LONG;
320 mysql_free_result(result_metadata);
321 __db_backend_mysql_finish(*statement);
326 bind->
length = mysql_bind->buffer_length;
327 mysql_bind->is_unsigned = 0;
331 mysql_bind->buffer_type = MYSQL_TYPE_LONG;
333 mysql_free_result(result_metadata);
334 __db_backend_mysql_finish(*statement);
339 bind->
length = mysql_bind->buffer_length;
340 mysql_bind->is_unsigned = 1;
344 mysql_bind->buffer_type = MYSQL_TYPE_LONGLONG;
346 mysql_free_result(result_metadata);
347 __db_backend_mysql_finish(*statement);
352 bind->
length = mysql_bind->buffer_length;
353 mysql_bind->is_unsigned = 0;
357 mysql_bind->buffer_type = MYSQL_TYPE_LONGLONG;
359 mysql_free_result(result_metadata);
360 __db_backend_mysql_finish(*statement);
365 bind->
length = mysql_bind->buffer_length;
366 mysql_bind->is_unsigned = 1;
370 mysql_bind->buffer_type = MYSQL_TYPE_STRING;
375 bind->
length = field->length + 1;
379 if (!(mysql_bind->buffer = calloc(1, bind->
length))) {
380 mysql_free_result(result_metadata);
381 __db_backend_mysql_finish(*statement);
385 mysql_bind->buffer_length = bind->
length;
386 mysql_bind->is_unsigned = 0;
391 switch (field->type) {
392 case MYSQL_TYPE_TINY:
393 case MYSQL_TYPE_SHORT:
394 case MYSQL_TYPE_LONG:
395 case MYSQL_TYPE_INT24:
396 mysql_bind->buffer_type = MYSQL_TYPE_LONG;
397 if (field->flags & UNSIGNED_FLAG) {
399 mysql_free_result(result_metadata);
400 __db_backend_mysql_finish(*statement);
405 mysql_bind->is_unsigned = 1;
409 mysql_free_result(result_metadata);
410 __db_backend_mysql_finish(*statement);
415 mysql_bind->is_unsigned = 0;
417 bind->
length = mysql_bind->buffer_length;
420 case MYSQL_TYPE_LONGLONG:
421 mysql_bind->buffer_type = MYSQL_TYPE_LONGLONG;
422 if (field->flags & UNSIGNED_FLAG) {
424 mysql_free_result(result_metadata);
425 __db_backend_mysql_finish(*statement);
430 mysql_bind->is_unsigned = 1;
434 mysql_free_result(result_metadata);
435 __db_backend_mysql_finish(*statement);
440 mysql_bind->is_unsigned = 0;
442 bind->
length = mysql_bind->buffer_length;
445 case MYSQL_TYPE_STRING:
446 case MYSQL_TYPE_VAR_STRING:
447 mysql_bind->buffer_type = MYSQL_TYPE_STRING;
452 bind->
length = field->length + 1;
456 if (!(mysql_bind->buffer = calloc(1, bind->
length))) {
457 mysql_free_result(result_metadata);
458 __db_backend_mysql_finish(*statement);
462 mysql_bind->buffer_length = bind->
length;
463 mysql_bind->is_unsigned = 0;
467 mysql_free_result(result_metadata);
468 __db_backend_mysql_finish(*statement);
478 if (!(*statement)->bind_output) {
479 (*statement)->bind_output = bind;
481 if ((*statement)->bind_output_end) {
482 (*statement)->bind_output_end->
next = bind;
484 (*statement)->bind_output_end = bind;
486 field = mysql_fetch_field(result_metadata);
492 if (object_field || field) {
493 mysql_free_result(result_metadata);
494 __db_backend_mysql_finish(*statement);
499 if (result_metadata) {
500 mysql_free_result(result_metadata);
524 if (!statement->
bound) {
528 ods_log_info(
"DB bind result Err %d: %s", mysql_stmt_errno(statement->
statement), mysql_stmt_error(statement->
statement));
531 statement->
bound = 1;
537 ret = mysql_stmt_fetch(statement->
statement);
539 ods_log_info(
"DB fetch Err %d: %s", mysql_stmt_errno(statement->
statement), mysql_stmt_error(statement->
statement));
542 else if (ret == MYSQL_DATA_TRUNCATED) {
555 for (i = 0, bind = statement->
bind_output; bind; i++, bind = bind->
next) {
560 ods_log_info(
"DB fetch Err data truncated");
567 ods_log_info(
"DB fetch Err data truncated");
575 ods_log_info(
"DB fetch Err data truncated");
581 else if (ret == MYSQL_NO_DATA) {
589 ods_log_info(
"DB fetch UNKNOWN %d Err %d: %s", ret, mysql_stmt_errno(statement->
statement), mysql_stmt_error(statement->
statement));
615 ods_log_info(
"DB bind param Err %d: %s", mysql_stmt_errno(statement->
statement), mysql_stmt_error(statement->
statement));
622 if (mysql_stmt_execute(statement->
statement)) {
623 ods_log_info(
"DB execute Err %d: %s", mysql_stmt_errno(statement->
statement), mysql_stmt_error(statement->
statement));
630 static int db_backend_mysql_initialize(
void* data) {
633 if (!backend_mysql) {
637 if (!__mysql_initialized) {
638 if (mysql_library_init(0, NULL, NULL)) {
641 __mysql_initialized = 1;
646 static int db_backend_mysql_shutdown(
void* data) {
649 if (!backend_mysql) {
653 if (__mysql_initialized) {
655 __mysql_initialized = 0;
669 unsigned int port = 0;
671 if (!__mysql_initialized) {
674 if (!backend_mysql) {
677 if (backend_mysql->
db) {
680 if (!configuration_list) {
689 if (port_configuration) {
700 backend_mysql->
timeout = (
unsigned int)timeout;
704 if (!(backend_mysql->
db = mysql_init(NULL))
705 || mysql_options(backend_mysql->
db, MYSQL_OPT_CONNECT_TIMEOUT, &backend_mysql->
timeout)
706 || !mysql_real_connect(backend_mysql->
db,
714 || mysql_autocommit(backend_mysql->
db, 1))
716 if (backend_mysql->
db) {
717 ods_log_error(
"db_backend_mysql: connect failed %d: %s", mysql_errno(backend_mysql->
db), mysql_error(backend_mysql->
db));
718 mysql_close(backend_mysql->
db);
719 backend_mysql->
db = NULL;
727 static int db_backend_mysql_disconnect(
void* data) {
730 if (!__mysql_initialized) {
733 if (!backend_mysql) {
736 if (!backend_mysql->
db) {
741 db_backend_mysql_transaction_rollback(backend_mysql);
744 mysql_close(backend_mysql->
db);
745 backend_mysql->
db = NULL;
759 static int __db_backend_mysql_build_clause(
const db_object_t*
object,
const db_clause_list_t* clause_list,
char** sqlp,
int* left) {
788 if ((ret = snprintf(*sqlp, *left,
" AND")) >= *left) {
794 if ((ret = snprintf(*sqlp, *left,
" OR")) >= *left) {
808 if ((ret = snprintf(*sqlp, *left,
" %s.%s = ?",
817 if ((ret = snprintf(*sqlp, *left,
" %s.%s != ?",
826 if ((ret = snprintf(*sqlp, *left,
" %s.%s < ?",
835 if ((ret = snprintf(*sqlp, *left,
" %s.%s <= ?",
844 if ((ret = snprintf(*sqlp, *left,
" %s.%s >= ?",
853 if ((ret = snprintf(*sqlp, *left,
" %s.%s > ?",
862 if ((ret = snprintf(*sqlp, *left,
" %s.%s IS NULL",
871 if ((ret = snprintf(*sqlp, *left,
" %s.%s IS NOT NULL",
880 if ((ret = snprintf(*sqlp, *left,
" (")) >= *left) {
885 if (__db_backend_mysql_build_clause(
object,
db_clause_list(clause), sqlp, left)) {
888 if ((ret = snprintf(*sqlp, *left,
" )")) >= *left) {
933 (*bind)->bind->length = &((*bind)->bind->buffer_length);
934 (*bind)->bind->is_null = (my_bool*)0;
949 (*bind)->bind->buffer_type = MYSQL_TYPE_LONG;
950 (*bind)->bind->buffer = (
void*)int32;
952 (*bind)->bind->is_unsigned = 0;
959 (*bind)->bind->buffer_type = MYSQL_TYPE_LONG;
960 (*bind)->bind->buffer = (
void*)uint32;
962 (*bind)->bind->is_unsigned = 1;
969 (*bind)->bind->buffer_type = MYSQL_TYPE_LONGLONG;
970 (*bind)->bind->buffer = (
void*)int64;
972 (*bind)->bind->is_unsigned = 0;
979 (*bind)->bind->buffer_type = MYSQL_TYPE_LONGLONG;
980 (*bind)->bind->buffer = (
void*)uint64;
982 (*bind)->bind->is_unsigned = 1;
989 (*bind)->bind->buffer_type = MYSQL_TYPE_STRING;
990 (*bind)->bind->buffer = (
void*)text;
991 (*bind)->bind->buffer_length = strlen(text);
992 (*bind)->bind->is_unsigned = 0;
999 (*bind)->bind->buffer_type = MYSQL_TYPE_LONG;
1000 (*bind)->bind->buffer = (
void*)&((*bind)->value_enum);
1001 (*bind)->bind->buffer_length =
sizeof(int);
1002 (*bind)->bind->is_unsigned = 0;
1019 *bind = (*bind)->
next;
1020 if (__db_backend_mysql_bind_clause(bind,
db_clause_list(clause))) {
1030 *bind = (*bind)->
next;
1053 bind->
bind->length = &(bind->
bind->buffer_length);
1054 bind->
bind->is_null = (my_bool*)0;
1062 bind->
bind->buffer_type = MYSQL_TYPE_LONG;
1063 bind->
bind->buffer = (
void*)int32;
1065 bind->
bind->is_unsigned = 0;
1072 bind->
bind->buffer_type = MYSQL_TYPE_LONG;
1073 bind->
bind->buffer = (
void*)uint32;
1075 bind->
bind->is_unsigned = 1;
1082 bind->
bind->buffer_type = MYSQL_TYPE_LONGLONG;
1083 bind->
bind->buffer = (
void*)int64;
1085 bind->
bind->is_unsigned = 0;
1092 bind->
bind->buffer_type = MYSQL_TYPE_LONGLONG;
1093 bind->
bind->buffer = (
void*)uint64;
1095 bind->
bind->is_unsigned = 1;
1102 bind->
bind->buffer_type = MYSQL_TYPE_STRING;
1103 bind->
bind->buffer = (
void*)text;
1104 bind->
bind->buffer_length = strlen(text);
1105 bind->
bind->is_unsigned = 0;
1112 bind->
bind->buffer_type = MYSQL_TYPE_LONG;
1114 bind->
bind->buffer_length =
sizeof(int);
1115 bind->
bind->is_unsigned = 0;
1143 if (__db_backend_mysql_bind_value(*bind,
db_value_set_at(value_set, i))) {
1150 static db_result_t* db_backend_mysql_next(
void* data,
int finish) {
1169 __db_backend_mysql_finish(statement);
1173 if (__db_backend_mysql_fetch(statement)) {
1188 while (object_field) {
1189 if (!bind || !bind->
bind || !bind->
bind->buffer) {
1198 switch (bind->
bind->buffer_type) {
1199 case MYSQL_TYPE_LONG:
1200 if ((bind->
bind->is_unsigned
1202 || (!bind->
bind->is_unsigned
1210 case MYSQL_TYPE_LONGLONG:
1211 if ((bind->
bind->is_unsigned
1213 || (!bind->
bind->is_unsigned
1221 case MYSQL_TYPE_STRING:
1251 if (bind->
bind->buffer_type != MYSQL_TYPE_LONG
1252 || (bind->
bind->is_unsigned
1254 || (!bind->
bind->is_unsigned
1264 if (bind->
bind->buffer_type != MYSQL_TYPE_LONGLONG
1265 || (bind->
bind->is_unsigned
1267 || (!bind->
bind->is_unsigned
1276 if (bind->
bind->buffer_type != MYSQL_TYPE_STRING
1305 int ret, left, first;
1310 if (!__mysql_initialized) {
1313 if (!backend_mysql) {
1319 if (!object_field_list) {
1330 while (object_field) {
1332 if (revision_field) {
1339 revision_field = object_field;
1346 memset(sql, 0, left);
1352 if ((ret = snprintf(sqlp, left,
"INSERT INTO %s () VALUES ()",
db_object_table(
object))) >= left) {
1359 if ((ret = snprintf(sqlp, left,
"INSERT INTO %s (",
db_object_table(
object))) >= left) {
1370 while (object_field) {
1391 if (revision_field) {
1407 if ((ret = snprintf(sqlp, left,
" ) VALUES (")) >= left) {
1418 while (object_field) {
1420 if ((ret = snprintf(sqlp, left,
" ?")) >= left) {
1426 if ((ret = snprintf(sqlp, left,
", ?")) >= left) {
1439 if (revision_field) {
1441 if ((ret = snprintf(sqlp, left,
" ?")) >= left) {
1447 if ((ret = snprintf(sqlp, left,
", ?")) >= left) {
1455 if ((ret = snprintf(sqlp, left,
" )")) >= left) {
1469 __db_backend_mysql_finish(statement);
1476 if (__db_backend_mysql_bind_value_set(&bind, value_set)) {
1477 __db_backend_mysql_finish(statement);
1484 if (revision_field) {
1486 || __db_backend_mysql_bind_value(bind, &revision))
1489 __db_backend_mysql_finish(statement);
1498 if (__db_backend_mysql_execute(statement)
1499 || mysql_stmt_affected_rows(statement->
statement) != 1)
1501 __db_backend_mysql_finish(statement);
1504 __db_backend_mysql_finish(statement);
1515 int ret, left, first;
1520 if (!__mysql_initialized) {
1523 if (!backend_mysql) {
1532 memset(sql, 0, left);
1534 if ((ret = snprintf(sqlp, left,
"SELECT")) >= left) {
1542 while (object_field) {
1560 if ((ret = snprintf(sqlp, left,
" FROM %s",
db_object_table(
object))) >= left) {
1569 if ((ret = snprintf(sqlp, left,
" INNER JOIN %s ON %s.%s = %s.%s",
1586 if ((ret = snprintf(sqlp, left,
" WHERE")) >= left) {
1592 if (__db_backend_mysql_build_clause(
object, clause_list, &sqlp, &left)) {
1600 __db_backend_mysql_finish(statement);
1607 if (__db_backend_mysql_bind_clause(&bind, clause_list)) {
1608 __db_backend_mysql_finish(statement);
1616 if (__db_backend_mysql_execute(statement)) {
1617 __db_backend_mysql_finish(statement);
1625 __db_backend_mysql_finish(statement);
1640 int ret, left, first;
1649 if (!__mysql_initialized) {
1652 if (!backend_mysql) {
1658 if (!object_field_list) {
1669 while (object_field) {
1671 if (revision_field) {
1678 revision_field = object_field;
1682 if (revision_field) {
1690 revision_clause = clause;
1695 if (!revision_clause) {
1703 revision_number = int32;
1710 revision_number = uint32;
1717 revision_number = int64;
1724 revision_number = uint64;
1734 memset(sql, 0, left);
1736 if ((ret = snprintf(sqlp, left,
"UPDATE %s SET",
db_object_table(
object))) >= left) {
1747 while (object_field) {
1768 if (revision_field) {
1789 if ((ret = snprintf(sqlp, left,
" WHERE")) >= left) {
1795 if (__db_backend_mysql_build_clause(
object, clause_list, &sqlp, &left)) {
1806 __db_backend_mysql_finish(statement);
1816 if (__db_backend_mysql_bind_value_set(&bind, value_set)) {
1817 __db_backend_mysql_finish(statement);
1825 if (revision_field) {
1827 || __db_backend_mysql_bind_value(bind, &revision))
1830 __db_backend_mysql_finish(statement);
1843 if (__db_backend_mysql_bind_clause(&bind, clause_list)) {
1844 __db_backend_mysql_finish(statement);
1852 if (__db_backend_mysql_execute(statement)) {
1853 __db_backend_mysql_finish(statement);
1861 if (revision_field) {
1862 if (mysql_stmt_affected_rows(statement->
statement) < 1) {
1863 __db_backend_mysql_finish(statement);
1868 __db_backend_mysql_finish(statement);
1883 if (!__mysql_initialized) {
1886 if (!backend_mysql) {
1897 while (object_field) {
1899 if (revision_field) {
1906 revision_field = object_field;
1910 if (revision_field) {
1929 memset(sql, 0, left);
1931 if ((ret = snprintf(sqlp, left,
"DELETE FROM %s",
db_object_table(
object))) >= left) {
1939 if ((ret = snprintf(sqlp, left,
" WHERE")) >= left) {
1945 if (__db_backend_mysql_build_clause(
object, clause_list, &sqlp, &left)) {
1953 __db_backend_mysql_finish(statement);
1960 if (__db_backend_mysql_bind_clause(&bind, clause_list)) {
1961 __db_backend_mysql_finish(statement);
1966 if (__db_backend_mysql_execute(statement)) {
1967 __db_backend_mysql_finish(statement);
1975 if (revision_field) {
1976 if (mysql_stmt_affected_rows(statement->
statement) < 1) {
1977 __db_backend_mysql_finish(statement);
1982 __db_backend_mysql_finish(statement);
1997 if (!__mysql_initialized) {
2000 if (!backend_mysql) {
2012 memset(sql, 0, left);
2014 if ((ret = snprintf(sqlp, left,
"SELECT COUNT(*)")) >= left) {
2020 if ((ret = snprintf(sqlp, left,
" FROM %s",
db_object_table(
object))) >= left) {
2029 if ((ret = snprintf(sqlp, left,
" INNER JOIN %s ON %s.%s = %s.%s",
2046 if ((ret = snprintf(sqlp, left,
" WHERE")) >= left) {
2052 if (__db_backend_mysql_build_clause(
object, clause_list, &sqlp, &left)) {
2068 if (__db_backend_mysql_prepare(backend_mysql, &statement, sql, strlen(sql), object_field_list)
2072 __db_backend_mysql_finish(statement);
2080 if (__db_backend_mysql_bind_clause(&bind, clause_list)) {
2081 __db_backend_mysql_finish(statement);
2086 if (__db_backend_mysql_execute(statement)) {
2087 __db_backend_mysql_finish(statement);
2091 if (__db_backend_mysql_fetch(statement)) {
2092 __db_backend_mysql_finish(statement);
2097 if (!bind || !bind->
bind || !bind->
bind->buffer
2098 || bind->
bind->buffer_type != MYSQL_TYPE_LONG
2099 || !bind->
bind->is_unsigned
2102 __db_backend_mysql_finish(statement);
2107 __db_backend_mysql_finish(statement);
2112 static void db_backend_mysql_free(
void* data) {
2115 if (backend_mysql) {
2116 if (backend_mysql->
db) {
2117 (void)db_backend_mysql_disconnect(backend_mysql);
2119 free(backend_mysql);
2123 static int db_backend_mysql_transaction_begin(
void* data) {
2125 static const char* sql =
"BEGIN TRANSACTION";
2128 if (!__mysql_initialized) {
2131 if (!backend_mysql) {
2138 if (__db_backend_mysql_prepare(backend_mysql, &statement, sql, strlen(sql), NULL)) {
2142 if (__db_backend_mysql_execute(statement)) {
2143 __db_backend_mysql_finish(statement);
2146 __db_backend_mysql_finish(statement);
2152 static int db_backend_mysql_transaction_commit(
void* data) {
2154 static const char* sql =
"COMMIT TRANSACTION";
2157 if (!__mysql_initialized) {
2160 if (!backend_mysql) {
2167 if (__db_backend_mysql_prepare(backend_mysql, &statement, sql, strlen(sql), NULL)) {
2171 if (__db_backend_mysql_execute(statement)) {
2172 __db_backend_mysql_finish(statement);
2175 __db_backend_mysql_finish(statement);
2181 static int db_backend_mysql_transaction_rollback(
void* data) {
2183 static const char* sql =
"ROLLBACK TRANSACTION";
2186 if (!__mysql_initialized) {
2189 if (!backend_mysql) {
2196 if (__db_backend_mysql_prepare(backend_mysql, &statement, sql, strlen(sql), NULL)) {
2200 if (__db_backend_mysql_execute(statement)) {
2201 __db_backend_mysql_finish(statement);
2204 __db_backend_mysql_finish(statement);
2232 free(backend_mysql);
2236 return backend_handle;