db_backend_mysql.c
Go to the documentation of this file.
/*
* Copyright (c) 2014 Jerry Lundström <lundstrom.jerry@gmail.com>
* Copyright (c) 2014 .SE (The Internet Infrastructure Foundation).
* Copyright (c) 2014 OpenDNSSEC AB (svb)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "db_backend_mysql.h"
#include "db_error.h"
#include "log.h"
#include <mysql/mysql.h>
/* Support building against MySQL. */
#ifndef LIBMARIADB
typedef _Bool my_bool;
#endif
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
#include <errno.h>
static int db_backend_mysql_transaction_rollback(void*);
static int __mysql_initialized = 0;
typedef struct db_backend_mysql {
MYSQL* db;
int transaction;
unsigned int timeout;
const char* db_host;
const char* db_user;
const char* db_pass;
const char* db_name;
int db_port;
} db_backend_mysql_t;
typedef struct db_backend_mysql_bind db_backend_mysql_bind_t;
struct db_backend_mysql_bind {
db_backend_mysql_bind_t* next;
MYSQL_BIND* bind;
unsigned long length;
my_bool error;
int value_enum;
};
typedef struct db_backend_mysql_statement {
db_backend_mysql_t* backend_mysql;
MYSQL_STMT* statement;
MYSQL_BIND* mysql_bind_input;
db_backend_mysql_bind_t* bind_input;
db_backend_mysql_bind_t* bind_input_end;
MYSQL_BIND* mysql_bind_output;
db_backend_mysql_bind_t* bind_output;
db_backend_mysql_bind_t* bind_output_end;
db_object_field_list_t* object_field_list;
int fields;
int bound;
} db_backend_mysql_statement_t;
static inline void __db_backend_mysql_finish(db_backend_mysql_statement_t* statement) {
db_backend_mysql_bind_t* bind;
if (!statement) {
return;
}
if (statement->statement) {
mysql_stmt_close(statement->statement);
}
if (statement->mysql_bind_input) {
free(statement->mysql_bind_input);
}
while (statement->bind_input) {
bind = statement->bind_input;
statement->bind_input = bind->next;
free(bind);
}
while (statement->bind_output) {
bind = statement->bind_output;
statement->bind_output = bind->next;
if (bind->bind && bind->bind->buffer) {
free(bind->bind->buffer);
}
free(bind);
}
if (statement->mysql_bind_output) {
free(statement->mysql_bind_output);
}
if (statement->object_field_list) {
db_object_field_list_free(statement->object_field_list);
}
free(statement);
}
static inline void checkconnection(db_backend_mysql_t* backend_mysql)
{
MYSQL_RES *result;
if(mysql_query(backend_mysql->db, "SELECT 1")) {
ods_log_warning("db_backend_mysql: connection lost, trying to reconnect");
if(!mysql_real_connect(backend_mysql->db, backend_mysql->db_host, backend_mysql->db_user, backend_mysql->db_pass,
backend_mysql->db_name, backend_mysql->db_port, NULL, 0) ||
mysql_autocommit(backend_mysql->db, 1)) {
if (backend_mysql->db) {
ods_log_error("db_backend_mysql: reconnect failed %d: %s", mysql_errno(backend_mysql->db), mysql_error(backend_mysql->db));
mysql_close(backend_mysql->db);
backend_mysql->db = NULL;
}
}
} else {
result = mysql_store_result(backend_mysql->db);
mysql_free_result(result);
}
}
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) {
unsigned long i, params;
db_backend_mysql_bind_t* bind;
const db_object_field_t* object_field;
MYSQL_BIND* mysql_bind;
MYSQL_RES* result_metadata = NULL;
MYSQL_FIELD* field;
if (!backend_mysql) {
return DB_ERROR_UNKNOWN;
}
if (!backend_mysql->db) {
return DB_ERROR_UNKNOWN;
}
if (!statement) {
return DB_ERROR_UNKNOWN;
}
if (*statement) {
return DB_ERROR_UNKNOWN;
}
if (!sql) {
return DB_ERROR_UNKNOWN;
}
checkconnection(backend_mysql);
/*
* Prepare the statement.
*/
ods_log_debug("%s", sql);
if (!(*statement = calloc(1, sizeof(db_backend_mysql_statement_t)))
|| !((*statement)->statement = mysql_stmt_init(backend_mysql->db))
|| mysql_stmt_prepare((*statement)->statement, sql, size))
{
if ((*statement)->statement) {
ods_log_info("DB prepare SQL %s", sql);
ods_log_info("DB prepare Err %d: %s", mysql_stmt_errno((*statement)->statement), mysql_stmt_error((*statement)->statement));
}
__db_backend_mysql_finish(*statement);
*statement = NULL;
return DB_ERROR_UNKNOWN;
}
(*statement)->backend_mysql = backend_mysql;
/*
* Create the input binding based on the number of parameters in the SQL
* statement.
*/
if ((params = mysql_stmt_param_count((*statement)->statement)) > 0) {
if (!((*statement)->mysql_bind_input = calloc(params, sizeof(MYSQL_BIND)))) {
__db_backend_mysql_finish(*statement);
*statement = NULL;
return DB_ERROR_UNKNOWN;
}
for (i = 0; i < params; i++) {
if (!(bind = calloc(1, sizeof(db_backend_mysql_bind_t)))) {
__db_backend_mysql_finish(*statement);
*statement = NULL;
return DB_ERROR_UNKNOWN;
}
bind->bind = &((*statement)->mysql_bind_input[i]);
if (!(*statement)->bind_input) {
(*statement)->bind_input = bind;
}
if ((*statement)->bind_input_end) {
(*statement)->bind_input_end->next = bind;
}
(*statement)->bind_input_end = bind;
}
}
/*
* Create the output binding based on the object field list given.
*/
if (object_field_list
&& (params = db_object_field_list_size(object_field_list)) > 0
&& (result_metadata = mysql_stmt_result_metadata((*statement)->statement)))
{
if (!((*statement)->object_field_list = db_object_field_list_new_copy(object_field_list))
|| !((*statement)->mysql_bind_output = calloc(params, sizeof(MYSQL_BIND))))
{
mysql_free_result(result_metadata);
__db_backend_mysql_finish(*statement);
*statement = NULL;
return DB_ERROR_UNKNOWN;
}
(*statement)->fields = params;
field = mysql_fetch_field(result_metadata);
object_field = db_object_field_list_begin(object_field_list);
for (i = 0; i < params; i++) {
if (!field
|| !object_field
|| !(bind = calloc(1, sizeof(db_backend_mysql_bind_t))))
{
mysql_free_result(result_metadata);
__db_backend_mysql_finish(*statement);
*statement = NULL;
return DB_ERROR_UNKNOWN;
}
bind->bind = (mysql_bind = &((*statement)->mysql_bind_output[i]));
mysql_bind->is_null = (my_bool*)0;
mysql_bind->error = &bind->error;
mysql_bind->length = &bind->length;
switch (db_object_field_type(object_field)) {
case DB_TYPE_PRIMARY_KEY:
switch (field->type) {
case MYSQL_TYPE_TINY:
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_LONG:
case MYSQL_TYPE_INT24:
mysql_bind->buffer_type = MYSQL_TYPE_LONG;
if (!(mysql_bind->buffer = calloc(1, sizeof(db_type_uint32_t)))) {
mysql_free_result(result_metadata);
__db_backend_mysql_finish(*statement);
*statement = NULL;
return DB_ERROR_UNKNOWN;
}
mysql_bind->buffer_length = sizeof(db_type_uint32_t);
bind->length = mysql_bind->buffer_length;
mysql_bind->is_unsigned = 1;
break;
case MYSQL_TYPE_LONGLONG:
mysql_bind->buffer_type = MYSQL_TYPE_LONGLONG;
if (!(mysql_bind->buffer = calloc(1, sizeof(db_type_uint64_t)))) {
mysql_free_result(result_metadata);
__db_backend_mysql_finish(*statement);
*statement = NULL;
return DB_ERROR_UNKNOWN;
}
mysql_bind->buffer_length = sizeof(db_type_uint64_t);
bind->length = mysql_bind->buffer_length;
mysql_bind->is_unsigned = 1;
break;
case MYSQL_TYPE_STRING:
case MYSQL_TYPE_VAR_STRING:
mysql_bind->buffer_type = MYSQL_TYPE_STRING;
/*
* field->length does not include ending NULL character so
* we increase it by one.
*/
bind->length = field->length + 1;
if (bind->length < DB_BACKEND_MYSQL_STRING_MIN_SIZE) {
bind->length = DB_BACKEND_MYSQL_STRING_MIN_SIZE;
}
if (!(mysql_bind->buffer = calloc(1, bind->length))) {
mysql_free_result(result_metadata);
__db_backend_mysql_finish(*statement);
*statement = NULL;
return DB_ERROR_UNKNOWN;
}
mysql_bind->buffer_length = bind->length;
mysql_bind->is_unsigned = 0;
break;
default:
mysql_free_result(result_metadata);
__db_backend_mysql_finish(*statement);
*statement = NULL;
return DB_ERROR_UNKNOWN;
}
break;
case DB_TYPE_ENUM:
/*
* Enum needs to be handled elsewhere since we don't know the
* enum_set_t here.
*
* TODO: can something be done here?
*/
case DB_TYPE_INT32:
mysql_bind->buffer_type = MYSQL_TYPE_LONG;
if (!(mysql_bind->buffer = calloc(1, sizeof(db_type_int32_t)))) {
mysql_free_result(result_metadata);
__db_backend_mysql_finish(*statement);
*statement = NULL;
return DB_ERROR_UNKNOWN;
}
mysql_bind->buffer_length = sizeof(db_type_int32_t);
bind->length = mysql_bind->buffer_length;
mysql_bind->is_unsigned = 0;
break;
case DB_TYPE_UINT32:
mysql_bind->buffer_type = MYSQL_TYPE_LONG;
if (!(mysql_bind->buffer = calloc(1, sizeof(db_type_uint32_t)))) {
mysql_free_result(result_metadata);
__db_backend_mysql_finish(*statement);
*statement = NULL;
return DB_ERROR_UNKNOWN;
}
mysql_bind->buffer_length = sizeof(db_type_uint32_t);
bind->length = mysql_bind->buffer_length;
mysql_bind->is_unsigned = 1;
break;
case DB_TYPE_INT64:
mysql_bind->buffer_type = MYSQL_TYPE_LONGLONG;
if (!(mysql_bind->buffer = calloc(1, sizeof(db_type_int64_t)))) {
mysql_free_result(result_metadata);
__db_backend_mysql_finish(*statement);
*statement = NULL;
return DB_ERROR_UNKNOWN;
}
mysql_bind->buffer_length = sizeof(db_type_int64_t);
bind->length = mysql_bind->buffer_length;
mysql_bind->is_unsigned = 0;
break;
case DB_TYPE_UINT64:
mysql_bind->buffer_type = MYSQL_TYPE_LONGLONG;
if (!(mysql_bind->buffer = calloc(1, sizeof(db_type_uint64_t)))) {
mysql_free_result(result_metadata);
__db_backend_mysql_finish(*statement);
*statement = NULL;
return DB_ERROR_UNKNOWN;
}
mysql_bind->buffer_length = sizeof(db_type_uint64_t);
bind->length = mysql_bind->buffer_length;
mysql_bind->is_unsigned = 1;
break;
case DB_TYPE_TEXT:
mysql_bind->buffer_type = MYSQL_TYPE_STRING;
/*
* field->length does not include ending NULL character so
* we increase it by one.
*/
bind->length = field->length + 1;
if (bind->length < DB_BACKEND_MYSQL_STRING_MIN_SIZE) {
bind->length = DB_BACKEND_MYSQL_STRING_MIN_SIZE;
}
if (!(mysql_bind->buffer = calloc(1, bind->length))) {
mysql_free_result(result_metadata);
__db_backend_mysql_finish(*statement);
*statement = NULL;
return DB_ERROR_UNKNOWN;
}
mysql_bind->buffer_length = bind->length;
mysql_bind->is_unsigned = 0;
break;
case DB_TYPE_ANY:
case DB_TYPE_REVISION:
switch (field->type) {
case MYSQL_TYPE_TINY:
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_LONG:
case MYSQL_TYPE_INT24:
mysql_bind->buffer_type = MYSQL_TYPE_LONG;
if (field->flags & UNSIGNED_FLAG) {
if (!(mysql_bind->buffer = calloc(1, sizeof(db_type_uint32_t)))) {
mysql_free_result(result_metadata);
__db_backend_mysql_finish(*statement);
*statement = NULL;
return DB_ERROR_UNKNOWN;
}
mysql_bind->buffer_length = sizeof(db_type_uint32_t);
mysql_bind->is_unsigned = 1;
}
else {
if (!(mysql_bind->buffer = calloc(1, sizeof(db_type_int32_t)))) {
mysql_free_result(result_metadata);
__db_backend_mysql_finish(*statement);
*statement = NULL;
return DB_ERROR_UNKNOWN;
}
mysql_bind->buffer_length = sizeof(db_type_int32_t);
mysql_bind->is_unsigned = 0;
}
bind->length = mysql_bind->buffer_length;
break;
case MYSQL_TYPE_LONGLONG:
mysql_bind->buffer_type = MYSQL_TYPE_LONGLONG;
if (field->flags & UNSIGNED_FLAG) {
if (!(mysql_bind->buffer = calloc(1, sizeof(db_type_uint64_t)))) {
mysql_free_result(result_metadata);
__db_backend_mysql_finish(*statement);
*statement = NULL;
return DB_ERROR_UNKNOWN;
}
mysql_bind->buffer_length = sizeof(db_type_uint64_t);
mysql_bind->is_unsigned = 1;
}
else {
if (!(mysql_bind->buffer = calloc(1, sizeof(db_type_int64_t)))) {
mysql_free_result(result_metadata);
__db_backend_mysql_finish(*statement);
*statement = NULL;
return DB_ERROR_UNKNOWN;
}
mysql_bind->buffer_length = sizeof(db_type_int64_t);
mysql_bind->is_unsigned = 0;
}
bind->length = mysql_bind->buffer_length;
break;
case MYSQL_TYPE_STRING:
case MYSQL_TYPE_VAR_STRING:
mysql_bind->buffer_type = MYSQL_TYPE_STRING;
/*
* field->length does not include ending NULL character so
* we increase it by one.
*/
bind->length = field->length + 1;
if (bind->length < DB_BACKEND_MYSQL_STRING_MIN_SIZE) {
bind->length = DB_BACKEND_MYSQL_STRING_MIN_SIZE;
}
if (!(mysql_bind->buffer = calloc(1, bind->length))) {
mysql_free_result(result_metadata);
__db_backend_mysql_finish(*statement);
*statement = NULL;
return DB_ERROR_UNKNOWN;
}
mysql_bind->buffer_length = bind->length;
mysql_bind->is_unsigned = 0;
break;
default:
mysql_free_result(result_metadata);
__db_backend_mysql_finish(*statement);
*statement = NULL;
return DB_ERROR_UNKNOWN;
}
break;
default:
return DB_ERROR_UNKNOWN;
}
if (!(*statement)->bind_output) {
(*statement)->bind_output = bind;
}
if ((*statement)->bind_output_end) {
(*statement)->bind_output_end->next = bind;
}
(*statement)->bind_output_end = bind;
object_field = db_object_field_next(object_field);
field = mysql_fetch_field(result_metadata);
}
/*
* If we still have an object field or a MySQL field then the number of
* fields in both is mismatching and we should return an error.
*/
if (object_field || field) {
mysql_free_result(result_metadata);
__db_backend_mysql_finish(*statement);
*statement = NULL;
return DB_ERROR_UNKNOWN;
}
}
if (result_metadata) {
mysql_free_result(result_metadata);
}
return DB_OK;
}
static inline int __db_backend_mysql_fetch(db_backend_mysql_statement_t* statement) {
int ret;
if (!statement) {
return DB_ERROR_UNKNOWN;
}
if (!statement->statement) {
return DB_ERROR_UNKNOWN;
}
/*
* Handle output binding if not already done.
*/
if (!statement->bound) {
if (statement->mysql_bind_output
&& mysql_stmt_bind_result(statement->statement, statement->mysql_bind_output))
{
ods_log_info("DB bind result Err %d: %s", mysql_stmt_errno(statement->statement), mysql_stmt_error(statement->statement));
return DB_ERROR_UNKNOWN;
}
statement->bound = 1;
}
/*
* Fetch the next row.
*/
ret = mysql_stmt_fetch(statement->statement);
if (ret == 1) {
ods_log_info("DB fetch Err %d: %s", mysql_stmt_errno(statement->statement), mysql_stmt_error(statement->statement));
return DB_ERROR_UNKNOWN;
}
else if (ret == MYSQL_DATA_TRUNCATED) {
int i;
db_backend_mysql_bind_t* bind;
/*
* Scan through all of the output binds and check where the data was
* truncated and reallocate the buffer and try again. MySQL should have
* updated bind->length with the required buffer size.
*
* We can really only retry fetch on string columns, if another type had
* a too small buffer its more a programmable error in the prepare
* function.
*/
for (i = 0, bind = statement->bind_output; bind; i++, bind = bind->next) {
if (bind->error) {
if (statement->mysql_bind_output[i].buffer_type != MYSQL_TYPE_STRING
|| bind->length <= statement->mysql_bind_output[i].buffer_length)
{
ods_log_info("DB fetch Err data truncated");
return DB_ERROR_UNKNOWN;
}
free(statement->mysql_bind_output[i].buffer);
statement->mysql_bind_output[i].buffer = NULL;
if (!(statement->mysql_bind_output[i].buffer = calloc(1, bind->length))) {
ods_log_info("DB fetch Err data truncated");
return DB_ERROR_UNKNOWN;
}
statement->mysql_bind_output[i].buffer_length = bind->length;
bind->error = 0;
if (mysql_stmt_fetch_column(statement->statement, &(statement->mysql_bind_output[i]), i, 0)
|| bind->error)
{
ods_log_info("DB fetch Err data truncated");
return DB_ERROR_UNKNOWN;
}
}
}
}
else if (ret == MYSQL_NO_DATA) {
/*
* Not really an error but we need to indicate that there is no more
* data some how.
*/
return DB_ERROR_UNKNOWN;
}
else if (ret) {
ods_log_info("DB fetch UNKNOWN %d Err %d: %s", ret, mysql_stmt_errno(statement->statement), mysql_stmt_error(statement->statement));
return DB_ERROR_UNKNOWN;
}
return DB_OK;
}
static inline int __db_backend_mysql_execute(db_backend_mysql_statement_t* statement) {
if (!statement) {
return DB_ERROR_UNKNOWN;
}
if (!statement->statement) {
return DB_ERROR_UNKNOWN;
}
/*
* Bind the input parameters.
*/
if (statement->mysql_bind_input
&& mysql_stmt_bind_param(statement->statement, statement->mysql_bind_input))
{
ods_log_info("DB bind param Err %d: %s", mysql_stmt_errno(statement->statement), mysql_stmt_error(statement->statement));
return DB_ERROR_UNKNOWN;
}
/*
* Execute the statement.
*/
if (mysql_stmt_execute(statement->statement)) {
ods_log_info("DB execute Err %d: %s", mysql_stmt_errno(statement->statement), mysql_stmt_error(statement->statement));
return DB_ERROR_UNKNOWN;
}
return DB_OK;
}
static int db_backend_mysql_initialize(void* data) {
db_backend_mysql_t* backend_mysql = (db_backend_mysql_t*)data;
if (!backend_mysql) {
return DB_ERROR_UNKNOWN;
}
if (!__mysql_initialized) {
if (mysql_library_init(0, NULL, NULL)) {
return DB_ERROR_UNKNOWN;
}
__mysql_initialized = 1;
}
return DB_OK;
}
static int db_backend_mysql_shutdown(void* data) {
db_backend_mysql_t* backend_mysql = (db_backend_mysql_t*)data;
if (!backend_mysql) {
return DB_ERROR_UNKNOWN;
}
if (__mysql_initialized) {
mysql_library_end();
__mysql_initialized = 0;
}
return DB_OK;
}
static int db_backend_mysql_connect(void* data, const db_configuration_list_t* configuration_list) {
db_backend_mysql_t* backend_mysql = (db_backend_mysql_t*)data;
const db_configuration_t* host;
const db_configuration_t* user;
const db_configuration_t* pass;
const db_configuration_t* db;
const db_configuration_t* port_configuration;
const db_configuration_t* timeout_configuration;
int timeout;
unsigned int port = 0;
if (!__mysql_initialized) {
return DB_ERROR_UNKNOWN;
}
if (!backend_mysql) {
return DB_ERROR_UNKNOWN;
}
if (backend_mysql->db) {
return DB_ERROR_UNKNOWN;
}
if (!configuration_list) {
return DB_ERROR_UNKNOWN;
}
host = db_configuration_list_find(configuration_list, "host");
user = db_configuration_list_find(configuration_list, "user");
pass = db_configuration_list_find(configuration_list, "pass");
db = db_configuration_list_find(configuration_list, "db");
port_configuration = db_configuration_list_find(configuration_list, "port");
if (port_configuration) {
port = atoi(db_configuration_value(port_configuration));
}
backend_mysql->timeout = DB_BACKEND_MYSQL_DEFAULT_TIMEOUT;
if ((timeout_configuration = db_configuration_list_find(configuration_list, "timeout"))) {
timeout = atoi(db_configuration_value(timeout_configuration));
if (timeout < 1) {
backend_mysql->timeout = DB_BACKEND_MYSQL_DEFAULT_TIMEOUT;
}
else {
backend_mysql->timeout = (unsigned int)timeout;
}
}
backend_mysql->db_host = (host ? db_configuration_value(host) : NULL);
backend_mysql->db_user = (user ? db_configuration_value(user) : NULL);
backend_mysql->db_pass = (pass ? db_configuration_value(pass) : NULL);
backend_mysql->db_port = port;
backend_mysql->db_name = (db ? db_configuration_value(db) : NULL);
if (!(backend_mysql->db = mysql_init(NULL))
|| mysql_options(backend_mysql->db, MYSQL_OPT_CONNECT_TIMEOUT, &backend_mysql->timeout)
|| !mysql_real_connect(backend_mysql->db,
backend_mysql->db_host, backend_mysql->db_user, backend_mysql->db_pass,
backend_mysql->db_name, backend_mysql->db_port, NULL, 0)
|| mysql_autocommit(backend_mysql->db, 1))
{
if (backend_mysql->db) {
ods_log_error("db_backend_mysql: connect failed %d: %s", mysql_errno(backend_mysql->db), mysql_error(backend_mysql->db));
mysql_close(backend_mysql->db);
backend_mysql->db = NULL;
}
return DB_ERROR_UNKNOWN;
}
return DB_OK;
}
static int db_backend_mysql_disconnect(void* data) {
db_backend_mysql_t* backend_mysql = (db_backend_mysql_t*)data;
if (!__mysql_initialized) {
return DB_ERROR_UNKNOWN;
}
if (!backend_mysql) {
return DB_ERROR_UNKNOWN;
}
if (!backend_mysql->db) {
return DB_ERROR_UNKNOWN;
}
if (backend_mysql->transaction) {
db_backend_mysql_transaction_rollback(backend_mysql);
}
mysql_close(backend_mysql->db);
backend_mysql->db = NULL;
return DB_OK;
}
static int __db_backend_mysql_build_clause(const db_object_t* object, const db_clause_list_t* clause_list, char** sqlp, int* left) {
const db_clause_t* clause;
int first, ret;
if (!clause_list) {
return DB_ERROR_UNKNOWN;
}
if (!sqlp) {
return DB_ERROR_UNKNOWN;
}
if (!*sqlp) {
return DB_ERROR_UNKNOWN;
}
if (!left) {
return DB_ERROR_UNKNOWN;
}
if (*left < 1) {
return DB_ERROR_UNKNOWN;
}
clause = db_clause_list_begin(clause_list);
first = 1;
while (clause) {
if (first) {
first = 0;
}
else {
switch (db_clause_operator(clause)) {
case DB_CLAUSE_OPERATOR_AND:
if ((ret = snprintf(*sqlp, *left, " AND")) >= *left) {
return DB_ERROR_UNKNOWN;
}
break;
case DB_CLAUSE_OPERATOR_OR:
if ((ret = snprintf(*sqlp, *left, " OR")) >= *left) {
return DB_ERROR_UNKNOWN;
}
break;
default:
return DB_ERROR_UNKNOWN;
}
*sqlp += ret;
*left -= ret;
}
switch (db_clause_type(clause)) {
case DB_CLAUSE_EQUAL:
if ((ret = snprintf(*sqlp, *left, " %s.%s = ?",
db_object_table(object),
db_clause_field(clause))) >= *left)
{
return DB_ERROR_UNKNOWN;
}
break;
case DB_CLAUSE_NOT_EQUAL:
if ((ret = snprintf(*sqlp, *left, " %s.%s != ?",
db_object_table(object),
db_clause_field(clause))) >= *left)
{
return DB_ERROR_UNKNOWN;
}
break;
case DB_CLAUSE_LESS_THEN:
if ((ret = snprintf(*sqlp, *left, " %s.%s < ?",
db_object_table(object),
db_clause_field(clause))) >= *left)
{
return DB_ERROR_UNKNOWN;
}
break;
case DB_CLAUSE_LESS_OR_EQUAL:
if ((ret = snprintf(*sqlp, *left, " %s.%s <= ?",
db_object_table(object),
db_clause_field(clause))) >= *left)
{
return DB_ERROR_UNKNOWN;
}
break;
case DB_CLAUSE_GREATER_OR_EQUAL:
if ((ret = snprintf(*sqlp, *left, " %s.%s >= ?",
db_object_table(object),
db_clause_field(clause))) >= *left)
{
return DB_ERROR_UNKNOWN;
}
break;
case DB_CLAUSE_GREATER_THEN:
if ((ret = snprintf(*sqlp, *left, " %s.%s > ?",
db_object_table(object),
db_clause_field(clause))) >= *left)
{
return DB_ERROR_UNKNOWN;
}
break;
case DB_CLAUSE_IS_NULL:
if ((ret = snprintf(*sqlp, *left, " %s.%s IS NULL",
db_object_table(object),
db_clause_field(clause))) >= *left)
{
return DB_ERROR_UNKNOWN;
}
break;
case DB_CLAUSE_IS_NOT_NULL:
if ((ret = snprintf(*sqlp, *left, " %s.%s IS NOT NULL",
db_object_table(object),
db_clause_field(clause))) >= *left)
{
return DB_ERROR_UNKNOWN;
}
break;
case DB_CLAUSE_NESTED:
if ((ret = snprintf(*sqlp, *left, " (")) >= *left) {
return DB_ERROR_UNKNOWN;
}
*sqlp += ret;
*left -= ret;
if (__db_backend_mysql_build_clause(object, db_clause_list(clause), sqlp, left)) {
return DB_ERROR_UNKNOWN;
}
if ((ret = snprintf(*sqlp, *left, " )")) >= *left) {
return DB_ERROR_UNKNOWN;
}
break;
default:
return DB_ERROR_UNKNOWN;
}
*sqlp += ret;
*left -= ret;
clause = db_clause_next(clause);
}
return DB_OK;
}
static int __db_backend_mysql_bind_clause(db_backend_mysql_bind_t** bind, const db_clause_list_t* clause_list) {
const db_clause_t* clause;
const db_type_int32_t* int32;
const db_type_uint32_t* uint32;
const db_type_int64_t* int64;
const db_type_uint64_t* uint64;
const char* text;
if (!bind) {
return DB_ERROR_UNKNOWN;
}
if (!*bind) {
return DB_ERROR_UNKNOWN;
}
if (!clause_list) {
return DB_ERROR_UNKNOWN;
}
clause = db_clause_list_begin(clause_list);
while (clause) {
if (!*bind) {
return DB_ERROR_UNKNOWN;
}
(*bind)->bind->length = &((*bind)->bind->buffer_length);
(*bind)->bind->is_null = (my_bool*)0;
switch (db_clause_type(clause)) {
case DB_CLAUSE_EQUAL:
case DB_CLAUSE_NOT_EQUAL:
case DB_CLAUSE_LESS_THEN:
case DB_CLAUSE_LESS_OR_EQUAL:
case DB_CLAUSE_GREATER_OR_EQUAL:
case DB_CLAUSE_GREATER_THEN:
switch (db_value_type(db_clause_value(clause))) {
case DB_TYPE_PRIMARY_KEY:
case DB_TYPE_INT32:
if (!(int32 = db_value_int32(db_clause_value(clause)))) {
return DB_ERROR_UNKNOWN;
}
(*bind)->bind->buffer_type = MYSQL_TYPE_LONG;
(*bind)->bind->buffer = (void*)int32;
(*bind)->bind->buffer_length = sizeof(db_type_int32_t);
(*bind)->bind->is_unsigned = 0;
break;
case DB_TYPE_UINT32:
if (!(uint32 = db_value_uint32(db_clause_value(clause)))) {
return DB_ERROR_UNKNOWN;
}
(*bind)->bind->buffer_type = MYSQL_TYPE_LONG;
(*bind)->bind->buffer = (void*)uint32;
(*bind)->bind->buffer_length = sizeof(db_type_uint32_t);
(*bind)->bind->is_unsigned = 1;
break;
case DB_TYPE_INT64:
if (!(int64 = db_value_int64(db_clause_value(clause)))) {
return DB_ERROR_UNKNOWN;
}
(*bind)->bind->buffer_type = MYSQL_TYPE_LONGLONG;
(*bind)->bind->buffer = (void*)int64;
(*bind)->bind->buffer_length = sizeof(db_type_int64_t);
(*bind)->bind->is_unsigned = 0;
break;
case DB_TYPE_UINT64:
if (!(uint64 = db_value_uint64(db_clause_value(clause)))) {
return DB_ERROR_UNKNOWN;
}
(*bind)->bind->buffer_type = MYSQL_TYPE_LONGLONG;
(*bind)->bind->buffer = (void*)uint64;
(*bind)->bind->buffer_length = sizeof(db_type_uint64_t);
(*bind)->bind->is_unsigned = 1;
break;
case DB_TYPE_TEXT:
if (!(text = db_value_text(db_clause_value(clause)))) {
return DB_ERROR_UNKNOWN;
}
(*bind)->bind->buffer_type = MYSQL_TYPE_STRING;
(*bind)->bind->buffer = (void*)text;
(*bind)->bind->buffer_length = strlen(text);
(*bind)->bind->is_unsigned = 0;
break;
case DB_TYPE_ENUM:
if (db_value_enum_value(db_clause_value(clause), &((*bind)->value_enum))) {
return DB_ERROR_UNKNOWN;
}
(*bind)->bind->buffer_type = MYSQL_TYPE_LONG;
(*bind)->bind->buffer = (void*)&((*bind)->value_enum);
(*bind)->bind->buffer_length = sizeof(int);
(*bind)->bind->is_unsigned = 0;
break;
default:
return DB_ERROR_UNKNOWN;
}
break;
case DB_CLAUSE_IS_NULL:
/* TODO: is null */
break;
case DB_CLAUSE_IS_NOT_NULL:
/* TODO: is not null */
break;
case DB_CLAUSE_NESTED:
*bind = (*bind)->next;
if (__db_backend_mysql_bind_clause(bind, db_clause_list(clause))) {
return DB_ERROR_UNKNOWN;
}
clause = db_clause_next(clause);
continue;
default:
return DB_ERROR_UNKNOWN;
}
*bind = (*bind)->next;
clause = db_clause_next(clause);
}
return DB_OK;
}
static int __db_backend_mysql_bind_value(db_backend_mysql_bind_t* bind, const db_value_t* value) {
const db_type_int32_t* int32;
const db_type_uint32_t* uint32;
const db_type_int64_t* int64;
const db_type_uint64_t* uint64;
const char* text;
if (!bind) {
return DB_ERROR_UNKNOWN;
}
if (!bind->bind) {
return DB_ERROR_UNKNOWN;
}
if (!value) {
return DB_ERROR_UNKNOWN;
}
bind->bind->length = &(bind->bind->buffer_length);
bind->bind->is_null = (my_bool*)0;
switch (db_value_type(value)) {
case DB_TYPE_PRIMARY_KEY:
case DB_TYPE_INT32:
if (!(int32 = db_value_int32(value))) {
return DB_ERROR_UNKNOWN;
}
bind->bind->buffer_type = MYSQL_TYPE_LONG;
bind->bind->buffer = (void*)int32;
bind->bind->buffer_length = sizeof(db_type_int32_t);
bind->bind->is_unsigned = 0;
break;
case DB_TYPE_UINT32:
if (!(uint32 = db_value_uint32(value))) {
return DB_ERROR_UNKNOWN;
}
bind->bind->buffer_type = MYSQL_TYPE_LONG;
bind->bind->buffer = (void*)uint32;
bind->bind->buffer_length = sizeof(db_type_uint32_t);
bind->bind->is_unsigned = 1;
break;
case DB_TYPE_INT64:
if (!(int64 = db_value_int64(value))) {
return DB_ERROR_UNKNOWN;
}
bind->bind->buffer_type = MYSQL_TYPE_LONGLONG;
bind->bind->buffer = (void*)int64;
bind->bind->buffer_length = sizeof(db_type_int64_t);
bind->bind->is_unsigned = 0;
break;
case DB_TYPE_UINT64:
if (!(uint64 = db_value_uint64(value))) {
return DB_ERROR_UNKNOWN;
}
bind->bind->buffer_type = MYSQL_TYPE_LONGLONG;
bind->bind->buffer = (void*)uint64;
bind->bind->buffer_length = sizeof(db_type_uint64_t);
bind->bind->is_unsigned = 1;
break;
case DB_TYPE_TEXT:
if (!(text = db_value_text(value))) {
return DB_ERROR_UNKNOWN;
}
bind->bind->buffer_type = MYSQL_TYPE_STRING;
bind->bind->buffer = (void*)text;
bind->bind->buffer_length = strlen(text);
bind->bind->is_unsigned = 0;
break;
case DB_TYPE_ENUM:
if (db_value_enum_value(value, &(bind->value_enum))) {
return DB_ERROR_UNKNOWN;
}
bind->bind->buffer_type = MYSQL_TYPE_LONG;
bind->bind->buffer = (void*)&(bind->value_enum);
bind->bind->buffer_length = sizeof(int);
bind->bind->is_unsigned = 0;
break;
default:
return DB_ERROR_UNKNOWN;
}
return DB_OK;
}
static int __db_backend_mysql_bind_value_set(db_backend_mysql_bind_t** bind, const db_value_set_t* value_set) {
size_t i;
if (!bind) {
return DB_ERROR_UNKNOWN;
}
if (!*bind) {
return DB_ERROR_UNKNOWN;
}
if (!value_set) {
return DB_ERROR_UNKNOWN;
}
for (i = 0; i < db_value_set_size(value_set); i++, *bind = (*bind)->next) {
if (!*bind) {
return DB_ERROR_UNKNOWN;
}
if (__db_backend_mysql_bind_value(*bind, db_value_set_at(value_set, i))) {
return DB_ERROR_UNKNOWN;
}
}
return DB_OK;
}
static db_result_t* db_backend_mysql_next(void* data, int finish) {
db_backend_mysql_statement_t* statement = (db_backend_mysql_statement_t*)data;
db_result_t* result = NULL;
db_value_set_t* value_set = NULL;
const db_object_field_t* object_field;
db_backend_mysql_bind_t* bind;
int value;
if (!statement) {
return NULL;
}
if (!statement->object_field_list) {
return NULL;
}
if (!statement->statement) {
return NULL;
}
if (finish) {
__db_backend_mysql_finish(statement);
return NULL;
}
if (__db_backend_mysql_fetch(statement)) {
return NULL;
}
if (!(result = db_result_new())
|| !(value_set = db_value_set_new(statement->fields))
|| db_result_set_value_set(result, value_set))
{
db_result_free(result);
db_value_set_free(value_set);
return NULL;
}
object_field = db_object_field_list_begin(statement->object_field_list);
bind = statement->bind_output;
value = 0;
while (object_field) {
if (!bind || !bind->bind || !bind->bind->buffer) {
db_result_free(result);
return NULL;
}
switch (db_object_field_type(object_field)) {
case DB_TYPE_PRIMARY_KEY:
case DB_TYPE_ANY:
case DB_TYPE_REVISION:
switch (bind->bind->buffer_type) {
case MYSQL_TYPE_LONG:
if ((bind->bind->is_unsigned
&& db_value_from_uint32(db_value_set_get(value_set, value), *((db_type_uint32_t*)bind->bind->buffer)))
|| (!bind->bind->is_unsigned
&& db_value_from_int32(db_value_set_get(value_set, value), *((db_type_int32_t*)bind->bind->buffer))))
{
db_result_free(result);
return NULL;
}
break;
case MYSQL_TYPE_LONGLONG:
if ((bind->bind->is_unsigned
&& db_value_from_uint64(db_value_set_get(value_set, value), *((db_type_uint64_t*)bind->bind->buffer)))
|| (!bind->bind->is_unsigned
&& db_value_from_int64(db_value_set_get(value_set, value), *((db_type_int64_t*)bind->bind->buffer))))
{
db_result_free(result);
return NULL;
}
break;
case MYSQL_TYPE_STRING:
if ((!bind->length
&& db_value_from_text(db_value_set_get(value_set, value), ""))
|| (bind->length
&& db_value_from_text2(db_value_set_get(value_set, value), (char*)bind->bind->buffer, bind->length)))
{
db_result_free(result);
return NULL;
}
break;
default:
db_result_free(result);
return NULL;
}
if (db_object_field_type(object_field) == DB_TYPE_PRIMARY_KEY
&& db_value_set_primary_key(db_value_set_get(value_set, value)))
{
db_result_free(result);
return NULL;
}
break;
case DB_TYPE_ENUM:
/*
* Enum needs to be handled elsewhere since we don't know the
* enum_set_t here.
*/
case DB_TYPE_INT32:
case DB_TYPE_UINT32:
if (bind->bind->buffer_type != MYSQL_TYPE_LONG
|| (bind->bind->is_unsigned
&& db_value_from_uint32(db_value_set_get(value_set, value), *((db_type_uint32_t*)bind->bind->buffer)))
|| (!bind->bind->is_unsigned
&& db_value_from_int32(db_value_set_get(value_set, value), *((db_type_int32_t*)bind->bind->buffer))))
{
db_result_free(result);
return NULL;
}
break;
case DB_TYPE_INT64:
case DB_TYPE_UINT64:
if (bind->bind->buffer_type != MYSQL_TYPE_LONGLONG
|| (bind->bind->is_unsigned
&& db_value_from_uint64(db_value_set_get(value_set, value), *((db_type_uint64_t*)bind->bind->buffer)))
|| (!bind->bind->is_unsigned
&& db_value_from_int64(db_value_set_get(value_set, value), *((db_type_int64_t*)bind->bind->buffer))))
{
db_result_free(result);
return NULL;
}
break;
case DB_TYPE_TEXT:
if (bind->bind->buffer_type != MYSQL_TYPE_STRING
|| (!bind->length
&& db_value_from_text(db_value_set_get(value_set, value), ""))
|| (bind->length
&& db_value_from_text2(db_value_set_get(value_set, value), (char*)bind->bind->buffer, bind->length)))
{
db_result_free(result);
return NULL;
}
break;
default:
db_result_free(result);
return NULL;
}
object_field = db_object_field_next(object_field);
value++;
bind = bind->next;
}
return result;
}
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) {
db_backend_mysql_t* backend_mysql = (db_backend_mysql_t*)data;
const db_object_field_t* object_field;
const db_object_field_t* revision_field = NULL;
char sql[4*1024];
char* sqlp;
int ret, left, first;
db_backend_mysql_statement_t* statement = NULL;
db_backend_mysql_bind_t* bind;
db_value_t revision = DB_VALUE_EMPTY;
if (!__mysql_initialized) {
return DB_ERROR_UNKNOWN;
}
if (!backend_mysql) {
return DB_ERROR_UNKNOWN;
}
if (!object) {
return DB_ERROR_UNKNOWN;
}
if (!object_field_list) {
return DB_ERROR_UNKNOWN;
}
if (!value_set) {
return DB_ERROR_UNKNOWN;
}
/*
* Check if the object has a revision field and keep it for later use.
*/
object_field = db_object_field_list_begin(db_object_object_field_list(object));
while (object_field) {
if (db_object_field_type(object_field) == DB_TYPE_REVISION) {
if (revision_field) {
/*
* We do not support multiple revision fields.
*/
return DB_ERROR_UNKNOWN;
}
revision_field = object_field;
}
object_field = db_object_field_next(object_field);
}
left = sizeof(sql);
sqlp = sql;
memset(sql, 0, left);
if (!db_object_field_list_begin(object_field_list) && !revision_field) {
/*
* Special case when tables has no fields except maybe a primary key.
*/
if ((ret = snprintf(sqlp, left, "INSERT INTO %s () VALUES ()", db_object_table(object))) >= left) {
return DB_ERROR_UNKNOWN;
}
sqlp += ret;
left -= ret;
}
else {
if ((ret = snprintf(sqlp, left, "INSERT INTO %s (", db_object_table(object))) >= left) {
return DB_ERROR_UNKNOWN;
}
sqlp += ret;
left -= ret;
/*
* Add the fields from the given object_field_list.
*/
object_field = db_object_field_list_begin(object_field_list);
first = 1;
while (object_field) {
if (first) {
if ((ret = snprintf(sqlp, left, " %s", db_object_field_name(object_field))) >= left) {
return DB_ERROR_UNKNOWN;
}
first = 0;
}
else {
if ((ret = snprintf(sqlp, left, ", %s", db_object_field_name(object_field))) >= left) {
return DB_ERROR_UNKNOWN;
}
}
sqlp += ret;
left -= ret;
object_field = db_object_field_next(object_field);
}
/*
* Add the revision field if we have one.
*/
if (revision_field) {
if (first) {
if ((ret = snprintf(sqlp, left, " %s", db_object_field_name(revision_field))) >= left) {
return DB_ERROR_UNKNOWN;
}
first = 0;
}
else {
if ((ret = snprintf(sqlp, left, ", %s", db_object_field_name(revision_field))) >= left) {
return DB_ERROR_UNKNOWN;
}
}
sqlp += ret;
left -= ret;
}
if ((ret = snprintf(sqlp, left, " ) VALUES (")) >= left) {
return DB_ERROR_UNKNOWN;
}
sqlp += ret;
left -= ret;
/*
* Mark all the fields for binding from the object_field_list.
*/
object_field = db_object_field_list_begin(object_field_list);
first = 1;
while (object_field) {
if (first) {
if ((ret = snprintf(sqlp, left, " ?")) >= left) {
return DB_ERROR_UNKNOWN;
}
first = 0;
}
else {
if ((ret = snprintf(sqlp, left, ", ?")) >= left) {
return DB_ERROR_UNKNOWN;
}
}
sqlp += ret;
left -= ret;
object_field = db_object_field_next(object_field);
}
/*
* Mark revision field for binding if we have one.
*/
if (revision_field) {
if (first) {
if ((ret = snprintf(sqlp, left, " ?")) >= left) {
return DB_ERROR_UNKNOWN;
}
first = 0;
}
else {
if ((ret = snprintf(sqlp, left, ", ?")) >= left) {
return DB_ERROR_UNKNOWN;
}
}
sqlp += ret;
left -= ret;
}
if ((ret = snprintf(sqlp, left, " )")) >= left) {
return DB_ERROR_UNKNOWN;
}
sqlp += ret;
left -= ret;
}
/*
* Prepare the SQL, create a MySQL statement.
*/
if (__db_backend_mysql_prepare(backend_mysql, &statement, sql, strlen(sql), db_object_object_field_list(object))
|| !statement
|| !(bind = statement->bind_input))
{
__db_backend_mysql_finish(statement);
return DB_ERROR_UNKNOWN;
}
/*
* Bind all the values from value_set.
*/
if (__db_backend_mysql_bind_value_set(&bind, value_set)) {
__db_backend_mysql_finish(statement);
return DB_ERROR_UNKNOWN;
}
/*
* Bind the revision field value if we have one.
*/
if (revision_field) {
if (db_value_from_int64(&revision, 1)
|| __db_backend_mysql_bind_value(bind, &revision))
{
db_value_reset(&revision);
__db_backend_mysql_finish(statement);
return DB_ERROR_UNKNOWN;
}
db_value_reset(&revision);
}
/*
* Execute the SQL.
*/
if (__db_backend_mysql_execute(statement)
|| mysql_stmt_affected_rows(statement->statement) != 1)
{
__db_backend_mysql_finish(statement);
return DB_ERROR_UNKNOWN;
}
__db_backend_mysql_finish(statement);
return DB_OK;
}
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) {
db_backend_mysql_t* backend_mysql = (db_backend_mysql_t*)data;
const db_object_field_t* object_field;
const db_join_t* join;
char sql[4*1024];
char* sqlp;
int ret, left, first;
db_result_list_t* result_list;
db_backend_mysql_statement_t* statement = NULL;
db_backend_mysql_bind_t* bind;
if (!__mysql_initialized) {
return NULL;
}
if (!backend_mysql) {
return NULL;
}
if (!object) {
return NULL;
}
left = sizeof(sql);
sqlp = sql;
memset(sql, 0, left);
if ((ret = snprintf(sqlp, left, "SELECT")) >= left) {
return NULL;
}
sqlp += ret;
left -= ret;
object_field = db_object_field_list_begin(db_object_object_field_list(object));
first = 1;
while (object_field) {
if (first) {
if ((ret = snprintf(sqlp, left, " %s.%s", db_object_table(object), db_object_field_name(object_field))) >= left) {
return NULL;
}
first = 0;
}
else {
if ((ret = snprintf(sqlp, left, ", %s.%s", db_object_table(object), db_object_field_name(object_field))) >= left) {
return NULL;
}
}
sqlp += ret;
left -= ret;
object_field = db_object_field_next(object_field);
}
if ((ret = snprintf(sqlp, left, " FROM %s", db_object_table(object))) >= left) {
return NULL;
}
sqlp += ret;
left -= ret;
if (join_list) {
join = db_join_list_begin(join_list);
while (join) {
if ((ret = snprintf(sqlp, left, " INNER JOIN %s ON %s.%s = %s.%s",
db_join_to_table(join),
db_join_to_table(join),
db_join_to_field(join),
db_join_from_table(join),
db_join_from_field(join))) >= left)
{
return NULL;
}
sqlp += ret;
left -= ret;
join = db_join_next(join);
}
}
if (clause_list) {
if (db_clause_list_begin(clause_list)) {
if ((ret = snprintf(sqlp, left, " WHERE")) >= left) {
return NULL;
}
sqlp += ret;
left -= ret;
}
if (__db_backend_mysql_build_clause(object, clause_list, &sqlp, &left)) {
return NULL;
}
}
if (__db_backend_mysql_prepare(backend_mysql, &statement, sql, strlen(sql), db_object_object_field_list(object))
|| !statement)
{
__db_backend_mysql_finish(statement);
return NULL;
}
bind = statement->bind_input;
if (clause_list) {
if (__db_backend_mysql_bind_clause(&bind, clause_list)) {
__db_backend_mysql_finish(statement);
return NULL;
}
}
/*
* Execute the SQL.
*/
if (__db_backend_mysql_execute(statement)) {
__db_backend_mysql_finish(statement);
return NULL;
}
if (!(result_list = db_result_list_new())
|| db_result_list_set_next(result_list, db_backend_mysql_next, statement, mysql_stmt_affected_rows(statement->statement)))
{
db_result_list_free(result_list);
__db_backend_mysql_finish(statement);
return NULL;
}
return result_list;
}
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) {
db_backend_mysql_t* backend_mysql = (db_backend_mysql_t*)data;
const db_object_field_t* object_field;
const db_object_field_t* revision_field = NULL;
const db_clause_t* clause;
const db_clause_t* revision_clause = NULL;
db_type_int64_t revision_number = -1;
char sql[4*1024];
char* sqlp;
int ret, left, first;
db_backend_mysql_statement_t* statement = NULL;
db_backend_mysql_bind_t* bind;
db_value_t revision = DB_VALUE_EMPTY;
db_type_int32_t int32;
db_type_uint32_t uint32;
db_type_int64_t int64;
db_type_uint64_t uint64;
if (!__mysql_initialized) {
return DB_ERROR_UNKNOWN;
}
if (!backend_mysql) {
return DB_ERROR_UNKNOWN;
}
if (!object) {
return DB_ERROR_UNKNOWN;
}
if (!object_field_list) {
return DB_ERROR_UNKNOWN;
}
if (!value_set) {
return DB_ERROR_UNKNOWN;
}
/*
* Check if the object has a revision field and keep it for later use.
*/
object_field = db_object_field_list_begin(db_object_object_field_list(object));
while (object_field) {
if (db_object_field_type(object_field) == DB_TYPE_REVISION) {
if (revision_field) {
/*
* We do not support multiple revision fields.
*/
return DB_ERROR_UNKNOWN;
}
revision_field = object_field;
}
object_field = db_object_field_next(object_field);
}
if (revision_field) {
/*
* If we have a revision field we should also have it in the clause,
* find it and get the value for later use or return error if not found.
*/
clause = db_clause_list_begin(clause_list);
while (clause) {
if (!strcmp(db_clause_field(clause), db_object_field_name(revision_field))) {
revision_clause = clause;
break;
}
clause = db_clause_next(clause);
}
if (!revision_clause) {
return DB_ERROR_UNKNOWN;
}
switch (db_value_type(db_clause_value(revision_clause))) {
case DB_TYPE_INT32:
if (db_value_to_int32(db_clause_value(revision_clause), &int32)) {
return DB_ERROR_UNKNOWN;
}
revision_number = int32;
break;
case DB_TYPE_UINT32:
if (db_value_to_uint32(db_clause_value(revision_clause), &uint32)) {
return DB_ERROR_UNKNOWN;
}
revision_number = uint32;
break;
case DB_TYPE_INT64:
if (db_value_to_int64(db_clause_value(revision_clause), &int64)) {
return DB_ERROR_UNKNOWN;
}
revision_number = int64;
break;
case DB_TYPE_UINT64:
if (db_value_to_uint64(db_clause_value(revision_clause), &uint64)) {
return DB_ERROR_UNKNOWN;
}
revision_number = uint64;
break;
default:
return DB_ERROR_UNKNOWN;
}
}
left = sizeof(sql);
sqlp = sql;
memset(sql, 0, left);
if ((ret = snprintf(sqlp, left, "UPDATE %s SET", db_object_table(object))) >= left) {
return DB_ERROR_UNKNOWN;
}
sqlp += ret;
left -= ret;
/*
* Build the update SQL from the object_field_list.
*/
object_field = db_object_field_list_begin(object_field_list);
first = 1;
while (object_field) {
if (first) {
if ((ret = snprintf(sqlp, left, " %s = ?", db_object_field_name(object_field))) >= left) {
return DB_ERROR_UNKNOWN;
}
first = 0;
}
else {
if ((ret = snprintf(sqlp, left, ", %s = ?", db_object_field_name(object_field))) >= left) {
return DB_ERROR_UNKNOWN;
}
}
sqlp += ret;
left -= ret;
object_field = db_object_field_next(object_field);
}
/*
* Add a new revision if we have any.
*/
if (revision_field) {
if (first) {
if ((ret = snprintf(sqlp, left, " %s = ?", db_object_field_name(revision_field))) >= left) {
return DB_ERROR_UNKNOWN;
}
first = 0;
}
else {
if ((ret = snprintf(sqlp, left, ", %s = ?", db_object_field_name(revision_field))) >= left) {
return DB_ERROR_UNKNOWN;
}
}
sqlp += ret;
left -= ret;
}
/*
* Build the clauses.
*/
if (clause_list) {
if (db_clause_list_begin(clause_list)) {
if ((ret = snprintf(sqlp, left, " WHERE")) >= left) {
return DB_ERROR_UNKNOWN;
}
sqlp += ret;
left -= ret;
}
if (__db_backend_mysql_build_clause(object, clause_list, &sqlp, &left)) {
return DB_ERROR_UNKNOWN;
}
}
/*
* Prepare the SQL.
*/
if (__db_backend_mysql_prepare(backend_mysql, &statement, sql, strlen(sql), db_object_object_field_list(object))
|| !statement)
{
__db_backend_mysql_finish(statement);
return DB_ERROR_UNKNOWN;
}
bind = statement->bind_input;
/*
* Bind all the values from value_set.
*/
if (value_set) {
if (__db_backend_mysql_bind_value_set(&bind, value_set)) {
__db_backend_mysql_finish(statement);
return DB_ERROR_UNKNOWN;
}
}
/*
* Bind the new revision if we have any.
*/
if (revision_field) {
if (db_value_from_int64(&revision, revision_number + 1)
|| __db_backend_mysql_bind_value(bind, &revision))
{
db_value_reset(&revision);
__db_backend_mysql_finish(statement);
return DB_ERROR_UNKNOWN;
}
if (bind) {
bind = bind->next;
}
}
/*
* Bind the clauses values.
*/
if (clause_list) {
if (__db_backend_mysql_bind_clause(&bind, clause_list)) {
__db_backend_mysql_finish(statement);
return DB_ERROR_UNKNOWN;
}
}
/*
* Execute the SQL.
*/
if (__db_backend_mysql_execute(statement)) {
__db_backend_mysql_finish(statement);
return DB_ERROR_UNKNOWN;
}
/*
* If we are using revision we have to have a positive number of changes
* otherwise its a failure.
*/
if (revision_field) {
if (mysql_stmt_affected_rows(statement->statement) < 1) {
__db_backend_mysql_finish(statement);
return DB_ERROR_UNKNOWN;
}
}
__db_backend_mysql_finish(statement);
return DB_OK;
}
static int db_backend_mysql_delete(void* data, const db_object_t* object, const db_clause_list_t* clause_list) {
db_backend_mysql_t* backend_mysql = (db_backend_mysql_t*)data;
char sql[4*1024];
char* sqlp;
int ret, left;
const db_object_field_t* revision_field = NULL;
const db_object_field_t* object_field;
const db_clause_t* clause;
db_backend_mysql_statement_t* statement = NULL;
db_backend_mysql_bind_t* bind;
if (!__mysql_initialized) {
return DB_ERROR_UNKNOWN;
}
if (!backend_mysql) {
return DB_ERROR_UNKNOWN;
}
if (!object) {
return DB_ERROR_UNKNOWN;
}
/*
* Check if the object has a revision field and keep it for later use.
*/
object_field = db_object_field_list_begin(db_object_object_field_list(object));
while (object_field) {
if (db_object_field_type(object_field) == DB_TYPE_REVISION) {
if (revision_field) {
/*
* We do not support multiple revision fields.
*/
return DB_ERROR_UNKNOWN;
}
revision_field = object_field;
}
object_field = db_object_field_next(object_field);
}
if (revision_field) {
/*
* If we have a revision field we should also have it in the clause,
* find it or return error if not found.
*/
clause = db_clause_list_begin(clause_list);
while (clause) {
if (!strcmp(db_clause_field(clause), db_object_field_name(revision_field))) {
break;
}
clause = db_clause_next(clause);
}
if (!clause) {
return DB_ERROR_UNKNOWN;
}
}
left = sizeof(sql);
sqlp = sql;
memset(sql, 0, left);
if ((ret = snprintf(sqlp, left, "DELETE FROM %s", db_object_table(object))) >= left) {
return DB_ERROR_UNKNOWN;
}
sqlp += ret;
left -= ret;
if (clause_list) {
if (db_clause_list_begin(clause_list)) {
if ((ret = snprintf(sqlp, left, " WHERE")) >= left) {
return DB_ERROR_UNKNOWN;
}
sqlp += ret;
left -= ret;
}
if (__db_backend_mysql_build_clause(object, clause_list, &sqlp, &left)) {
return DB_ERROR_UNKNOWN;
}
}
if (__db_backend_mysql_prepare(backend_mysql, &statement, sql, strlen(sql), db_object_object_field_list(object))
|| !statement)
{
__db_backend_mysql_finish(statement);
return DB_ERROR_UNKNOWN;
}
bind = statement->bind_input;
if (clause_list) {
if (__db_backend_mysql_bind_clause(&bind, clause_list)) {
__db_backend_mysql_finish(statement);
return DB_ERROR_UNKNOWN;
}
}
if (__db_backend_mysql_execute(statement)) {
__db_backend_mysql_finish(statement);
return DB_ERROR_UNKNOWN;
}
/*
* If we are using revision we have to have a positive number of changes
* otherwise its a failure.
*/
if (revision_field) {
if (mysql_stmt_affected_rows(statement->statement) < 1) {
__db_backend_mysql_finish(statement);
return DB_ERROR_UNKNOWN;
}
}
__db_backend_mysql_finish(statement);
return DB_OK;
}
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) {
db_backend_mysql_t* backend_mysql = (db_backend_mysql_t*)data;
const db_join_t* join;
char sql[4*1024];
char* sqlp;
int ret, left;
db_backend_mysql_statement_t* statement = NULL;
db_backend_mysql_bind_t* bind;
db_object_field_list_t* object_field_list;
db_object_field_t* object_field = NULL;
if (!__mysql_initialized) {
return DB_ERROR_UNKNOWN;
}
if (!backend_mysql) {
return DB_ERROR_UNKNOWN;
}
if (!object) {
return DB_ERROR_UNKNOWN;
}
if (!count) {
return DB_ERROR_UNKNOWN;
}
left = sizeof(sql);
sqlp = sql;
memset(sql, 0, left);
if ((ret = snprintf(sqlp, left, "SELECT COUNT(*)")) >= left) {
return DB_ERROR_UNKNOWN;
}
sqlp += ret;
left -= ret;
if ((ret = snprintf(sqlp, left, " FROM %s", db_object_table(object))) >= left) {
return DB_ERROR_UNKNOWN;
}
sqlp += ret;
left -= ret;
if (join_list) {
join = db_join_list_begin(join_list);
while (join) {
if ((ret = snprintf(sqlp, left, " INNER JOIN %s ON %s.%s = %s.%s",
db_join_to_table(join),
db_join_to_table(join),
db_join_to_field(join),
db_join_from_table(join),
db_join_from_field(join))) >= left)
{
return DB_ERROR_UNKNOWN;
}
sqlp += ret;
left -= ret;
join = db_join_next(join);
}
}
if (clause_list) {
if (db_clause_list_begin(clause_list)) {
if ((ret = snprintf(sqlp, left, " WHERE")) >= left) {
return DB_ERROR_UNKNOWN;
}
sqlp += ret;
left -= ret;
}
if (__db_backend_mysql_build_clause(object, clause_list, &sqlp, &left)) {
return DB_ERROR_UNKNOWN;
}
}
if (!(object_field_list = db_object_field_list_new())
|| !(object_field = db_object_field_new())
|| db_object_field_set_name(object_field, "countField")
|| db_object_field_set_type(object_field, DB_TYPE_UINT32)
|| db_object_field_list_add(object_field_list, object_field))
{
db_object_field_free(object_field);
db_object_field_list_free(object_field_list);
return DB_ERROR_UNKNOWN;
}
if (__db_backend_mysql_prepare(backend_mysql, &statement, sql, strlen(sql), object_field_list)
|| !statement)
{
db_object_field_list_free(object_field_list);
__db_backend_mysql_finish(statement);
return DB_ERROR_UNKNOWN;
}
db_object_field_list_free(object_field_list);
bind = statement->bind_input;
if (clause_list) {
if (__db_backend_mysql_bind_clause(&bind, clause_list)) {
__db_backend_mysql_finish(statement);
return DB_ERROR_UNKNOWN;
}
}
if (__db_backend_mysql_execute(statement)) {
__db_backend_mysql_finish(statement);
return DB_ERROR_UNKNOWN;
}
if (__db_backend_mysql_fetch(statement)) {
__db_backend_mysql_finish(statement);
return DB_ERROR_UNKNOWN;
}
bind = statement->bind_output;
if (!bind || !bind->bind || !bind->bind->buffer
|| bind->bind->buffer_type != MYSQL_TYPE_LONG
|| !bind->bind->is_unsigned
|| bind->length != sizeof(db_type_uint32_t))
{
__db_backend_mysql_finish(statement);
return DB_ERROR_UNKNOWN;
}
*count = *((db_type_uint32_t*)bind->bind->buffer);
__db_backend_mysql_finish(statement);
return DB_OK;
}
static void db_backend_mysql_free(void* data) {
db_backend_mysql_t* backend_mysql = (db_backend_mysql_t*)data;
if (backend_mysql) {
if (backend_mysql->db) {
(void)db_backend_mysql_disconnect(backend_mysql);
}
free(backend_mysql);
}
}
static int db_backend_mysql_transaction_begin(void* data) {
db_backend_mysql_t* backend_mysql = (db_backend_mysql_t*)data;
static const char* sql = "BEGIN TRANSACTION";
db_backend_mysql_statement_t* statement = NULL;
if (!__mysql_initialized) {
return DB_ERROR_UNKNOWN;
}
if (!backend_mysql) {
return DB_ERROR_UNKNOWN;
}
if (backend_mysql->transaction) {
return DB_ERROR_UNKNOWN;
}
if (__db_backend_mysql_prepare(backend_mysql, &statement, sql, strlen(sql), NULL)) {
return DB_ERROR_UNKNOWN;
}
if (__db_backend_mysql_execute(statement)) {
__db_backend_mysql_finish(statement);
return DB_ERROR_UNKNOWN;
}
__db_backend_mysql_finish(statement);
backend_mysql->transaction = 1;
return DB_OK;
}
static int db_backend_mysql_transaction_commit(void* data) {
db_backend_mysql_t* backend_mysql = (db_backend_mysql_t*)data;
static const char* sql = "COMMIT TRANSACTION";
db_backend_mysql_statement_t* statement = NULL;
if (!__mysql_initialized) {
return DB_ERROR_UNKNOWN;
}
if (!backend_mysql) {
return DB_ERROR_UNKNOWN;
}
if (!backend_mysql->transaction) {
return DB_ERROR_UNKNOWN;
}
if (__db_backend_mysql_prepare(backend_mysql, &statement, sql, strlen(sql), NULL)) {
return DB_ERROR_UNKNOWN;
}
if (__db_backend_mysql_execute(statement)) {
__db_backend_mysql_finish(statement);
return DB_ERROR_UNKNOWN;
}
__db_backend_mysql_finish(statement);
backend_mysql->transaction = 0;
return DB_OK;
}
static int db_backend_mysql_transaction_rollback(void* data) {
db_backend_mysql_t* backend_mysql = (db_backend_mysql_t*)data;
static const char* sql = "ROLLBACK TRANSACTION";
db_backend_mysql_statement_t* statement = NULL;
if (!__mysql_initialized) {
return DB_ERROR_UNKNOWN;
}
if (!backend_mysql) {
return DB_ERROR_UNKNOWN;
}
if (!backend_mysql->transaction) {
return DB_ERROR_UNKNOWN;
}
if (__db_backend_mysql_prepare(backend_mysql, &statement, sql, strlen(sql), NULL)) {
return DB_ERROR_UNKNOWN;
}
if (__db_backend_mysql_execute(statement)) {
__db_backend_mysql_finish(statement);
return DB_ERROR_UNKNOWN;
}
__db_backend_mysql_finish(statement);
backend_mysql->transaction = 0;
return DB_OK;
}
db_backend_handle_t* db_backend_mysql_new_handle(void) {
db_backend_handle_t* backend_handle = NULL;
db_backend_mysql_t* backend_mysql =
(db_backend_mysql_t*)calloc(1, sizeof(db_backend_mysql_t));
if (backend_mysql && (backend_handle = db_backend_handle_new())) {
if (db_backend_handle_set_data(backend_handle, (void*)backend_mysql)
|| db_backend_handle_set_initialize(backend_handle, db_backend_mysql_initialize)
|| db_backend_handle_set_shutdown(backend_handle, db_backend_mysql_shutdown)
|| db_backend_handle_set_connect(backend_handle, db_backend_mysql_connect)
|| db_backend_handle_set_disconnect(backend_handle, db_backend_mysql_disconnect)
|| db_backend_handle_set_create(backend_handle, db_backend_mysql_create)
|| db_backend_handle_set_read(backend_handle, db_backend_mysql_read)
|| db_backend_handle_set_update(backend_handle, db_backend_mysql_update)
|| db_backend_handle_set_delete(backend_handle, db_backend_mysql_delete)
|| db_backend_handle_set_count(backend_handle, db_backend_mysql_count)
|| db_backend_handle_set_free(backend_handle, db_backend_mysql_free)
|| db_backend_handle_set_transaction_begin(backend_handle, db_backend_mysql_transaction_begin)
|| db_backend_handle_set_transaction_commit(backend_handle, db_backend_mysql_transaction_commit)
|| db_backend_handle_set_transaction_rollback(backend_handle, db_backend_mysql_transaction_rollback))
{
db_backend_handle_free(backend_handle);
free(backend_mysql);
return NULL;
}
}
return backend_handle;
}
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_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_backend_handle_new
db_backend_handle_t * db_backend_handle_new(void)
Definition db_backend.c:49
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_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_backend_handle_free
void db_backend_handle_free(db_backend_handle_t *backend_handle)
Definition db_backend.c:56
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_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_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_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_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_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_backend_handle_set_create
int db_backend_handle_set_create(db_backend_handle_t *backend_handle, db_backend_handle_create_t create_function)
Definition db_backend.c:214
db_backend_handle_set_data
int db_backend_handle_set_data(db_backend_handle_t *backend_handle, void *data)
Definition db_backend.c:295
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_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_backend_handle_t
struct db_backend_handle db_backend_handle_t
Definition db_backend.h:35
db_backend_mysql_new_handle
db_backend_handle_t * db_backend_mysql_new_handle(void)
Definition db_backend_mysql.c:2244
db_backend_mysql_statement_t
struct db_backend_mysql_statement db_backend_mysql_statement_t
db_backend_mysql_bind_t
struct db_backend_mysql_bind db_backend_mysql_bind_t
Definition db_backend_mysql.c:76
my_bool
_Bool my_bool
Definition db_backend_mysql.c:39
db_backend_mysql_t
struct db_backend_mysql db_backend_mysql_t
db_backend_mysql.h
DB_BACKEND_MYSQL_STRING_MIN_SIZE
#define DB_BACKEND_MYSQL_STRING_MIN_SIZE
Definition db_backend_mysql.h:36
DB_BACKEND_MYSQL_DEFAULT_TIMEOUT
#define DB_BACKEND_MYSQL_DEFAULT_TIMEOUT
Definition db_backend_mysql.h:35
db_clause_list
const db_clause_list_t * db_clause_list(const db_clause_t *clause)
Definition db_clause.c:101
db_clause_operator
db_clause_operator_t db_clause_operator(const db_clause_t *clause)
Definition db_clause.c:93
db_clause_value
const db_value_t * db_clause_value(const db_clause_t *clause)
Definition db_clause.c:85
db_clause_type
db_clause_type_t db_clause_type(const db_clause_t *clause)
Definition db_clause.c:77
db_clause_next
const db_clause_t * db_clause_next(const db_clause_t *clause)
Definition db_clause.c:179
db_clause_field
const char * db_clause_field(const db_clause_t *clause)
Definition db_clause.c:69
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_list_t
struct db_clause_list db_clause_list_t
Definition db_clause.h:110
DB_CLAUSE_OPERATOR_AND
@ DB_CLAUSE_OPERATOR_AND
Definition db_clause.h:97
DB_CLAUSE_OPERATOR_OR
@ DB_CLAUSE_OPERATOR_OR
Definition db_clause.h:101
DB_CLAUSE_NESTED
@ DB_CLAUSE_NESTED
Definition db_clause.h:76
DB_CLAUSE_GREATER_THEN
@ DB_CLAUSE_GREATER_THEN
Definition db_clause.h:64
DB_CLAUSE_NOT_EQUAL
@ DB_CLAUSE_NOT_EQUAL
Definition db_clause.h:48
DB_CLAUSE_IS_NOT_NULL
@ DB_CLAUSE_IS_NOT_NULL
Definition db_clause.h:72
DB_CLAUSE_GREATER_OR_EQUAL
@ DB_CLAUSE_GREATER_OR_EQUAL
Definition db_clause.h:60
DB_CLAUSE_IS_NULL
@ DB_CLAUSE_IS_NULL
Definition db_clause.h:68
DB_CLAUSE_EQUAL
@ DB_CLAUSE_EQUAL
Definition db_clause.h:44
DB_CLAUSE_LESS_OR_EQUAL
@ DB_CLAUSE_LESS_OR_EQUAL
Definition db_clause.h:56
DB_CLAUSE_LESS_THEN
@ DB_CLAUSE_LESS_THEN
Definition db_clause.h:52
db_clause_t
struct db_clause db_clause_t
Definition db_clause.h:109
db_configuration_value
const char * db_configuration_value(const db_configuration_t *configuration)
Definition db_configuration.c:60
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_configuration_t
struct db_configuration db_configuration_t
Definition db_configuration.h:35
db_configuration_list_t
struct db_configuration_list db_configuration_list_t
Definition db_configuration.h:36
db_error.h
DB_ERROR_UNKNOWN
#define DB_ERROR_UNKNOWN
Definition db_error.h:40
DB_OK
#define DB_OK
Definition db_error.h:36
db_join_from_table
const char * db_join_from_table(const db_join_t *join)
Definition db_join.c:41
db_join_from_field
const char * db_join_from_field(const db_join_t *join)
Definition db_join.c:49
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_join_to_table
const char * db_join_to_table(const db_join_t *join)
Definition db_join.c:57
db_join_next
const db_join_t * db_join_next(const db_join_t *join)
Definition db_join.c:73
db_join_to_field
const char * db_join_to_field(const db_join_t *join)
Definition db_join.c:65
db_join_list_t
struct db_join_list db_join_list_t
Definition db_join.h:36
db_join_t
struct db_join db_join_t
Definition db_join.h:35
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_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_object_field_type
db_type_t db_object_field_type(const db_object_field_t *object_field)
Definition db_object.c:102
db_object_field_new
db_object_field_t * db_object_field_new(void)
Definition db_object.c:40
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_name
int db_object_field_set_name(db_object_field_t *object_field, const char *name)
Definition db_object.c:110
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_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_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_object_table
const char * db_object_table(const db_object_t *object)
Definition db_object.c:327
db_object_field_list_new
db_object_field_list_t * db_object_field_list_new(void)
Definition db_object.c:174
db_object_field_name
const char * db_object_field_name(const db_object_field_t *object_field)
Definition db_object.c:94
db_object_field_free
void db_object_field_free(db_object_field_t *object_field)
Definition db_object.c:69
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_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_object_field_list_t
struct db_object_field_list db_object_field_list_t
Definition db_object.h:38
db_object_field_t
struct db_object_field db_object_field_t
Definition db_object.h:37
db_object_t
struct db_object db_object_t
Definition db_object.h:36
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_result_list_new
db_result_list_t * db_result_list_new(void)
Definition db_result.c:134
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_result_new
db_result_t * db_result_new(void)
Definition db_result.c:38
db_result_free
void db_result_free(db_result_t *result)
Definition db_result.c:63
db_result_list_free
void db_result_list_free(db_result_list_t *result_list)
Definition db_result.c:160
db_result_t
struct db_result db_result_t
Definition db_result.h:35
db_result_list_t
struct db_result_list db_result_list_t
Definition db_result.h:36
DB_TYPE_INT64
@ DB_TYPE_INT64
Definition db_type.h:74
DB_TYPE_UINT64
@ DB_TYPE_UINT64
Definition db_type.h:78
DB_TYPE_PRIMARY_KEY
@ DB_TYPE_PRIMARY_KEY
Definition db_type.h:62
DB_TYPE_REVISION
@ DB_TYPE_REVISION
Definition db_type.h:97
DB_TYPE_TEXT
@ DB_TYPE_TEXT
Definition db_type.h:82
DB_TYPE_INT32
@ DB_TYPE_INT32
Definition db_type.h:66
DB_TYPE_ENUM
@ DB_TYPE_ENUM
Definition db_type.h:86
DB_TYPE_UINT32
@ DB_TYPE_UINT32
Definition db_type.h:70
DB_TYPE_ANY
@ DB_TYPE_ANY
Definition db_type.h:90
db_type_uint64_t
uint64_t db_type_uint64_t
Definition db_type.h:50
db_type_uint32_t
uint32_t db_type_uint32_t
Definition db_type.h:42
db_type_int64_t
int64_t db_type_int64_t
Definition db_type.h:46
db_type_int32_t
int32_t db_type_int32_t
Definition db_type.h:38
db_value_int64
const db_type_int64_t * db_value_int64(const db_value_t *value)
Definition db_value.c:299
db_value_int32
const db_type_int32_t * db_value_int32(const db_value_t *value)
Definition db_value.c:277
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_value_type
db_type_t db_value_type(const db_value_t *value)
Definition db_value.c:269
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_value_set_primary_key
int db_value_set_primary_key(db_value_t *value)
Definition db_value.c:595
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_value_set_free
void db_value_set_free(db_value_set_t *value_set)
Definition db_value.c:697
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_value_set_new
db_value_set_t * db_value_set_new(size_t size)
Definition db_value.c:622
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_text
int db_value_from_text(db_value_t *value, const char *from_text)
Definition db_value.c:531
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_from_int64
int db_value_from_int64(db_value_t *value, db_type_int64_t from_int64)
Definition db_value.c:505
db_value_uint32
const db_type_uint32_t * db_value_uint32(const db_value_t *value)
Definition db_value.c:288
db_value_set_size
size_t db_value_set_size(const db_value_set_t *value_set)
Definition db_value.c:734
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_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_value_enum_value
int db_value_enum_value(const db_value_t *value, int *enum_value)
Definition db_value.c:332
db_value_uint64
const db_type_uint64_t * db_value_uint64(const db_value_t *value)
Definition db_value.c:310
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_value_reset
void db_value_reset(db_value_t *value)
Definition db_value.c:60
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_value_text
const char * db_value_text(const db_value_t *value)
Definition db_value.c:321
db_value_set_t
struct db_value_set db_value_set_t
Definition db_value.h:36
DB_VALUE_EMPTY
#define DB_VALUE_EMPTY
Definition db_value.h:60
db_value_t
struct db_value db_value_t
Definition db_value.h:35
db_backend_mysql_bind
Definition db_backend_mysql.c:77
db_backend_mysql_bind::next
db_backend_mysql_bind_t * next
Definition db_backend_mysql.c:78
db_backend_mysql_bind::bind
MYSQL_BIND * bind
Definition db_backend_mysql.c:79
db_backend_mysql_bind::value_enum
int value_enum
Definition db_backend_mysql.c:82
db_backend_mysql_bind::length
unsigned long length
Definition db_backend_mysql.c:80
db_backend_mysql_bind::error
my_bool error
Definition db_backend_mysql.c:81
db_backend_mysql_statement
Definition db_backend_mysql.c:90
db_backend_mysql_statement::fields
int fields
Definition db_backend_mysql.c:100
db_backend_mysql_statement::bind_input
db_backend_mysql_bind_t * bind_input
Definition db_backend_mysql.c:94
db_backend_mysql_statement::bind_output_end
db_backend_mysql_bind_t * bind_output_end
Definition db_backend_mysql.c:98
db_backend_mysql_statement::bind_input_end
db_backend_mysql_bind_t * bind_input_end
Definition db_backend_mysql.c:95
db_backend_mysql_statement::statement
MYSQL_STMT * statement
Definition db_backend_mysql.c:92
db_backend_mysql_statement::bound
int bound
Definition db_backend_mysql.c:101
db_backend_mysql_statement::bind_output
db_backend_mysql_bind_t * bind_output
Definition db_backend_mysql.c:97
db_backend_mysql_statement::backend_mysql
db_backend_mysql_t * backend_mysql
Definition db_backend_mysql.c:91
db_backend_mysql_statement::object_field_list
db_object_field_list_t * object_field_list
Definition db_backend_mysql.c:99
db_backend_mysql_statement::mysql_bind_input
MYSQL_BIND * mysql_bind_input
Definition db_backend_mysql.c:93
db_backend_mysql_statement::mysql_bind_output
MYSQL_BIND * mysql_bind_output
Definition db_backend_mysql.c:96
db_backend_mysql
Definition db_backend_mysql.c:60
db_backend_mysql::db_user
const char * db_user
Definition db_backend_mysql.c:65
db_backend_mysql::transaction
int transaction
Definition db_backend_mysql.c:62
db_backend_mysql::db_host
const char * db_host
Definition db_backend_mysql.c:64
db_backend_mysql::timeout
unsigned int timeout
Definition db_backend_mysql.c:63
db_backend_mysql::db
MYSQL * db
Definition db_backend_mysql.c:61
db_backend_mysql::db_pass
const char * db_pass
Definition db_backend_mysql.c:66
db_backend_mysql::db_name
const char * db_name
Definition db_backend_mysql.c:67
db_backend_mysql::db_port
int db_port
Definition db_backend_mysql.c:68