Direct database side of things implemented
This commit is contained in:
10
src/database.c
Normal file
10
src/database.c
Normal file
@@ -0,0 +1,10 @@
|
||||
#include <mysql.h>
|
||||
|
||||
#include "database.h"
|
||||
|
||||
void sessionEnd()
|
||||
{
|
||||
destroyAllConnections();
|
||||
mysql_library_end();
|
||||
setDefaultTimeout(-1);
|
||||
}
|
||||
12
src/database.h
Normal file
12
src/database.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef H__DATABASE__
|
||||
#define H__DATABASE__
|
||||
|
||||
#include "db_connection.h"
|
||||
#include "db_timeout.h"
|
||||
#include "db_transaction.h"
|
||||
#include "db_column.h"
|
||||
#include "db_query.h"
|
||||
|
||||
void sessionEnd();
|
||||
|
||||
#endif // H__DATABASE__
|
||||
329
src/db_column.c
Normal file
329
src/db_column.c
Normal file
@@ -0,0 +1,329 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <mysql.h>
|
||||
|
||||
#include "db_column.h"
|
||||
|
||||
|
||||
size_t columnTypeToByteSize(enum e_column_type type)
|
||||
{
|
||||
switch(type) {
|
||||
case TYPE_BOOL:
|
||||
return sizeof(uint8_t);
|
||||
|
||||
case TYPE_INT8:
|
||||
case TYPE_UINT8:
|
||||
return sizeof(uint8_t);
|
||||
|
||||
case TYPE_INT16:
|
||||
case TYPE_UINT16:
|
||||
return sizeof(uint16_t);
|
||||
|
||||
case TYPE_INT32:
|
||||
case TYPE_UINT32:
|
||||
return sizeof(uint32_t);
|
||||
|
||||
case TYPE_INT64:
|
||||
case TYPE_UINT64:
|
||||
return sizeof(uint64_t);
|
||||
|
||||
case TYPE_FLOAT:
|
||||
return sizeof(float);
|
||||
case TYPE_DOUBLE:
|
||||
return sizeof(double);
|
||||
|
||||
case TYPE_STRING:
|
||||
return sizeof(char *);
|
||||
case TYPE_BLOB:
|
||||
return sizeof(char *);
|
||||
|
||||
case TYPE_TIMESTAMP:
|
||||
return sizeof(uint32_t);
|
||||
|
||||
case TYPE_RAW:
|
||||
return sizeof(char *);
|
||||
}
|
||||
return sizeof(char *);
|
||||
}
|
||||
|
||||
enum e_column_type simplifyFieldType(enum enum_field_types sql_type, int is_unsigned)
|
||||
{
|
||||
switch(sql_type) {
|
||||
case MYSQL_TYPE_TINY:
|
||||
return is_unsigned ? TYPE_UINT8 : TYPE_INT8;
|
||||
|
||||
case MYSQL_TYPE_SHORT:
|
||||
return is_unsigned ? TYPE_UINT16 : TYPE_INT16;
|
||||
|
||||
case MYSQL_TYPE_LONG:
|
||||
case MYSQL_TYPE_INT24:
|
||||
return is_unsigned ? TYPE_UINT32 : TYPE_INT32;
|
||||
|
||||
case MYSQL_TYPE_LONGLONG:
|
||||
case MYSQL_TYPE_BIT:
|
||||
return is_unsigned ? TYPE_UINT64 : TYPE_INT64;
|
||||
|
||||
case MYSQL_TYPE_FLOAT:
|
||||
return TYPE_FLOAT;
|
||||
|
||||
case MYSQL_TYPE_DOUBLE:
|
||||
return TYPE_DOUBLE;
|
||||
|
||||
case MYSQL_TYPE_TIMESTAMP:
|
||||
case MYSQL_TYPE_TIMESTAMP2:
|
||||
return TYPE_TIMESTAMP;
|
||||
|
||||
case MYSQL_TYPE_VAR_STRING:
|
||||
case MYSQL_TYPE_STRING:
|
||||
case MYSQL_TYPE_VARCHAR:
|
||||
return TYPE_STRING;
|
||||
|
||||
case MYSQL_TYPE_JSON:
|
||||
case MYSQL_TYPE_TINY_BLOB:
|
||||
case MYSQL_TYPE_MEDIUM_BLOB:
|
||||
case MYSQL_TYPE_LONG_BLOB:
|
||||
case MYSQL_TYPE_BLOB:
|
||||
return TYPE_BLOB;
|
||||
|
||||
case MYSQL_TYPE_YEAR:
|
||||
|
||||
case MYSQL_TYPE_DATE:
|
||||
case MYSQL_TYPE_NEWDATE:
|
||||
|
||||
case MYSQL_TYPE_TIME:
|
||||
case MYSQL_TYPE_TIME2:
|
||||
|
||||
case MYSQL_TYPE_DATETIME:
|
||||
case MYSQL_TYPE_DATETIME2:
|
||||
|
||||
case MYSQL_TYPE_SET:
|
||||
case MYSQL_TYPE_ENUM:
|
||||
case MYSQL_TYPE_NEWDECIMAL:
|
||||
case MYSQL_TYPE_DECIMAL:
|
||||
case MYSQL_TYPE_GEOMETRY:
|
||||
case MYSQL_TYPE_NULL:
|
||||
default:
|
||||
return TYPE_RAW;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct column_data_t *columnFromResult(struct stored_conn_t *sconn, MYSQL_RES *result,
|
||||
uint64_t num_rows)
|
||||
{
|
||||
MYSQL_FIELD *field;
|
||||
struct column_data_t *col;
|
||||
|
||||
field = mysql_fetch_field(result);
|
||||
if (field == NULL) {
|
||||
fprintf(
|
||||
stderr, "[%d]mysql_fetch_field: (%d) %s\n",
|
||||
__LINE__, mysql_errno(SQCONN(sconn)), mysql_error(SQCONN(sconn))
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
col = (struct column_data_t *)malloc(sizeof(struct column_data_t));
|
||||
if (col == NULL) {
|
||||
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
memset(col, 0, sizeof(struct column_data_t));
|
||||
|
||||
col->name_size = field->name_length;
|
||||
col->name = (char*)malloc(field->name_length + 1);
|
||||
if (col->name == NULL) {
|
||||
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
free(col);
|
||||
return 0;
|
||||
}
|
||||
memcpy(col->name, field->name, col->name_size);
|
||||
*(col->name + col->name_size) = '\0';
|
||||
|
||||
col->type = simplifyFieldType(field->type, (field->flags & UNSIGNED_FLAG) > 0);
|
||||
col->type_bytes = columnTypeToByteSize(col->type);
|
||||
|
||||
col->n_values = num_rows;
|
||||
|
||||
col->hasPointers = col->type == TYPE_STRING
|
||||
|| col->type == TYPE_BLOB
|
||||
|| col->type == TYPE_RAW;
|
||||
col->isNullable = (field->flags & NOT_NULL_FLAG) == 0;
|
||||
col->isBlob = (field->flags & BLOB_FLAG) > 0;
|
||||
col->isTimestamp = (field->flags & TIMESTAMP_FLAG) > 0;
|
||||
|
||||
col->data.vptr = malloc(col->type_bytes * num_rows);
|
||||
if (col->data.vptr == NULL) {
|
||||
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
free(col->name);
|
||||
free(col);
|
||||
return 0;
|
||||
}
|
||||
memset(col->data.vptr, 0, col->type_bytes * num_rows);
|
||||
|
||||
col->data_sizes = 0;
|
||||
if (col->hasPointers) {
|
||||
col->data_sizes = (size_t *)malloc(sizeof(size_t) * num_rows);
|
||||
if (col->data_sizes == NULL) {
|
||||
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
free(col->data.vptr);
|
||||
free(col->name);
|
||||
free(col);
|
||||
return 0;
|
||||
}
|
||||
memset(col->data_sizes, 0, sizeof(size_t) * num_rows);
|
||||
}
|
||||
|
||||
col->nulls = 0;
|
||||
if (col->isNullable) {
|
||||
col->nulls = malloc(num_rows / 8 + 1);
|
||||
if (col->nulls == NULL) {
|
||||
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
if (col->data_sizes) {
|
||||
free(col->data_sizes);
|
||||
}
|
||||
free(col->data.vptr);
|
||||
free(col->name);
|
||||
free(col);
|
||||
return 0;
|
||||
}
|
||||
memset(col->nulls, 0, num_rows / 8 + 1);
|
||||
}
|
||||
|
||||
return col;
|
||||
}
|
||||
|
||||
void freeColumn(struct column_data_t *col)
|
||||
{
|
||||
if (col->hasPointers) {
|
||||
for (unsigned int r = 0; r < col->n_values; r++) {
|
||||
if (!columnRowIsNull(col, r)) {
|
||||
free(*(col->data.ptr_str + r));
|
||||
*(col->data.ptr_str + r) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
free(col->data_sizes);
|
||||
col->data_sizes = 0;
|
||||
}
|
||||
|
||||
if (col->data.vptr) {
|
||||
free(col->data.vptr);
|
||||
col->data.vptr = 0;
|
||||
}
|
||||
|
||||
if (col->isNullable) {
|
||||
free(col->nulls);
|
||||
col->nulls = 0;
|
||||
}
|
||||
|
||||
free(col->name);
|
||||
col->name = 0;
|
||||
|
||||
free(col);
|
||||
}
|
||||
void freeColumns(struct column_data_t **col_data, size_t n_cols)
|
||||
{
|
||||
for (size_t c = 0; c < n_cols; c++) {
|
||||
freeColumn(*(col_data + c));
|
||||
}
|
||||
free(col_data);
|
||||
}
|
||||
|
||||
|
||||
int setColumnValue(struct column_data_t *col, uint64_t row, const char *value, size_t value_size)
|
||||
{
|
||||
if (value == NULL) {
|
||||
columnRowSetNull(col, row);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch(col->type) {
|
||||
case TYPE_BOOL:
|
||||
{
|
||||
*(col->data.ptr_uint8 + row) = value[0] == '1';
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_INT8:
|
||||
{
|
||||
*(col->data.ptr_int8 + row) = (int8_t)strtol(value, NULL, 10);
|
||||
break;
|
||||
}
|
||||
case TYPE_UINT8:
|
||||
{
|
||||
*(col->data.ptr_uint8 + row) = (uint8_t)strtoul(value, NULL, 10);
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_INT16:
|
||||
{
|
||||
*(col->data.ptr_int16 + row) = (int16_t)strtol(value, NULL, 10);
|
||||
break;
|
||||
}
|
||||
case TYPE_UINT16:
|
||||
{
|
||||
*(col->data.ptr_uint16 + row) = (uint16_t)strtoul(value, NULL, 10);
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_INT32:
|
||||
{
|
||||
*(col->data.ptr_int32 + row) = (int32_t)strtol(value, NULL, 10);
|
||||
break;
|
||||
}
|
||||
case TYPE_UINT32:
|
||||
{
|
||||
*(col->data.ptr_uint32 + row) = (uint32_t)strtoul(value, NULL, 10);
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_INT64:
|
||||
{
|
||||
*(col->data.ptr_int64 + row) = strtoll(value, NULL, 10);
|
||||
break;
|
||||
}
|
||||
case TYPE_UINT64:
|
||||
{
|
||||
*(col->data.ptr_uint64 + row) = strtoull(value, NULL, 10);
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_FLOAT:
|
||||
{
|
||||
*(col->data.ptr_float + row) = strtof(value, NULL);
|
||||
break;
|
||||
}
|
||||
case TYPE_DOUBLE:
|
||||
{
|
||||
*(col->data.ptr_double + row) = strtod(value, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_TIMESTAMP:
|
||||
{
|
||||
*(col->data.ptr_uint32 + row) = (uint32_t)strtoul(value, NULL, 10);
|
||||
break;
|
||||
}
|
||||
case TYPE_STRING:
|
||||
case TYPE_BLOB:
|
||||
case TYPE_RAW:
|
||||
{
|
||||
*(col->data.ptr_str + row) = (char *)malloc(value_size + 1);
|
||||
if (*(col->data.ptr_str + row) == 0) {
|
||||
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
memcpy(*(col->data.ptr_str + row), value, value_size);
|
||||
*(*(col->data.ptr_str + row) + value_size) = 0;
|
||||
*(col->data_sizes + row) = value_size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
93
src/db_column.h
Normal file
93
src/db_column.h
Normal file
@@ -0,0 +1,93 @@
|
||||
#ifndef H__DB_COLUMN__
|
||||
#define H__DB_COLUMN__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <mysql.h>
|
||||
#include "db_connection.h"
|
||||
|
||||
enum e_column_type {
|
||||
TYPE_BOOL,
|
||||
TYPE_INT8,
|
||||
TYPE_UINT8,
|
||||
TYPE_INT16,
|
||||
TYPE_UINT16,
|
||||
TYPE_INT32,
|
||||
TYPE_UINT32,
|
||||
TYPE_INT64,
|
||||
TYPE_UINT64,
|
||||
TYPE_FLOAT,
|
||||
TYPE_DOUBLE,
|
||||
TYPE_STRING,
|
||||
TYPE_BLOB,
|
||||
TYPE_TIMESTAMP,
|
||||
TYPE_RAW
|
||||
};
|
||||
|
||||
struct column_data_t {
|
||||
char *name;
|
||||
size_t name_size;
|
||||
|
||||
enum e_column_type type;
|
||||
size_t type_bytes;
|
||||
|
||||
size_t n_values;
|
||||
|
||||
uint8_t hasPointers :1;
|
||||
uint8_t isNullable :1;
|
||||
uint8_t isBlob :1;
|
||||
uint8_t isTimestamp :1;
|
||||
|
||||
union u_data {
|
||||
void *vptr;
|
||||
|
||||
int8_t *ptr_int8;
|
||||
uint8_t *ptr_uint8;
|
||||
|
||||
int16_t *ptr_int16;
|
||||
uint16_t *ptr_uint16;
|
||||
|
||||
int32_t *ptr_int32;
|
||||
uint32_t *ptr_uint32;
|
||||
|
||||
int64_t *ptr_int64;
|
||||
uint64_t *ptr_uint64;
|
||||
|
||||
float *ptr_float;
|
||||
double *ptr_double;
|
||||
|
||||
char **ptr_str;
|
||||
} data;
|
||||
size_t *data_sizes;
|
||||
|
||||
uint8_t *nulls;
|
||||
};
|
||||
|
||||
|
||||
// Null column value handling - maybe convert these to macros?
|
||||
static inline int columnRowIsNull(struct column_data_t *col, uint64_t row)
|
||||
{
|
||||
return col->isNullable && (*(col->nulls + (row / 8)) & (1 << (row % 8))) > 0;
|
||||
}
|
||||
static inline void columnRowSetNull(struct column_data_t *col, uint64_t row)
|
||||
{
|
||||
if (col->isNullable) {
|
||||
*(col->nulls + (row / 8)) |= (1 << (row % 8));
|
||||
}
|
||||
}
|
||||
static inline void columnRowClearNull(struct column_data_t *col, uint64_t row)
|
||||
{
|
||||
if (col->isNullable) {
|
||||
*(col->nulls + (row / 8)) &= ~(1 << (row % 8));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct column_data_t *columnFromResult(struct stored_conn_t *sconn, MYSQL_RES *result,
|
||||
uint64_t num_rows);
|
||||
void freeColumn(struct column_data_t *col);
|
||||
void freeColumns(struct column_data_t **col_data, size_t n_cols);
|
||||
|
||||
|
||||
int setColumnValue(struct column_data_t *col, uint64_t row, const char *value, size_t value_size);
|
||||
|
||||
#endif // H__DB_COLUMN__
|
||||
@@ -4,14 +4,13 @@
|
||||
#include <errno.h>
|
||||
#include <mysql.h>
|
||||
|
||||
#include "database.h"
|
||||
|
||||
#define SQCONN(s) (MYSQL *)s->conn
|
||||
#include "db_connection.h"
|
||||
#include "db_timeout.h"
|
||||
#include "db_transaction.h"
|
||||
|
||||
|
||||
struct stored_conn_t *storedConnections = 0;
|
||||
int nextConnId = 1;
|
||||
int defaultTimeout = -1;
|
||||
static struct stored_conn_t *storedConnections = 0;
|
||||
static int nextConnId = 1;
|
||||
|
||||
|
||||
struct stored_conn_t *connectionById(int conn_id)
|
||||
@@ -31,8 +30,11 @@ struct stored_conn_t *connectionByName(const char *name)
|
||||
{
|
||||
struct stored_conn_t *ptr = storedConnections;
|
||||
|
||||
size_t name_len = strlen(name);
|
||||
while (ptr != 0) {
|
||||
if (ptr->name != 0 && strcmp(ptr->name, name) == 0) {
|
||||
if (ptr->name != 0
|
||||
&& strlen(ptr->name) == name_len
|
||||
&& strncmp(name, ptr->name, name_len) == 0) {
|
||||
return ptr;
|
||||
}
|
||||
ptr = ptr->next;
|
||||
@@ -41,6 +43,18 @@ struct stored_conn_t *connectionByName(const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int connectionCount()
|
||||
{
|
||||
int i = 0;
|
||||
struct stored_conn_t *ptr = storedConnections;
|
||||
|
||||
while (ptr != 0) {
|
||||
i++;
|
||||
ptr = ptr->next;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
struct stored_conn_t *createStoredConnection(const char *name)
|
||||
{
|
||||
@@ -48,14 +62,14 @@ struct stored_conn_t *createStoredConnection(const char *name)
|
||||
|
||||
if (name && strlen(name) > 0) {
|
||||
if (connectionByName(name) != 0) {
|
||||
fprintf(stderr, "createStoredConnection: Named connection already exists\n");
|
||||
fprintf(stderr, "[%d]createStoredConnection: Named connection already exists\n", __LINE__);
|
||||
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));
|
||||
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -63,36 +77,38 @@ struct stored_conn_t *createStoredConnection(const char *name)
|
||||
sconn->name = 0;
|
||||
sconn->conn = (MYSQL *)malloc(sizeof(MYSQL));
|
||||
sconn->isOpen = 0;
|
||||
sconn->isTransact = 0;
|
||||
sconn->inTransaction = 0;
|
||||
sconn->needsReset = 0;
|
||||
sconn->timeout = -1;
|
||||
sconn->timeout = (unsigned int)-1;
|
||||
sconn->prev = 0;
|
||||
sconn->next = 0;
|
||||
|
||||
if (sconn->conn == 0) {
|
||||
fprintf(stderr, "malloc: (%d) %s\n", errno, strerror(errno));
|
||||
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
destroyStoredConnection(sconn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (name && strlen(name) > 0) {
|
||||
sconn->name = (char *)malloc(sizeof(char) * strlen(name));
|
||||
sconn->name_len = sizeof(char) * strlen(name);
|
||||
sconn->name = (char *)malloc(sconn->name_len + 1);
|
||||
if (sconn->name == 0) {
|
||||
fprintf(stderr, "malloc: (%d) %s\n", errno, strerror(errno));
|
||||
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
destroyStoredConnection(sconn);
|
||||
return 0;
|
||||
}
|
||||
memcpy(sconn->name, name, strlen(name) * sizeof(char));
|
||||
memcpy(sconn->name, name, sconn->name_len);
|
||||
sconn->name[sconn->name_len] = '\0';
|
||||
}
|
||||
|
||||
if (mysql_init(SQCONN(sconn)) == 0) {
|
||||
fprintf(stderr, "mysql_init: unknown error\n");
|
||||
fprintf(stderr, "[%d]mysql_init: unknown error\n", __LINE__);
|
||||
destroyStoredConnection(sconn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (defaultTimeout >= 0) {
|
||||
setTimeout(sconn, defaultTimeout);
|
||||
if (getDefaultTimeout() != (unsigned int)-1) {
|
||||
setTimeout(sconn, getDefaultTimeout());
|
||||
}
|
||||
|
||||
if (storedConnections == 0) {
|
||||
@@ -114,19 +130,20 @@ struct stored_conn_t *resetStoredConnection(struct stored_conn_t *sconn)
|
||||
|
||||
new_conn = (MYSQL *)malloc(sizeof(MYSQL));
|
||||
if (new_conn == 0) {
|
||||
fprintf(stderr, "malloc: (%d) %s\n", errno, strerror(errno));
|
||||
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mysql_init(new_conn) == 0) {
|
||||
fprintf(stderr, "mysql_init: unknown error\n");
|
||||
fprintf(stderr, "[%d]mysql_init: unknown error\n", __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
mysql_close(sconn->conn);
|
||||
free(sconn->conn);
|
||||
sconn->conn = new_conn;
|
||||
|
||||
if (sconn->timeout >= 0) {
|
||||
if (sconn->timeout != (unsigned int)-1) {
|
||||
setTimeout(sconn, sconn->timeout);
|
||||
}
|
||||
|
||||
@@ -136,12 +153,8 @@ struct stored_conn_t *resetStoredConnection(struct stored_conn_t *sconn)
|
||||
}
|
||||
void destroyStoredConnection(struct stored_conn_t *sconn)
|
||||
{
|
||||
if (sconn->isTransact) {
|
||||
// rollback transaction
|
||||
}
|
||||
|
||||
if (sconn->isOpen) {
|
||||
mysql_close(SQCONN(sconn));
|
||||
closeConnection(sconn);
|
||||
}
|
||||
|
||||
if (sconn->name) {
|
||||
@@ -181,42 +194,6 @@ void destroyAllConnections()
|
||||
}
|
||||
|
||||
|
||||
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(SQCONN(sconn), MYSQL_OPT_CONNECT_TIMEOUT, (void *)&timeout) != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (mysql_optionsv(SQCONN(sconn), MYSQL_OPT_READ_TIMEOUT, (void *)&timeout) != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (mysql_optionsv(SQCONN(sconn), 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)
|
||||
@@ -233,7 +210,7 @@ int connectToHost(struct stored_conn_t *sconn,
|
||||
}
|
||||
|
||||
if (sconn->isOpen) {
|
||||
fprintf(stderr, "connectToHost: Connection already open\n");
|
||||
fprintf(stderr, "[%d]connectToHost: Connection already open\n", __LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -246,10 +223,11 @@ int connectToHost(struct stored_conn_t *sconn,
|
||||
|
||||
if (ret == 0) {
|
||||
fprintf(
|
||||
stderr, "mysql_real_connect: (%d) %s\n", mysql_errno(SQCONN(sconn)), mysql_error(SQCONN(sconn))
|
||||
stderr, "[%d]mysql_real_connect: (%d) %s\n",
|
||||
__LINE__, mysql_errno(SQCONN(sconn)), mysql_error(SQCONN(sconn))
|
||||
);
|
||||
sconn->needsReset = 1;
|
||||
errno = -mysql_errno(SQCONN(sconn));
|
||||
errno = -(int)mysql_errno(SQCONN(sconn));
|
||||
if (freeCon) {
|
||||
destroyStoredConnection(sconn);
|
||||
}
|
||||
@@ -276,7 +254,7 @@ int connectToSocket(struct stored_conn_t *sconn,
|
||||
}
|
||||
|
||||
if (sconn->isOpen) {
|
||||
fprintf(stderr, "connectToSocket: Connection already open\n");
|
||||
fprintf(stderr, "[%d]connectToSocket: Connection already open\n", __LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -289,10 +267,11 @@ int connectToSocket(struct stored_conn_t *sconn,
|
||||
|
||||
if (ret == 0) {
|
||||
fprintf(
|
||||
stderr, "mysql_real_connect: (%d) %s\n", mysql_errno(SQCONN(sconn)), mysql_error(SQCONN(sconn))
|
||||
stderr, "[%d]mysql_real_connect: (%d) %s\n",
|
||||
__LINE__, mysql_errno(SQCONN(sconn)), mysql_error(SQCONN(sconn))
|
||||
);
|
||||
sconn->needsReset = 1;
|
||||
errno = -mysql_errno(SQCONN(sconn));
|
||||
errno = -(int)mysql_errno(SQCONN(sconn));
|
||||
if (freeCon) {
|
||||
destroyStoredConnection(sconn);
|
||||
}
|
||||
@@ -306,8 +285,8 @@ int connectToSocket(struct stored_conn_t *sconn,
|
||||
|
||||
void closeConnection(struct stored_conn_t *sconn)
|
||||
{
|
||||
if (sconn->isTransact) {
|
||||
// rollback transaction
|
||||
if (sconn->inTransaction) {
|
||||
transactionRollback(sconn);
|
||||
}
|
||||
|
||||
if (sconn->isOpen) {
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
#ifndef __CONNECTION_H__
|
||||
#define __CONNECTION_H__
|
||||
#ifndef H__DB_CONNECTION__
|
||||
#define H__DB_CONNECTION__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define SQCONN(s) (MYSQL *)s->conn
|
||||
|
||||
|
||||
struct stored_conn_t {
|
||||
int conn_id;
|
||||
char *name;
|
||||
size_t name_len;
|
||||
|
||||
void *conn;
|
||||
|
||||
int isOpen :1;
|
||||
int isTransact :1;
|
||||
int needsReset :1;
|
||||
int __FLAGS;
|
||||
uint8_t isOpen :1;
|
||||
uint8_t inTransaction :1;
|
||||
uint8_t needsReset :1;
|
||||
|
||||
unsigned int timeout;
|
||||
|
||||
@@ -19,30 +23,25 @@ struct stored_conn_t {
|
||||
struct stored_conn_t *next;
|
||||
};
|
||||
|
||||
|
||||
// Connections are stored in a linked list, these functions provide access
|
||||
struct stored_conn_t *connectionById(int conn_id);
|
||||
struct stored_conn_t *connectionByName(const char *name);
|
||||
|
||||
int connectionCount();
|
||||
|
||||
// Connection management
|
||||
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 // __CONNECTION_H__
|
||||
#endif // H__DB_CONNECTION__
|
||||
|
||||
300
src/db_query.c
Normal file
300
src/db_query.c
Normal file
@@ -0,0 +1,300 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <mysql.h>
|
||||
#include "db_connection.h"
|
||||
#include "db_column.h"
|
||||
|
||||
|
||||
uint64_t simpleQuery(struct stored_conn_t *sconn, const char *qry, size_t qry_len)
|
||||
{
|
||||
if (mysql_real_query(SQCONN(sconn), qry, qry_len) != 0) {
|
||||
fprintf(
|
||||
stderr, "[%d]mysql_real_query: (%d) %s\n",
|
||||
__LINE__, mysql_errno(SQCONN(sconn)), mysql_error(SQCONN(sconn))
|
||||
);
|
||||
return (uint64_t)-1;
|
||||
}
|
||||
|
||||
return mysql_insert_id(SQCONN(sconn));
|
||||
}
|
||||
|
||||
uint64_t scalarQuery(struct stored_conn_t *sconn, const char *qry, size_t qry_len,
|
||||
char **res, size_t *res_len)
|
||||
{
|
||||
my_ulonglong insertId;
|
||||
my_ulonglong n_row, n_col;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
unsigned long *lens;
|
||||
|
||||
insertId = simpleQuery(sconn, qry, qry_len);
|
||||
if (insertId == (uint64_t)-1) {
|
||||
return insertId;
|
||||
}
|
||||
|
||||
if (mysql_field_count(SQCONN(sconn)) == 0) {
|
||||
// insert/update query
|
||||
// TODO: res = makeInt64() // lastInsertId
|
||||
return insertId;
|
||||
}
|
||||
|
||||
|
||||
result = mysql_store_result(SQCONN(sconn));
|
||||
if (result == NULL) {
|
||||
fprintf(
|
||||
stderr, "[%d]mysql_store_result: (%d) %s\n",
|
||||
__LINE__, mysql_errno(SQCONN(sconn)), mysql_error(SQCONN(sconn))
|
||||
);
|
||||
return (uint64_t)-1;
|
||||
}
|
||||
|
||||
|
||||
n_row = mysql_num_rows(result);
|
||||
if (n_row == 0) {
|
||||
fprintf(stderr, "[%d]scalarQuery: Not enough rows in result\n", __LINE__);
|
||||
return (uint64_t)-1;
|
||||
}
|
||||
if (n_row > 1) {
|
||||
fprintf(stderr, "[%d]scalarQuery: WARN: Too many rows in result, only returning first value\n", __LINE__);
|
||||
}
|
||||
|
||||
n_col = mysql_num_fields(result);
|
||||
if (n_col > 1) {
|
||||
fprintf(stderr, "[%d]scalarQuery: WARN: Too many columns in result, only returning first value\n", __LINE__);
|
||||
}
|
||||
|
||||
row = mysql_fetch_row(result);
|
||||
lens = mysql_fetch_lengths(result);
|
||||
if (row == NULL) {
|
||||
fprintf(stderr, "[%d]scalarQuery: Not enough rows in result\n", __LINE__);
|
||||
return (uint64_t)-1;
|
||||
}
|
||||
|
||||
if (*row == NULL) {
|
||||
(*res_len) = 0;
|
||||
(*res) = 0;
|
||||
} else {
|
||||
(*res_len) = *(lens + 0);
|
||||
(*res) = malloc(*(lens + 0) * sizeof(char) + 1);
|
||||
if ((*res) == 0) {
|
||||
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
return (uint64_t)-1;
|
||||
}
|
||||
memcpy((*res), *(row + 0), *(lens + 0));
|
||||
*((*res) + *(lens + 0)) = '\0';
|
||||
}
|
||||
|
||||
mysql_free_result(result);
|
||||
|
||||
return insertId;
|
||||
}
|
||||
|
||||
uint64_t tableQuery(struct stored_conn_t *sconn, const char *qry, size_t qry_len, int scalar_result,
|
||||
struct column_data_t ***col_data_ptr, size_t *n_cols)
|
||||
{
|
||||
my_ulonglong insertId;
|
||||
my_ulonglong n_rows;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
unsigned long *lens;
|
||||
int failed = 0;
|
||||
struct column_data_t **col_data;
|
||||
|
||||
insertId = simpleQuery(sconn, qry, qry_len);
|
||||
if (insertId == (uint64_t)-1) {
|
||||
return insertId;
|
||||
}
|
||||
|
||||
*n_cols = mysql_field_count(SQCONN(sconn));
|
||||
if (scalar_result && (*n_cols) > 1) {
|
||||
// TODO: throw warning due to column sizing issue
|
||||
(*n_cols) = 1;
|
||||
}
|
||||
if (*n_cols == 0) {
|
||||
// insert/update query
|
||||
// TODO: res = makeInt64() // lastInsertId
|
||||
return insertId;
|
||||
}
|
||||
|
||||
result = mysql_store_result(SQCONN(sconn));
|
||||
if (result == NULL) {
|
||||
fprintf(
|
||||
stderr, "[%d]mysql_real_query: (%d) %s\n",
|
||||
__LINE__, mysql_errno(SQCONN(sconn)), mysql_error(SQCONN(sconn))
|
||||
);
|
||||
return (uint64_t)-1;
|
||||
}
|
||||
|
||||
|
||||
col_data = (struct column_data_t **)malloc(sizeof(struct column_data_t *) * *n_cols);
|
||||
if (result == NULL) {
|
||||
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
mysql_free_result(result);
|
||||
return insertId;
|
||||
}
|
||||
|
||||
n_rows = mysql_num_rows(result);
|
||||
if (scalar_result && n_rows > 1) {
|
||||
// TODO: throw warning due to column sizing issue
|
||||
n_rows = 1;
|
||||
}
|
||||
|
||||
|
||||
for (unsigned int i = 0; i < *n_cols; i++) {
|
||||
*(col_data + i) = columnFromResult(sconn, result, n_rows);
|
||||
|
||||
if (*(col_data + i) == 0) {
|
||||
failed++;
|
||||
}
|
||||
}
|
||||
if (failed > 0) {
|
||||
for (unsigned int i = 0; i < *n_cols; i++) {
|
||||
if (*(col_data + i) != 0) {
|
||||
freeColumn(*(col_data + i));
|
||||
}
|
||||
}
|
||||
free(col_data);
|
||||
mysql_free_result(result);
|
||||
return insertId;
|
||||
}
|
||||
|
||||
for (my_ulonglong r = 0; r < n_rows; r++) {
|
||||
row = mysql_fetch_row(result);
|
||||
lens = mysql_fetch_lengths(result);
|
||||
|
||||
if (row == NULL) {
|
||||
fprintf(
|
||||
stderr, "[%d]mysql_fetch_row: (%d) %s\n",
|
||||
__LINE__, mysql_errno(SQCONN(sconn)), mysql_error(SQCONN(sconn))
|
||||
);
|
||||
return insertId;
|
||||
}
|
||||
|
||||
for (unsigned int c = 0; c < *n_cols; c++) {
|
||||
struct column_data_t *col = (*(col_data + c));
|
||||
|
||||
if (setColumnValue(col, r, *(row + c), *(lens + c)) < 0) {
|
||||
failed++;
|
||||
}
|
||||
}
|
||||
|
||||
if (failed > 0) {
|
||||
r = n_rows;
|
||||
}
|
||||
}
|
||||
|
||||
if (failed > 0) {
|
||||
for (size_t c = 0; c < *n_cols; c++) {
|
||||
if (*(col_data + c) != 0) {
|
||||
freeColumn(*(col_data + c));
|
||||
}
|
||||
}
|
||||
free(col_data);
|
||||
mysql_free_result(result);
|
||||
return insertId;
|
||||
}
|
||||
|
||||
mysql_free_result(result);
|
||||
|
||||
*col_data_ptr = col_data;
|
||||
|
||||
return n_rows;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int scalarInt(struct stored_conn_t *sconn, const char *qry, size_t qry_len, int default_value)
|
||||
{
|
||||
struct column_data_t **col_data;
|
||||
size_t n_cols;
|
||||
|
||||
if (tableQuery(sconn, qry, qry_len, 1, &col_data, &n_cols) != (uint64_t)-1) {
|
||||
if (!((*col_data)->isNullable && columnRowIsNull(*col_data, 0))) {
|
||||
default_value = *((*col_data)->data.ptr_int32);
|
||||
}
|
||||
freeColumn(*col_data);
|
||||
free(col_data);
|
||||
}
|
||||
|
||||
return default_value;
|
||||
}
|
||||
|
||||
unsigned int scalarUInt(struct stored_conn_t *sconn, const char *qry, size_t qry_len,
|
||||
unsigned int default_value)
|
||||
{
|
||||
struct column_data_t **col_data;
|
||||
size_t n_cols;
|
||||
|
||||
if (tableQuery(sconn, qry, qry_len, 1, &col_data, &n_cols) != (uint64_t)-1) {
|
||||
if (!((*col_data)->isNullable && columnRowIsNull(*col_data, 0))) {
|
||||
default_value = *((*col_data)->data.ptr_uint32);
|
||||
}
|
||||
freeColumn(*col_data);
|
||||
free(col_data);
|
||||
}
|
||||
|
||||
return default_value;
|
||||
}
|
||||
|
||||
double scalarReal(struct stored_conn_t *sconn, const char *qry, size_t qry_len,
|
||||
double default_value)
|
||||
{
|
||||
struct column_data_t **col_data;
|
||||
size_t n_cols;
|
||||
|
||||
if (tableQuery(sconn, qry, qry_len, 1, &col_data, &n_cols) != (uint64_t)-1) {
|
||||
if (!((*col_data)->isNullable && columnRowIsNull(*col_data, 0))) {
|
||||
default_value = *((*col_data)->data.ptr_double);
|
||||
}
|
||||
freeColumn(*col_data);
|
||||
free(col_data);
|
||||
}
|
||||
|
||||
return default_value;
|
||||
}
|
||||
|
||||
char scalarChar(struct stored_conn_t *sconn, const char *qry, size_t qry_len, char default_value)
|
||||
{
|
||||
struct column_data_t **col_data;
|
||||
size_t n_cols;
|
||||
|
||||
if (tableQuery(sconn, qry, qry_len, 1, &col_data, &n_cols) != (uint64_t)-1) {
|
||||
if (!((*col_data)->isNullable && columnRowIsNull(*col_data, 0))) {
|
||||
default_value = *((*col_data)->data.ptr_str)[0];
|
||||
}
|
||||
freeColumn(*col_data);
|
||||
free(col_data);
|
||||
}
|
||||
|
||||
return default_value;
|
||||
}
|
||||
|
||||
char *scalarString(struct stored_conn_t *sconn, const char *qry, size_t qry_len,
|
||||
char *default_value)
|
||||
{
|
||||
struct column_data_t **col_data;
|
||||
size_t n_cols;
|
||||
char *retval;
|
||||
|
||||
if (tableQuery(sconn, qry, qry_len, 1, &col_data, &n_cols) == (uint64_t)-1) {
|
||||
return default_value;
|
||||
}
|
||||
|
||||
if ((*col_data)->isNullable && columnRowIsNull(*col_data, 0)) {
|
||||
retval = NULL;
|
||||
} else {
|
||||
retval = (char *)malloc((*col_data)->data_sizes[0] + 1);
|
||||
if (retval == 0) {
|
||||
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
return default_value;
|
||||
}
|
||||
memcpy(retval, *((*col_data)->data.ptr_str), (*col_data)->data_sizes[0]);
|
||||
retval[(*col_data)->data_sizes[0]] = '\0';
|
||||
}
|
||||
freeColumn(*col_data);
|
||||
free(col_data);
|
||||
|
||||
return retval;
|
||||
}
|
||||
24
src/db_query.h
Normal file
24
src/db_query.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef H__DB_QUERY__
|
||||
#define H__DB_QUERY__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "db_connection.h"
|
||||
|
||||
// Generic query methods
|
||||
uint64_t simpleQuery(struct stored_conn_t *sconn, const char *qry, size_t qry_len);
|
||||
uint64_t scalarQuery(struct stored_conn_t *sconn, const char *qry, size_t qry_len,
|
||||
char **res, size_t *res_len);
|
||||
uint64_t tableQuery(struct stored_conn_t *sconn, const char *qry, size_t qry_len, int scalar_result,
|
||||
struct column_data_t ***col_data, size_t *n_cols);
|
||||
|
||||
// Scalar helpers
|
||||
int scalarInt(struct stored_conn_t *sconn, const char *qry, size_t qry_len, int default_value);
|
||||
unsigned int scalarUInt(struct stored_conn_t *sconn, const char *qry, size_t qry_len,
|
||||
unsigned int default_value);
|
||||
double scalarReal(struct stored_conn_t *sconn, const char *qry, size_t qry_len,
|
||||
double default_value);
|
||||
char scalarChar(struct stored_conn_t *sconn, const char *qry, size_t qry_len, char default_value);
|
||||
char *scalarString(struct stored_conn_t *sconn, const char *qry, size_t qry_len,
|
||||
char *default_value);
|
||||
|
||||
#endif // H__DB_QUERY__
|
||||
33
src/db_timeout.c
Normal file
33
src/db_timeout.c
Normal file
@@ -0,0 +1,33 @@
|
||||
#include <mysql.h>
|
||||
|
||||
#include "db_timeout.h"
|
||||
|
||||
|
||||
int defaultTimeout = -1;
|
||||
|
||||
|
||||
void setDefaultTimeout(unsigned int timeout)
|
||||
{
|
||||
defaultTimeout = timeout;
|
||||
}
|
||||
unsigned int getDefaultTimeout()
|
||||
{
|
||||
return defaultTimeout;
|
||||
}
|
||||
|
||||
int setTimeout(struct stored_conn_t *sconn, unsigned int timeout)
|
||||
{
|
||||
sconn->timeout = timeout;
|
||||
|
||||
if (mysql_optionsv(SQCONN(sconn), MYSQL_OPT_CONNECT_TIMEOUT, (void *)&timeout) != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (mysql_optionsv(SQCONN(sconn), MYSQL_OPT_READ_TIMEOUT, (void *)&timeout) != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (mysql_optionsv(SQCONN(sconn), MYSQL_OPT_WRITE_TIMEOUT, (void *)&timeout) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
12
src/db_timeout.h
Normal file
12
src/db_timeout.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef __DB_TIMEOUT_H__
|
||||
#define __DB_TIMEOUT_H__
|
||||
|
||||
#include "db_connection.h"
|
||||
|
||||
// Timeouts can either be set globally or on a per-connection basis
|
||||
void setDefaultTimeout(unsigned int timeout);
|
||||
unsigned int getDefaultTimeout();
|
||||
|
||||
int setTimeout(struct stored_conn_t *sconn, unsigned int timeout);
|
||||
|
||||
#endif // __DB_TIMEOUT_H__
|
||||
55
src/db_transaction.c
Normal file
55
src/db_transaction.c
Normal file
@@ -0,0 +1,55 @@
|
||||
#include <stdio.h>
|
||||
#include <mysql.h>
|
||||
|
||||
#include "db_transaction.h"
|
||||
|
||||
int transactionStart(struct stored_conn_t *sconn)
|
||||
{
|
||||
if (mysql_autocommit(SQCONN(sconn), 1) != 0) {
|
||||
fprintf(
|
||||
stderr, "[%d]mysql_autocommit: (%d) %s\n",
|
||||
__LINE__, mysql_errno(SQCONN(sconn)), mysql_error(SQCONN(sconn))
|
||||
);
|
||||
return -1;
|
||||
}
|
||||
sconn->inTransaction = 1;
|
||||
return 0;
|
||||
}
|
||||
int transactionCommit(struct stored_conn_t *sconn)
|
||||
{
|
||||
if (mysql_commit(SQCONN(sconn)) != 0) {
|
||||
fprintf(
|
||||
stderr, "[%d]mysql_commit: (%d) %s\n",
|
||||
__LINE__, mysql_errno(SQCONN(sconn)), mysql_error(SQCONN(sconn))
|
||||
);
|
||||
return -1;
|
||||
}
|
||||
if (mysql_autocommit(SQCONN(sconn), 0) != 0) {
|
||||
fprintf(
|
||||
stderr, "[%d]mysql_autocommit: (%d) %s\n",
|
||||
__LINE__, mysql_errno(SQCONN(sconn)), mysql_error(SQCONN(sconn))
|
||||
);
|
||||
return -1;
|
||||
}
|
||||
sconn->inTransaction = 0;
|
||||
return 0;
|
||||
}
|
||||
int transactionRollback(struct stored_conn_t *sconn)
|
||||
{
|
||||
if (mysql_rollback(SQCONN(sconn)) != 0) {
|
||||
fprintf(
|
||||
stderr, "[%d]mysql_rollback: (%d) %s\n",
|
||||
__LINE__, mysql_errno(SQCONN(sconn)), mysql_error(SQCONN(sconn))
|
||||
);
|
||||
return -1;
|
||||
}
|
||||
if (mysql_autocommit(SQCONN(sconn), 0) != 0) {
|
||||
fprintf(
|
||||
stderr, "[%d]mysql_autocommit: (%d) %s\n",
|
||||
__LINE__, mysql_errno(SQCONN(sconn)), mysql_error(SQCONN(sconn))
|
||||
);
|
||||
return -1;
|
||||
}
|
||||
sconn->inTransaction = 0;
|
||||
return 0;
|
||||
}
|
||||
11
src/db_transaction.h
Normal file
11
src/db_transaction.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef H__DB_TRANSACTION__
|
||||
#define H__DB_TRANSACTION__
|
||||
|
||||
#include "db_connection.h"
|
||||
|
||||
// Transaction management
|
||||
int transactionStart(struct stored_conn_t *sconn);
|
||||
int transactionCommit(struct stored_conn_t *sconn);
|
||||
int transactionRollback(struct stored_conn_t *sconn);
|
||||
|
||||
#endif // H__DB_TRANSACTION__
|
||||
Reference in New Issue
Block a user