Created a WHERE query builder and implemented a TYPE to char * method for database values
This commit is contained in:
@@ -6,6 +6,8 @@
|
||||
#include "db_transaction.h"
|
||||
#include "db_column.h"
|
||||
#include "db_query.h"
|
||||
#include "db_value.h"
|
||||
#include "db_where-builder.h"
|
||||
|
||||
void sessionEnd(void);
|
||||
|
||||
|
||||
188
src/db_value.c
Normal file
188
src/db_value.c
Normal file
@@ -0,0 +1,188 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <mysql.h>
|
||||
|
||||
#include "strext.h"
|
||||
#include "db_value.h"
|
||||
|
||||
char *db_value(char **str, size_t *len, e_column_type type, uint32_t n_args, ...)
|
||||
{
|
||||
va_list args;
|
||||
char *ret;
|
||||
|
||||
va_start(args, n_args);
|
||||
ret = db_value_va(str, len, type, n_args, args);
|
||||
va_end(args);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *db_value_va(char **str, size_t *len, e_column_type type, uint32_t n_args, va_list args)
|
||||
{
|
||||
char buf[32], *tmp_str = 0, *esc_str = 0;
|
||||
size_t tmp_len = 0, esc_len = 0;
|
||||
MYSQL *sql;
|
||||
|
||||
if (n_args == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(buf, 0, 32);
|
||||
|
||||
switch(type) {
|
||||
case TYPE_BOOL:
|
||||
{
|
||||
sprintf(buf, "%s", va_arg(args, int) == 0 ? "FALSE" : "TRUE");
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_INT8:
|
||||
{
|
||||
vsprintf(buf, "%"PRIi8, args);
|
||||
break;
|
||||
}
|
||||
case TYPE_UINT8:
|
||||
{
|
||||
vsprintf(buf, "%"PRIu8, args);
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_INT16:
|
||||
{
|
||||
vsprintf(buf, "%"PRIi16, args);
|
||||
break;
|
||||
}
|
||||
case TYPE_UINT16:
|
||||
{
|
||||
vsprintf(buf, "%"PRIu16, args);
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_INT32:
|
||||
{
|
||||
vsprintf(buf, "%"PRIi32, args);
|
||||
break;
|
||||
}
|
||||
case TYPE_TIMESTAMP:
|
||||
case TYPE_UINT32:
|
||||
{
|
||||
vsprintf(buf, "%"PRIu32, args);
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_INT64:
|
||||
{
|
||||
vsprintf(buf, "%"PRIi64, args);
|
||||
break;
|
||||
}
|
||||
case TYPE_UINT64:
|
||||
{
|
||||
vsprintf(buf, "%"PRIu64, args);
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_FLOAT:
|
||||
{
|
||||
vsprintf(buf, "%f", args);
|
||||
break;
|
||||
}
|
||||
case TYPE_DOUBLE:
|
||||
{
|
||||
vsprintf(buf, "%lf", args);
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_STRING:
|
||||
{
|
||||
tmp_str = va_arg(args, char *);
|
||||
if (n_args == 1) {
|
||||
tmp_len = strlen(tmp_str);
|
||||
} else {
|
||||
tmp_len = va_arg(args, size_t);
|
||||
}
|
||||
__attribute__((fallthrough));
|
||||
}
|
||||
case TYPE_BLOB:
|
||||
{
|
||||
if (tmp_str == 0) {
|
||||
tmp_str = (char *)va_arg(args, void *);
|
||||
tmp_len = va_arg(args, size_t);
|
||||
}
|
||||
|
||||
if (tmp_str == 0) {
|
||||
esc_str = (char *)malloc(5);
|
||||
if (esc_str == 0) {
|
||||
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
memcpy(esc_str, "NULL", 4);
|
||||
esc_str[4] = '\0';
|
||||
esc_len = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
sql = mysql_init(NULL);
|
||||
if (sql == 0) {
|
||||
fprintf(stderr, "[%d]mysql_init: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
esc_str = (char *)malloc(tmp_len * 2 + 1 + 2);
|
||||
if (esc_str == 0) {
|
||||
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
mysql_close(sql);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
esc_str[0] = '\'';
|
||||
esc_len = mysql_real_escape_string(sql, esc_str + 1, tmp_str, tmp_len);
|
||||
esc_str[esc_len + 1] = '\'';
|
||||
esc_str[esc_len + 2] = '\0';
|
||||
esc_len += 2;
|
||||
mysql_close(sql);
|
||||
|
||||
tmp_str = esc_str;
|
||||
esc_str = (char *)realloc(esc_str, esc_len + 1);
|
||||
if (esc_str == 0) {
|
||||
fprintf(stderr, "[%d]realloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_RAW:
|
||||
{
|
||||
tmp_str = va_arg(args, char *);
|
||||
tmp_len = va_arg(args, size_t);
|
||||
|
||||
esc_str = (char *)malloc(tmp_len + 1);
|
||||
if (esc_str == 0) {
|
||||
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
memcpy(esc_str, tmp_str, tmp_len);
|
||||
esc_str[tmp_len] = '\0';
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (esc_str == 0) {
|
||||
if (strmemcpy(buf, strlen(buf), &esc_str, &esc_len) != 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (str != 0) {
|
||||
*str = esc_str;
|
||||
*len = esc_len;
|
||||
}
|
||||
|
||||
return esc_str;
|
||||
}
|
||||
9
src/db_value.h
Normal file
9
src/db_value.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef H__DB_VALUE__
|
||||
#define H__DB_VALUE__
|
||||
|
||||
#include "db_column.h"
|
||||
|
||||
char *db_value(char **str, size_t *len, e_column_type type, uint32_t n_args, ...);
|
||||
char *db_value_va(char **str, size_t *len, e_column_type type, uint32_t n_args, va_list args);
|
||||
|
||||
#endif // H__DB_VALUE__
|
||||
719
src/db_where-builder.c
Normal file
719
src/db_where-builder.c
Normal file
@@ -0,0 +1,719 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "db_where-builder.h"
|
||||
#include "db_connection.h"
|
||||
#include "db_value.h"
|
||||
#include "strext.h"
|
||||
|
||||
|
||||
struct where_logic_t {
|
||||
where_builder *up;
|
||||
e_where_logic logic_type;
|
||||
|
||||
where_builder **constructs;
|
||||
size_t n_constructs;
|
||||
size_t n_alloc;
|
||||
};
|
||||
typedef struct where_logic_t where_logic;
|
||||
|
||||
struct where_clause_t {
|
||||
where_builder *up;
|
||||
e_where_logic logic_type;
|
||||
|
||||
// Table
|
||||
char *table;
|
||||
size_t table_len;
|
||||
|
||||
// Column
|
||||
char *col;
|
||||
size_t col_len;
|
||||
|
||||
// Op
|
||||
e_where_op op;
|
||||
|
||||
// Values
|
||||
char **values;
|
||||
size_t *values_len;
|
||||
size_t n_values;
|
||||
size_t n_alloc;
|
||||
};
|
||||
typedef struct where_clause_t where_clause;
|
||||
|
||||
|
||||
// private:
|
||||
void freeLogic(where_logic **logic_ptr)
|
||||
{
|
||||
where_logic *logic;
|
||||
where_builder *construct;
|
||||
|
||||
logic = *logic_ptr;
|
||||
while (logic->n_constructs > 0) {
|
||||
construct = logic->constructs[logic->n_constructs - 1];
|
||||
construct->up = 0;
|
||||
destroyWhereBuilder(&construct);
|
||||
logic->n_constructs--;
|
||||
}
|
||||
if (logic->constructs != 0) {
|
||||
free(logic->constructs);
|
||||
logic->constructs = 0;
|
||||
}
|
||||
free(*logic_ptr);
|
||||
*logic_ptr = 0;
|
||||
}
|
||||
where_logic *createLogic(e_where_logic type, size_t initial_size)
|
||||
{
|
||||
where_logic *logic = (where_logic *)malloc(sizeof(where_logic));
|
||||
if (logic == 0) {
|
||||
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
memset(logic, 0, sizeof(where_logic));
|
||||
|
||||
logic->logic_type = type;
|
||||
|
||||
if (initial_size == 0) {
|
||||
return logic;
|
||||
}
|
||||
|
||||
logic->constructs = (where_builder **)malloc(sizeof(where_builder *) * initial_size);
|
||||
if (logic->constructs == 0) {
|
||||
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
freeLogic(&logic);
|
||||
return 0;
|
||||
}
|
||||
memset(logic->constructs, 0, sizeof(where_builder *) * initial_size);
|
||||
logic->n_constructs = 0;
|
||||
logic->n_alloc = initial_size;
|
||||
|
||||
return logic;
|
||||
}
|
||||
where_builder *appendClause(where_builder *wb, where_builder *wb_clause)
|
||||
{
|
||||
where_logic *logic = (where_logic *)wb;
|
||||
where_builder **old_ptr;
|
||||
size_t new_size;
|
||||
|
||||
if (wb_clause == 0) {
|
||||
return wb;
|
||||
}
|
||||
|
||||
if (!(wb->logic_type == AND || wb->logic_type == OR)) {
|
||||
fprintf(stderr, "[%d]appendClause: Where-builder stack corrupted!\n", __LINE__);
|
||||
return wb;
|
||||
}
|
||||
|
||||
if (logic->n_constructs == logic->n_alloc) {
|
||||
old_ptr = (where_builder **)logic->constructs;
|
||||
new_size = sizeof(where_builder *) * (logic->n_alloc + 1);
|
||||
logic->constructs = (where_builder **)realloc(logic->constructs, new_size);
|
||||
if (logic->constructs == 0) {
|
||||
fprintf(stderr, "[%d]realloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
logic->constructs = old_ptr;
|
||||
return wb;
|
||||
}
|
||||
logic->n_alloc++;
|
||||
}
|
||||
|
||||
logic->constructs[logic->n_constructs] = wb_clause;
|
||||
logic->n_constructs++;
|
||||
wb_clause->up = (where_builder *)logic;
|
||||
|
||||
return wb;
|
||||
}
|
||||
|
||||
int ensureValueSize(where_clause *clause, size_t new_size)
|
||||
{
|
||||
size_t *old_lens;
|
||||
char **old_values;
|
||||
|
||||
if (clause->n_alloc >= new_size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
old_values = clause->values;
|
||||
clause->values = (char **)realloc(clause->values, sizeof(char *) * new_size);
|
||||
if (clause->values == 0) {
|
||||
fprintf(stderr, "[%d]realloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
clause->values = old_values;
|
||||
return 1;
|
||||
}
|
||||
|
||||
old_lens = clause->values_len;
|
||||
clause->values_len = (size_t *)realloc(clause->values_len, sizeof(size_t) * new_size);
|
||||
if (clause->values_len == 0) {
|
||||
fprintf(stderr, "[%d]realloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
clause->values_len = old_lens;
|
||||
return 1;
|
||||
}
|
||||
|
||||
(clause->n_alloc)++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
where_clause *createWhere(const char *tbl, const char *col, e_where_op op)
|
||||
{
|
||||
where_clause *clause;
|
||||
|
||||
clause = (where_clause *)malloc(sizeof(where_clause));
|
||||
if (clause == 0) {
|
||||
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
memset(clause, 0, sizeof(where_clause));
|
||||
|
||||
clause->logic_type = CLAUSE;
|
||||
clause->op = op;
|
||||
|
||||
if (tbl != 0) {
|
||||
if (strmemcpy(tbl, strlen(tbl), &clause->table, &clause->table_len) != 0) {
|
||||
freeWhere((where_builder **)&clause);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (strmemcpy(col, strlen(col), &clause->col, &clause->col_len) != 0) {
|
||||
freeWhere((where_builder **)&clause);
|
||||
return 0;
|
||||
}
|
||||
|
||||
clause->values = (char **)malloc(sizeof(char *));
|
||||
clause->values_len = (size_t *)malloc(sizeof(size_t));
|
||||
if (clause->values == 0 || clause->values_len == 0) {
|
||||
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
freeWhere((where_builder **)&clause);
|
||||
return 0;
|
||||
}
|
||||
clause->n_alloc = 1;
|
||||
|
||||
return clause;
|
||||
}
|
||||
|
||||
where_builder *where_And_Or(where_builder *wb, where_builder *wb_clause, e_where_logic and_or)
|
||||
{
|
||||
where_logic *logic;
|
||||
|
||||
if (wb == 0) {
|
||||
wb = (where_builder *)createLogic(and_or, 2);
|
||||
if (wb == 0) {
|
||||
return wb_clause;
|
||||
}
|
||||
}
|
||||
|
||||
switch(wb->logic_type) {
|
||||
case UNK:
|
||||
{
|
||||
if ((logic = createLogic(and_or, 2)) == 0) {
|
||||
destroyWhereBuilder(&wb_clause);
|
||||
return wb;
|
||||
}
|
||||
free(wb);
|
||||
if (wb_clause != 0) {
|
||||
logic->constructs[0] = wb_clause;
|
||||
logic->n_constructs++;
|
||||
wb_clause->up = (where_builder *)logic;
|
||||
}
|
||||
wb = (where_builder *)logic;
|
||||
break;
|
||||
}
|
||||
|
||||
case CLAUSE:
|
||||
{
|
||||
if ((logic = createLogic(and_or, 2)) == 0) {
|
||||
destroyWhereBuilder(&wb_clause);
|
||||
return wb;
|
||||
}
|
||||
logic->constructs[0] = wb;
|
||||
logic->n_constructs++;
|
||||
wb->up = (where_builder *)logic;
|
||||
if (wb_clause != 0) {
|
||||
logic->constructs[1] = wb_clause;
|
||||
logic->n_constructs++;
|
||||
wb_clause->up = (where_builder *)logic;
|
||||
}
|
||||
wb = (where_builder *)logic;
|
||||
break;
|
||||
}
|
||||
|
||||
case OR:
|
||||
{
|
||||
if (and_or == AND) {
|
||||
if ((logic = createLogic(AND, 2)) == 0) {
|
||||
destroyWhereBuilder(&wb_clause);
|
||||
return wb;
|
||||
}
|
||||
if (whereOr(wb, (where_builder *)logic) == 0) {
|
||||
freeLogic(&logic);
|
||||
destroyWhereBuilder(&wb_clause);
|
||||
return wb;
|
||||
}
|
||||
wb = appendClause((where_builder *)logic, wb_clause);
|
||||
} else {
|
||||
wb = appendClause(wb, wb_clause);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case AND:
|
||||
{
|
||||
if (and_or == AND) {
|
||||
wb = appendClause(wb, wb_clause);
|
||||
} else {
|
||||
if ((logic = createLogic(OR, 2)) == 0) {
|
||||
destroyWhereBuilder(&wb_clause);
|
||||
return wb;
|
||||
}
|
||||
if (whereAnd(wb, (where_builder *)logic) == 0) {
|
||||
freeLogic(&logic);
|
||||
destroyWhereBuilder(&wb_clause);
|
||||
return wb;
|
||||
}
|
||||
wb = appendClause((where_builder *)logic, wb_clause);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return wb;
|
||||
}
|
||||
|
||||
where_builder *where_In_notIn_va(where_builder *wb, const char *tbl, const char *col, e_where_op op,
|
||||
e_column_type type, uint32_t n_args, va_list args)
|
||||
{
|
||||
where_clause *clause;
|
||||
where_builder *wb_clause;
|
||||
|
||||
if (wb == 0) {
|
||||
return where_va(tbl, col, op, type, n_args, args);
|
||||
}
|
||||
|
||||
switch (wb->logic_type) {
|
||||
case UNK:
|
||||
{
|
||||
free(wb);
|
||||
return where_va(tbl, col, op, type, n_args, args);
|
||||
}
|
||||
case CLAUSE:
|
||||
{
|
||||
clause = (where_clause *)wb;
|
||||
if (clause->op != op
|
||||
|| (tbl != 0 && clause->table == 0)
|
||||
|| (tbl != 0 && clause->table != 0 && strcmp(clause->table, tbl) != 0)
|
||||
|| (col != 0 && clause->col == 0)
|
||||
|| (col != 0 && clause->col != 0 && strcmp(clause->col, col) != 0)) {
|
||||
if (wb->up == 0) {
|
||||
fprintf(stderr, "[%d]whereIn_notIn: Where-builder stack corrupted!\n", __LINE__);
|
||||
return wb;
|
||||
}
|
||||
return where_In_notIn_va(wb->up, tbl, col, op, type, n_args, args);
|
||||
}
|
||||
|
||||
return setWhereValue_va((where_builder *)clause, type, n_args, args);
|
||||
}
|
||||
case AND:
|
||||
case OR:
|
||||
{
|
||||
if ((wb_clause = where_va(tbl, col, op, type, n_args, args)) == 0) {
|
||||
return wb;
|
||||
}
|
||||
if (wb->logic_type == AND) {
|
||||
whereAnd(wb, wb_clause);
|
||||
} else {
|
||||
whereOr(wb, wb_clause);
|
||||
}
|
||||
return wb_clause;
|
||||
}
|
||||
}
|
||||
|
||||
return wb;
|
||||
}
|
||||
where_builder *where_In_notIn(where_builder *wb, const char *tbl, const char *col, e_where_op op,
|
||||
e_column_type type, uint32_t n_args, ...)
|
||||
{
|
||||
where_builder *ret;
|
||||
va_list args;
|
||||
|
||||
va_start(args, n_args);
|
||||
ret = where_In_notIn_va(wb, tbl, col, op, type, n_args, args);
|
||||
va_end(args);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// public:
|
||||
where_builder *createWhereBuilder(where_builder *initial_clause)
|
||||
{
|
||||
if (initial_clause != 0) {
|
||||
return initial_clause;
|
||||
}
|
||||
|
||||
where_builder *wb = (where_builder *)malloc(sizeof(where_builder));
|
||||
if (wb == 0) {
|
||||
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
memset(wb, 0, sizeof(where_builder));
|
||||
|
||||
return wb;
|
||||
}
|
||||
void destroyWhereBuilder(where_builder **wb_ptr)
|
||||
{
|
||||
where_builder *wb = finalizeWhere(*wb_ptr);
|
||||
|
||||
if (*wb_ptr == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch(wb->logic_type) {
|
||||
case CLAUSE:
|
||||
{
|
||||
freeWhere(&wb);
|
||||
break;
|
||||
}
|
||||
case OR:
|
||||
case AND:
|
||||
{
|
||||
freeLogic((where_logic **)&wb);
|
||||
break;
|
||||
}
|
||||
case UNK:
|
||||
{
|
||||
free(*wb_ptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*wb_ptr = 0;
|
||||
}
|
||||
|
||||
|
||||
where_builder *where(const char *tbl, const char *col, e_where_op op, e_column_type type,
|
||||
uint32_t n_args, ...)
|
||||
{
|
||||
va_list args;
|
||||
where_builder *ret;
|
||||
|
||||
va_start(args, n_args);
|
||||
ret = where_va(tbl, col, op, type, n_args, args);
|
||||
va_end(args);
|
||||
|
||||
return ret;
|
||||
}
|
||||
where_builder *where_va(const char *tbl, const char *col, e_where_op op, e_column_type type,
|
||||
uint32_t n_args, va_list args)
|
||||
{
|
||||
where_builder *wb_clause = (where_builder *)createWhere(tbl, col, op);
|
||||
|
||||
if (wb_clause == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return setWhereValue_va(wb_clause, type, n_args, args);
|
||||
}
|
||||
void freeWhere(where_builder **wb_clause_ptr)
|
||||
{
|
||||
where_clause *clause = (where_clause *)(*wb_clause_ptr);
|
||||
|
||||
if (wb_clause_ptr == 0 || (*wb_clause_ptr)->logic_type != CLAUSE) {
|
||||
fprintf(stderr, "[%d]freeWhere: Where-builder stack corrupted!\n", __LINE__);
|
||||
return;
|
||||
}
|
||||
|
||||
while (clause->n_values > 0) {
|
||||
free(clause->values[clause->n_values - 1]);
|
||||
clause->n_values--;
|
||||
}
|
||||
if (clause->values != 0) {
|
||||
free(clause->values);
|
||||
clause->values = 0;
|
||||
}
|
||||
if (clause->values_len != 0) {
|
||||
free(clause->values_len);
|
||||
clause->values_len = 0;
|
||||
}
|
||||
|
||||
if (clause->col != 0) {
|
||||
free(clause->col);
|
||||
clause->col = 0;
|
||||
}
|
||||
|
||||
if (clause->table) {
|
||||
free(clause->table);
|
||||
clause->table = 0;
|
||||
}
|
||||
|
||||
free(clause);
|
||||
*wb_clause_ptr = 0;
|
||||
}
|
||||
|
||||
|
||||
where_builder *clearWhereValue(where_builder *wb_clause)
|
||||
{
|
||||
where_clause *clause = (where_clause *)wb_clause;
|
||||
|
||||
if (wb_clause->logic_type != CLAUSE) {
|
||||
fprintf(stderr, "[%d]clearWhereValue: Where-builder stack corrupted!\n", __LINE__);
|
||||
return wb_clause;
|
||||
}
|
||||
|
||||
while (clause->n_values > 0) {
|
||||
clause->n_values--;
|
||||
free(clause->values[clause->n_values]);
|
||||
clause->values[clause->n_values] = 0;
|
||||
clause->values_len[clause->n_values] = 0;
|
||||
}
|
||||
|
||||
return wb_clause;
|
||||
}
|
||||
where_builder *setWhereValue(where_builder *wb_clause, e_column_type type, uint32_t n_args, ...)
|
||||
{
|
||||
va_list args;
|
||||
where_builder *ret;
|
||||
|
||||
va_start(args, n_args);
|
||||
ret = setWhereValue_va(wb_clause, type, n_args, args);
|
||||
va_end(args);
|
||||
|
||||
return ret;
|
||||
}
|
||||
where_builder *setWhereValue_va(where_builder *wb_clause,
|
||||
e_column_type type, uint32_t n_args, va_list args)
|
||||
{
|
||||
where_clause *clause = (where_clause *)wb_clause;
|
||||
char *value;
|
||||
size_t value_len;
|
||||
|
||||
if (wb_clause->logic_type != CLAUSE) {
|
||||
fprintf(stderr, "[%d]setWhereValue: Where-builder stack corrupted!\n", __LINE__);
|
||||
return wb_clause;
|
||||
}
|
||||
|
||||
switch (clause->op) {
|
||||
case EQ:
|
||||
case NEQ:
|
||||
case GT:
|
||||
case GTE:
|
||||
case LT:
|
||||
case LTE:
|
||||
{
|
||||
clearWhereValue(wb_clause);
|
||||
|
||||
db_value_va(&value, &value_len, type, n_args, args);
|
||||
|
||||
if (value != 0) {
|
||||
clause->values[clause->n_values] = value;
|
||||
clause->values_len[clause->n_values] = value_len;
|
||||
}
|
||||
clause->n_values++;
|
||||
break;
|
||||
}
|
||||
|
||||
case IS_NULL:
|
||||
case NOT_NULL:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
case IN:
|
||||
case NOT_IN:
|
||||
{
|
||||
if (ensureValueSize(clause, clause->n_values + n_args) != 0) {
|
||||
freeWhere(&wb_clause);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < n_args; i++) {
|
||||
db_value_va(&value, &value_len, type, 1, args);
|
||||
if (value != 0) {
|
||||
clause->values[clause->n_values] = value;
|
||||
clause->values_len[clause->n_values] = value_len;
|
||||
}
|
||||
clause->n_values++;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return wb_clause;
|
||||
}
|
||||
|
||||
|
||||
where_builder *whereAnd(where_builder *wb, where_builder *wb_clause)
|
||||
{
|
||||
return where_And_Or(wb, wb_clause, AND);
|
||||
}
|
||||
where_builder *whereOr(where_builder *wb, where_builder *wb_clause)
|
||||
{
|
||||
return where_And_Or(wb, wb_clause, OR);
|
||||
}
|
||||
|
||||
where_builder *whereIn(where_builder *wb, const char *tbl, const char *col,
|
||||
e_column_type type, uint32_t n_args, ...)
|
||||
{
|
||||
where_builder *ret;
|
||||
va_list args;
|
||||
|
||||
va_start(args, n_args);
|
||||
ret = whereIn_va(wb, tbl, col, type, n_args, args);
|
||||
va_end(args);
|
||||
|
||||
return ret;
|
||||
}
|
||||
where_builder *whereIn_va(where_builder *wb, const char *tbl, const char *col,
|
||||
e_column_type type, uint32_t n_args, va_list args)
|
||||
{
|
||||
return where_In_notIn_va(wb, tbl, col, IN, type, n_args, args);
|
||||
}
|
||||
where_builder *whereNotIn(where_builder *wb, const char *tbl, const char *col,
|
||||
e_column_type type, uint32_t n_args, ...)
|
||||
{
|
||||
where_builder *ret;
|
||||
va_list args;
|
||||
|
||||
va_start(args, n_args);
|
||||
ret = whereIn_va(wb, tbl, col, type, n_args, args);
|
||||
va_end(args);
|
||||
|
||||
return ret;
|
||||
}
|
||||
where_builder *whereNotIn_va(where_builder *wb, const char *tbl, const char *col,
|
||||
e_column_type type, uint32_t n_args, va_list args)
|
||||
{
|
||||
|
||||
return where_In_notIn_va(wb, tbl, col, NOT_IN, type, n_args, args);
|
||||
}
|
||||
|
||||
where_builder *whereNext(where_builder *wb)
|
||||
{
|
||||
if (wb->up == 0) {
|
||||
fprintf(stderr, "[%d]whereEnd: Where-builder stack corrupted!\n", __LINE__);
|
||||
return wb;
|
||||
}
|
||||
|
||||
return wb->up;
|
||||
}
|
||||
where_builder *finalizeWhere(where_builder *wb)
|
||||
{
|
||||
while (wb->up != 0) {
|
||||
wb = wb->up;
|
||||
}
|
||||
return wb;
|
||||
}
|
||||
|
||||
|
||||
int compileWhere(where_builder *wb, char **str, size_t *str_len)
|
||||
{
|
||||
where_logic *logic;
|
||||
where_clause *clause;
|
||||
struct str_builder_t *sb;
|
||||
char *tmp;
|
||||
size_t tmp_len;
|
||||
size_t idx;
|
||||
|
||||
sb = strbld_create();
|
||||
if (sb == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch(wb->logic_type) {
|
||||
case UNK:
|
||||
strbld_destroy(&sb);
|
||||
return -1;
|
||||
case CLAUSE:
|
||||
{
|
||||
clause = (where_clause *)wb;
|
||||
|
||||
// Column
|
||||
if (clause->table != 0) {
|
||||
strbld_char(sb, '`');
|
||||
strbld_str(sb, clause->table, clause->table_len);
|
||||
strbld_char(sb, '`');
|
||||
strbld_char(sb, '.');
|
||||
}
|
||||
strbld_char(sb, '`');
|
||||
strbld_str(sb, clause->col, clause->col_len);
|
||||
strbld_char(sb, '`');
|
||||
strbld_char(sb, ' ');
|
||||
|
||||
// Op
|
||||
switch(clause->op) {
|
||||
case EQ:
|
||||
strbld_char(sb, '=');
|
||||
break;
|
||||
case NEQ:
|
||||
strbld_char(sb, '!');
|
||||
strbld_char(sb, '=');
|
||||
break;
|
||||
case GT:
|
||||
strbld_char(sb, '>');
|
||||
break;
|
||||
case GTE:
|
||||
strbld_char(sb, '>');
|
||||
strbld_char(sb, '=');
|
||||
break;
|
||||
case LT:
|
||||
strbld_char(sb, '<');
|
||||
break;
|
||||
case LTE:
|
||||
strbld_char(sb, '<');
|
||||
strbld_char(sb, '=');
|
||||
break;
|
||||
case IS_NULL:
|
||||
strbld_str(sb, "IS NULL", 7);
|
||||
break;
|
||||
case NOT_NULL:
|
||||
strbld_str(sb, "IS NOT NULL", 11);
|
||||
break;
|
||||
case IN:
|
||||
strbld_str(sb, "IN(", 3);
|
||||
break;
|
||||
case NOT_IN:
|
||||
strbld_str(sb, "NOT IN(", 7);
|
||||
break;
|
||||
}
|
||||
|
||||
// Value
|
||||
for (idx = 0; idx < clause->n_values; idx++) {
|
||||
strbld_char(sb, ' ');
|
||||
strbld_str(sb, clause->values[idx], clause->values_len[idx]);
|
||||
if (idx < clause->n_values - 1 && (clause->op == IN || clause->op == NOT_IN)) {
|
||||
strbld_char(sb, ',');
|
||||
}
|
||||
}
|
||||
|
||||
if (clause->op == IN || clause->op == NOT_IN) {
|
||||
strbld_char(sb, ' ');
|
||||
strbld_char(sb, ')');
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OR:
|
||||
case AND:
|
||||
{
|
||||
logic = (where_logic *)wb;
|
||||
|
||||
if (logic->n_constructs == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
strbld_char(sb, '(');
|
||||
for (size_t i = 0; i < logic->n_constructs; i++) {
|
||||
if (compileWhere(logic->constructs[i], &tmp, &tmp_len) == 0) {
|
||||
strbld_str(sb, tmp, tmp_len);
|
||||
free(tmp);
|
||||
}
|
||||
if (i < (logic->n_constructs - 1)) {
|
||||
strbld_str(sb, (wb->logic_type == OR ? " OR " : " AND "), (wb->logic_type == OR ? 4 : 5));
|
||||
}
|
||||
}
|
||||
strbld_char(sb, ')');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return strbld_finalize_or_destroy(&sb, str, str_len);
|
||||
}
|
||||
72
src/db_where-builder.h
Normal file
72
src/db_where-builder.h
Normal file
@@ -0,0 +1,72 @@
|
||||
#ifndef DB_WHEREBUILDER_H
|
||||
#define DB_WHEREBUILDER_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include "db_column.h"
|
||||
|
||||
enum e_where_logic_t {
|
||||
UNK,
|
||||
CLAUSE,
|
||||
AND,
|
||||
OR
|
||||
};
|
||||
|
||||
enum e_where_op_t {
|
||||
EQ,
|
||||
NEQ,
|
||||
GT,
|
||||
GTE,
|
||||
LT,
|
||||
LTE,
|
||||
IS_NULL,
|
||||
NOT_NULL,
|
||||
IN,
|
||||
NOT_IN
|
||||
};
|
||||
|
||||
struct where_builder_t {
|
||||
struct where_builder_t *up;
|
||||
enum e_where_logic_t logic_type;
|
||||
};
|
||||
|
||||
typedef enum e_where_logic_t e_where_logic;
|
||||
typedef enum e_where_op_t e_where_op;
|
||||
typedef struct where_builder_t where_builder;
|
||||
|
||||
|
||||
where_builder *createWhereBuilder(where_builder *initial_clause);
|
||||
void destroyWhereBuilder(where_builder **wb_ptr);
|
||||
|
||||
|
||||
where_builder *where(const char *tbl, const char *col, e_where_op op, e_column_type type,
|
||||
uint32_t n_args, ...);
|
||||
where_builder *where_va(const char *tbl, const char *col, e_where_op op, e_column_type type,
|
||||
uint32_t n_args, va_list args);
|
||||
void freeWhere(where_builder **wb_clause_ptr);
|
||||
|
||||
|
||||
where_builder *clearWhereValue(where_builder *wb_clause);
|
||||
where_builder *setWhereValue(where_builder *wb_clause, e_column_type type, uint32_t n_args, ...);
|
||||
where_builder *setWhereValue_va(where_builder *wb_clause,
|
||||
e_column_type type, uint32_t n_args, va_list args);
|
||||
|
||||
|
||||
where_builder *whereAnd(where_builder *wb, where_builder *wb_clause);
|
||||
where_builder *whereOr(where_builder *wb, where_builder *wb_clause);
|
||||
|
||||
where_builder *whereIn(where_builder *wb, const char *tbl, const char *col,
|
||||
e_column_type type, uint32_t n_args, ...);
|
||||
where_builder *whereIn_va(where_builder *wb, const char *tbl, const char *col,
|
||||
e_column_type type, uint32_t n_args, va_list args);
|
||||
where_builder *whereNotIn(where_builder *wb, const char *tbl, const char *col,
|
||||
e_column_type type, uint32_t n_args, ...);
|
||||
where_builder *whereNotIn_va(where_builder *wb, const char *tbl, const char *col,
|
||||
e_column_type type, uint32_t n_args, va_list args);
|
||||
|
||||
where_builder *whereNext(where_builder *wb);
|
||||
where_builder *finalizeWhere(where_builder *wb);
|
||||
|
||||
|
||||
int compileWhere(where_builder *wb, char **str, size_t *str_len);
|
||||
|
||||
#endif // DB_WHEREBUILDER_H
|
||||
221
src/strext.c
Normal file
221
src/strext.c
Normal file
@@ -0,0 +1,221 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "strext.h"
|
||||
|
||||
size_t strlen_norm(const char *str, size_t str_len)
|
||||
{
|
||||
if (str == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (str_len == 0) {
|
||||
return strlen(str);
|
||||
}
|
||||
while (str[str_len - 1] == '\0') {
|
||||
str_len--;
|
||||
}
|
||||
return str_len;
|
||||
}
|
||||
|
||||
int strmemcpy(const char *str, size_t str_len, char **new_str, size_t *new_len)
|
||||
{
|
||||
if (str == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
str_len = strlen_norm(str, str_len);
|
||||
|
||||
*new_str = (char *)malloc(str_len + 1);
|
||||
if (*new_str == 0) {
|
||||
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
memcpy(*new_str, str, str_len);
|
||||
(*new_str)[str_len] = '\0';
|
||||
(*new_len) = str_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t strapp(char **out, const char *a, size_t a_len)
|
||||
{
|
||||
size_t s_len;
|
||||
if (a[a_len - 1] == '\0') {
|
||||
a_len -= 1;
|
||||
}
|
||||
|
||||
if (*out == 0) {
|
||||
s_len = 0;
|
||||
*out = (char *)malloc(a_len + 1);
|
||||
if (*out == 0) {
|
||||
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
s_len = strlen(*out);
|
||||
*out = (char *)realloc(*out, s_len + a_len + 1);
|
||||
if (*out == 0) {
|
||||
fprintf(stderr, "[%d]realloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
strncpy(*out + s_len, a, a_len);
|
||||
*(*out + s_len + a_len) = '\0';
|
||||
|
||||
return s_len + a_len;
|
||||
}
|
||||
|
||||
size_t strcmb(char **out, const char *a, size_t a_len, const char *b, size_t b_len)
|
||||
{
|
||||
size_t s_len, t_len;
|
||||
if (a_len == 0) {
|
||||
a_len = strlen(a);
|
||||
} else if (a[a_len - 1] == '\0') {
|
||||
a_len -= 1;
|
||||
}
|
||||
if (b_len == 0) {
|
||||
b_len = strlen(b);
|
||||
} else if (b[b_len - 1] == '\0') {
|
||||
b_len -= 1;
|
||||
}
|
||||
t_len = a_len + b_len;
|
||||
|
||||
if (*out == 0) {
|
||||
s_len = 0;
|
||||
*out = (char *)malloc(t_len + 1);
|
||||
if (*out == 0) {
|
||||
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
s_len = strlen(*out);
|
||||
*out = (char *)realloc(*out, s_len + t_len + 1);
|
||||
if (*out == 0) {
|
||||
fprintf(stderr, "[%d]realloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
strncpy(*out + s_len, a, a_len);
|
||||
strncpy(*out + s_len + a_len, b, b_len);
|
||||
*(*out + s_len + t_len) = '\0';
|
||||
|
||||
return s_len + t_len;
|
||||
}
|
||||
|
||||
|
||||
str_builder *strbld_create()
|
||||
{
|
||||
str_builder *sb = malloc(sizeof(str_builder));
|
||||
if (sb == 0) {
|
||||
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
sb->str = (char *)malloc(32);
|
||||
if (sb == 0) {
|
||||
fprintf(stderr, "[%d]malloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
free(sb);
|
||||
return 0;
|
||||
}
|
||||
memset(sb->str, '\0', 32);
|
||||
|
||||
sb->alloc = 32;
|
||||
sb->len = 0;
|
||||
sb->fails = 0;
|
||||
|
||||
return sb;
|
||||
}
|
||||
void strbld_destroy(str_builder **sbp)
|
||||
{
|
||||
str_builder *sb = *sbp;
|
||||
if (sb->alloc > 0 && sb->str != 0) {
|
||||
free(sb->str);
|
||||
sb->alloc = 0;
|
||||
sb->str = 0;
|
||||
}
|
||||
free(sb);
|
||||
*sbp = 0;
|
||||
}
|
||||
void strbld_finalize(str_builder **sbp, char **str, size_t *len)
|
||||
{
|
||||
str_builder *sb = *sbp;
|
||||
*str = sb->str;
|
||||
*len = sb->len;
|
||||
sb->alloc = 0;
|
||||
strbld_destroy(sbp);
|
||||
}
|
||||
int strbld_finalize_or_destroy(str_builder **sbp, char **str, size_t *len)
|
||||
{
|
||||
if ((*sbp)->fails > 0) {
|
||||
strbld_destroy(sbp);
|
||||
return -1;
|
||||
} else {
|
||||
strbld_finalize(sbp, str, len);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int strbld_ensure_len(str_builder *sb, size_t len, int absolute)
|
||||
{
|
||||
char *new_str;
|
||||
if (sb->alloc > len) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (absolute) {
|
||||
sb->alloc = len;
|
||||
} else {
|
||||
while (sb->alloc <= len) {
|
||||
sb->alloc <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
new_str = (char *)realloc(sb->str, sb->alloc);
|
||||
if (new_str == 0) {
|
||||
fprintf(stderr, "[%d]realloc: (%d) %s\n", __LINE__, errno, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
sb->str = new_str;
|
||||
memset(sb->str + sb->len, '\0', sb->alloc - sb->len);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int strbld_str(str_builder *sb, const char *str, size_t len)
|
||||
{
|
||||
if (sb->fails > 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
len = strlen(str);
|
||||
}
|
||||
if (str[len - 1] == '\0') {
|
||||
len--;
|
||||
}
|
||||
|
||||
if (!strbld_ensure_len(sb, sb->len + len, 0)) {
|
||||
sb->fails++;
|
||||
return 0;
|
||||
}
|
||||
memmove(sb->str + sb->len, str, len);
|
||||
sb->len += len;
|
||||
|
||||
return 1;
|
||||
}
|
||||
int strbld_char(str_builder *sb, const char c)
|
||||
{
|
||||
if (sb->fails > 0) {
|
||||
return 0;
|
||||
}
|
||||
if (!strbld_ensure_len(sb, sb->len + 1, 0)) {
|
||||
sb->fails++;
|
||||
return 0;
|
||||
}
|
||||
*(sb->str + sb->len) = c;
|
||||
sb->len++;
|
||||
return 1;
|
||||
}
|
||||
32
src/strext.h
Normal file
32
src/strext.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef H__STRCMB__
|
||||
#define H__STRCMB__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#define STR_LEN(x) (sizeof(x)/sizeof(x[0])-1)
|
||||
|
||||
struct str_builder_t {
|
||||
char *str;
|
||||
size_t alloc;
|
||||
size_t len;
|
||||
size_t fails;
|
||||
};
|
||||
typedef struct str_builder_t str_builder;
|
||||
|
||||
size_t strlen_norm(const char *str, size_t str_len);
|
||||
int strmemcpy(const char *str, size_t str_len, char **new_str, size_t *new_len);
|
||||
|
||||
size_t strapp(char **out, const char *a, size_t a_len);
|
||||
size_t strcmb(char **out, const char *a, size_t a_len, const char *b, size_t b_len);
|
||||
|
||||
str_builder *strbld_create(void);
|
||||
void strbld_destroy(str_builder **sb);
|
||||
void strbld_finalize(str_builder **sb, char **str, size_t *len);
|
||||
int strbld_finalize_or_destroy(str_builder **sb, char **str, size_t *len);
|
||||
|
||||
int strbld_ensure_len(str_builder *sb, size_t len, int absolute);
|
||||
|
||||
int strbld_str(str_builder *sb, const char *str, size_t len);
|
||||
int strbld_char(str_builder *sb, const char c);
|
||||
|
||||
#endif // H__STRCMB__
|
||||
Reference in New Issue
Block a user