MySQL database connection handling
This commit is contained in:
328
src/database.c
Normal file
328
src/database.c
Normal file
@@ -0,0 +1,328 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <mysql.h>
|
||||
|
||||
#include "database.h"
|
||||
|
||||
|
||||
struct stored_conn_t *storedConnections = 0;
|
||||
int nextConnId = 1;
|
||||
int defaultTimeout = -1;
|
||||
|
||||
|
||||
struct stored_conn_t *connectionById(int conn_id)
|
||||
{
|
||||
struct stored_conn_t *ptr = storedConnections;
|
||||
|
||||
while (ptr != 0) {
|
||||
if (ptr->conn_id == conn_id) {
|
||||
return ptr;
|
||||
}
|
||||
ptr = ptr->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
struct stored_conn_t *connectionByName(const char *name)
|
||||
{
|
||||
struct stored_conn_t *ptr = storedConnections;
|
||||
|
||||
while (ptr != 0) {
|
||||
if (ptr->name != 0 && strcmp(ptr->name, name) == 0) {
|
||||
return ptr;
|
||||
}
|
||||
ptr = ptr->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct stored_conn_t *createStoredConnection(const char *name)
|
||||
{
|
||||
struct stored_conn_t *sconn, *tail;
|
||||
|
||||
if (name && strlen(name) > 0) {
|
||||
if (connectionByName(name) != 0) {
|
||||
fprintf(stderr, "createStoredConnection: Named connection already exists\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
sconn = (struct stored_conn_t *)malloc(sizeof(struct stored_conn_t));
|
||||
if (sconn == 0) {
|
||||
fprintf(stderr, "malloc: (%d) %s\n", errno, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
sconn->conn_id = nextConnId++;
|
||||
sconn->name = 0;
|
||||
sconn->conn = (MYSQL *)malloc(sizeof(MYSQL));
|
||||
sconn->isOpen = 0;
|
||||
sconn->isTransact = 0;
|
||||
sconn->needsReset = 0;
|
||||
sconn->timeout = -1;
|
||||
sconn->prev = 0;
|
||||
sconn->next = 0;
|
||||
|
||||
if (sconn->conn == 0) {
|
||||
fprintf(stderr, "malloc: (%d) %s\n", errno, strerror(errno));
|
||||
destroyStoredConnection(sconn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (name && strlen(name) > 0) {
|
||||
sconn->name = (char *)malloc(sizeof(char) * strlen(name));
|
||||
if (sconn->name == 0) {
|
||||
fprintf(stderr, "malloc: (%d) %s\n", errno, strerror(errno));
|
||||
destroyStoredConnection(sconn);
|
||||
return 0;
|
||||
}
|
||||
memcpy(sconn->name, name, strlen(name) * sizeof(char));
|
||||
}
|
||||
|
||||
if (mysql_init(sconn->conn) == 0) {
|
||||
fprintf(stderr, "mysql_init: unknown error\n");
|
||||
destroyStoredConnection(sconn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (defaultTimeout >= 0) {
|
||||
setTimeout(sconn, defaultTimeout);
|
||||
}
|
||||
|
||||
if (storedConnections == 0) {
|
||||
storedConnections = sconn;
|
||||
} else {
|
||||
tail = storedConnections;
|
||||
while (tail->next != 0) {
|
||||
tail = tail->next;
|
||||
}
|
||||
tail->next = sconn;
|
||||
sconn->prev = tail;
|
||||
}
|
||||
|
||||
return sconn;
|
||||
}
|
||||
struct stored_conn_t *resetStoredConnection(struct stored_conn_t *sconn)
|
||||
{
|
||||
MYSQL *new_conn;
|
||||
|
||||
new_conn = (MYSQL *)malloc(sizeof(MYSQL));
|
||||
if (new_conn == 0) {
|
||||
fprintf(stderr, "malloc: (%d) %s\n", errno, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mysql_init(new_conn) == 0) {
|
||||
fprintf(stderr, "mysql_init: unknown error\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
free(sconn->conn);
|
||||
sconn->conn = new_conn;
|
||||
|
||||
if (sconn->timeout >= 0) {
|
||||
setTimeout(sconn, sconn->timeout);
|
||||
}
|
||||
|
||||
sconn->needsReset = 0;
|
||||
|
||||
return sconn;
|
||||
}
|
||||
void destroyStoredConnection(struct stored_conn_t *sconn)
|
||||
{
|
||||
if (sconn->isTransact) {
|
||||
// rollback transaction
|
||||
}
|
||||
|
||||
if (sconn->isOpen) {
|
||||
mysql_close(sconn->conn);
|
||||
}
|
||||
|
||||
if (sconn->name) {
|
||||
free(sconn->name);
|
||||
sconn->name = 0;
|
||||
}
|
||||
|
||||
if (sconn->conn) {
|
||||
free(sconn->conn);
|
||||
sconn->conn = 0;
|
||||
}
|
||||
|
||||
if (sconn->prev) {
|
||||
sconn->prev->next = sconn->next;
|
||||
} else {
|
||||
storedConnections = sconn->next;
|
||||
}
|
||||
|
||||
if (sconn->next) {
|
||||
sconn->next->prev = sconn->prev;
|
||||
}
|
||||
|
||||
free(sconn);
|
||||
}
|
||||
void destroyAllConnections()
|
||||
{
|
||||
struct stored_conn_t *ptr = storedConnections;
|
||||
|
||||
while (ptr != 0 && ptr->next != 0) {
|
||||
ptr = ptr->next;
|
||||
destroyStoredConnection(ptr->prev);
|
||||
}
|
||||
|
||||
if (ptr != 0) {
|
||||
destroyStoredConnection(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int connectionCount()
|
||||
{
|
||||
int i = 0;
|
||||
struct stored_conn_t *ptr = storedConnections;
|
||||
|
||||
while (ptr != 0) {
|
||||
i++;
|
||||
ptr = ptr->next;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
int setTimeout(struct stored_conn_t *sconn, unsigned int timeout)
|
||||
{
|
||||
sconn->timeout = timeout;
|
||||
|
||||
if (mysql_optionsv(sconn->conn, MYSQL_OPT_CONNECT_TIMEOUT, (void *)&timeout) != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (mysql_optionsv(sconn->conn, MYSQL_OPT_READ_TIMEOUT, (void *)&timeout) != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (mysql_optionsv(sconn->conn, MYSQL_OPT_WRITE_TIMEOUT, (void *)&timeout) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
void setDefaultTimeout(unsigned int timeout)
|
||||
{
|
||||
defaultTimeout = timeout;
|
||||
}
|
||||
|
||||
|
||||
int connectToHost(struct stored_conn_t *sconn,
|
||||
const char *host, unsigned int port,
|
||||
const char *user, const char *passwd, const char *db)
|
||||
{
|
||||
MYSQL *ret;
|
||||
int freeCon = 0;
|
||||
|
||||
if (sconn == NULL) {
|
||||
sconn = createStoredConnection(NULL);
|
||||
if (sconn == 0) {
|
||||
return -1;
|
||||
}
|
||||
freeCon = 1;
|
||||
}
|
||||
|
||||
if (sconn->isOpen) {
|
||||
fprintf(stderr, "connectToHost: Connection already open\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sconn->needsReset && resetStoredConnection(sconn) != sconn) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = mysql_real_connect(sconn->conn, host, user, passwd, db, port, NULL, 0);
|
||||
// flags: CLIENT_MULTI_STATEMENTS
|
||||
|
||||
if (ret == 0) {
|
||||
fprintf(
|
||||
stderr, "mysql_real_connect: (%d) %s\n", mysql_errno(sconn->conn), mysql_error(sconn->conn)
|
||||
);
|
||||
sconn->needsReset = 1;
|
||||
errno = -mysql_errno(sconn->conn);
|
||||
if (freeCon) {
|
||||
destroyStoredConnection(sconn);
|
||||
}
|
||||
return errno;
|
||||
}
|
||||
|
||||
sconn->isOpen = 1;
|
||||
|
||||
return sconn->conn_id;
|
||||
}
|
||||
int connectToSocket(struct stored_conn_t *sconn,
|
||||
const char *unix_socket,
|
||||
const char *user, const char *passwd, const char *db)
|
||||
{
|
||||
MYSQL *ret;
|
||||
int freeCon = 0;
|
||||
|
||||
if (sconn == NULL) {
|
||||
sconn = createStoredConnection(NULL);
|
||||
if (sconn == 0) {
|
||||
return -1;
|
||||
}
|
||||
freeCon = 1;
|
||||
}
|
||||
|
||||
if (sconn->isOpen) {
|
||||
fprintf(stderr, "connectToSocket: Connection already open\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sconn->needsReset && resetStoredConnection(sconn) != sconn) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = mysql_real_connect(sconn->conn, NULL, user, passwd, db, 0, unix_socket, 0);
|
||||
// flags: CLIENT_MULTI_STATEMENTS
|
||||
|
||||
if (ret == 0) {
|
||||
fprintf(
|
||||
stderr, "mysql_real_connect: (%d) %s\n", mysql_errno(sconn->conn), mysql_error(sconn->conn)
|
||||
);
|
||||
sconn->needsReset = 1;
|
||||
errno = -mysql_errno(sconn->conn);
|
||||
if (freeCon) {
|
||||
destroyStoredConnection(sconn);
|
||||
}
|
||||
return errno;
|
||||
}
|
||||
|
||||
sconn->isOpen = 1;
|
||||
|
||||
return sconn->conn_id;
|
||||
}
|
||||
|
||||
void closeConnection(struct stored_conn_t *sconn)
|
||||
{
|
||||
if (sconn->isTransact) {
|
||||
// rollback transaction
|
||||
}
|
||||
|
||||
if (sconn->isOpen) {
|
||||
mysql_close(sconn->conn);
|
||||
}
|
||||
|
||||
sconn->needsReset = 1;
|
||||
sconn->isOpen = 0;
|
||||
}
|
||||
|
||||
void closeAllConnections()
|
||||
{
|
||||
struct stored_conn_t *c, *ptr = storedConnections;
|
||||
|
||||
while (ptr != 0) {
|
||||
c = ptr;
|
||||
ptr = ptr->next;
|
||||
destroyStoredConnection(c);
|
||||
}
|
||||
}
|
||||
49
src/database.h
Normal file
49
src/database.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#ifndef __DATABASE_H__
|
||||
#define __DATABASE_H__
|
||||
|
||||
#include <mysql.h>
|
||||
|
||||
struct stored_conn_t {
|
||||
int conn_id;
|
||||
char *name;
|
||||
|
||||
MYSQL *conn;
|
||||
|
||||
int isOpen :1;
|
||||
int isTransact :1;
|
||||
int needsReset :1;
|
||||
int __FLAGS;
|
||||
|
||||
unsigned int timeout;
|
||||
|
||||
struct stored_conn_t *prev;
|
||||
struct stored_conn_t *next;
|
||||
};
|
||||
|
||||
|
||||
struct stored_conn_t *connectionById(int conn_id);
|
||||
struct stored_conn_t *connectionByName(const char *name);
|
||||
|
||||
|
||||
struct stored_conn_t *createStoredConnection(const char *name);
|
||||
struct stored_conn_t *resetStoredConnection(struct stored_conn_t *sconn);
|
||||
void destroyStoredConnection(struct stored_conn_t *sconn);
|
||||
void destroyAllConnections();
|
||||
|
||||
int connectionCount();
|
||||
|
||||
int setTimeout(struct stored_conn_t *sconn, unsigned int timeout);
|
||||
void setDefaultTimeout(unsigned int timeout);
|
||||
|
||||
|
||||
int connectToHost(struct stored_conn_t *sconn,
|
||||
const char *host, unsigned int port,
|
||||
const char *user, const char *passwd, const char *db);
|
||||
int connectToSocket(struct stored_conn_t *sconn,
|
||||
const char *unix_socket,
|
||||
const char *user, const char *passwd, const char *db);
|
||||
|
||||
void closeConnection(struct stored_conn_t *sconn);
|
||||
void closeAllConnections();
|
||||
|
||||
#endif // __DATABASE_H__
|
||||
Reference in New Issue
Block a user