MySQL database connection handling

This commit is contained in:
2020-09-08 13:38:28 +01:00
parent 0e37adc86a
commit 8729642387
2 changed files with 377 additions and 0 deletions

328
src/database.c Normal file
View 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
View 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__