A zero-boilerplate, ORM for PostgreSQL
git clone git://soophie.de/glue
blob: d9216815c6c71d939bca408914f338cf9e5e2b09 (4988 bytes)[doc][blame][raw]
1
#ifndef _SO_GLUE_H2
#define _SO_GLUE_H4
#include <stddef.h>5
#include <stdbool.h>7
typedef void (*glue_fetch_fn)(char *, char *, void *);9
void glue_fetch(const char *query, size_t params_len, const char *params[params_len], glue_fetch_fn fn, void **data, size_t *len, size_t size);10
void glue_execute(const char *query, size_t params_len, const char *params[params_len]);11
void glue_get_string(char *src, char **dest);12
void glue_get_int(char *src, int *dest);13
void glue_get_double(char *src, double *dest);14
void glue_get_float(char *src, float *dest);15
void glue_get_bool(char *src, bool *dest);18
#define TABLEDEF($name, $cols) \19
typedef struct { \20
$cols(X_COLDEF) \21
} $name##_t; \22
\23
void _##$name##_fetch_fn(char *column, char *value, void *data) { \24
$name##_t *self = ($name##_t *) data; \25
$cols(X_ASSIGN) \26
} \27
void $name##_fetch(const char *query, size_t params_len, const char *params[params_len], $name##_t **data, size_t *len) { \28
glue_fetch(query, params_len, params, _##$name##_fetch_fn, (void *) data, len, sizeof($name##_t)); \29
} \30
void $name##_free($name##_t *self) { \31
$cols(X_FREE) \32
} \33
\34
void $name##_list_free($name##_t *list, size_t len) { \35
if (!list) return; \36
for (size_t i = 0; i < len; i++) { \37
$name##_free(&list[i]); \38
} \39
free(list); \40
} \41
\42
void $name##_dbg($name##_t *self) { \43
fprintf(stdout, "(%s_t) {\n", #$name); \44
$cols(X_DEBUG) \45
fprintf(stdout, "}\n"); \46
}48
#define X_COLDEF($type, $name, $getter, $freeable, $format) \49
$type $name;51
#define X_FREE($type, $name, $getter, $freeable, $format) \52
if ($freeable) { \53
if (self->$name) { \54
void **name = (void **) &self->$name; \55
free(*name); \56
*name = NULL; \57
} \58
}60
#define X_ASSIGN($type, $name, $getter, $freeable, $format) \61
if (strcmp(column, #$name) == 0) { \62
$getter(value, &self->$name); \63
}65
#define X_DEBUG($type, $name, $getter, $freeable, $format) \66
fprintf(stdout, " .%s = ", #$name); \67
$format($name) \68
fprintf(stdout, "\n");70
#define FORMAT_INT($name) \71
fprintf(stdout, "%d,", (int) self->$name);73
#define FORMAT_TEXT($name) \74
fprintf(stdout, "%s,", (const char *) self->$name);76
#define COLDEF_INT(X, $name) \77
X(int, $name, glue_get_int, 0, FORMAT_INT)79
#define COLDEF_TEXT(X, $name) \80
X(char *, $name, glue_get_string, 1, FORMAT_TEXT)82
#ifdef SO_GLUE_IMPL84
#include <stdio.h>85
#include <stdlib.h>86
#include <string.h>87
#include <inttypes.h>88
#include <libpq-fe.h>90
void glue_execute(const char *query, size_t params_len, const char *params[params_len]) {91
PGconn *conn = PQconnectdb(GLUE_DB_INFO);92
if (PQstatus(conn) != CONNECTION_OK) {93
fprintf(stderr, "%s\n", PQerrorMessage(conn));94
PQfinish(conn);95
return;96
}97
PGresult *result = PQexecParams(conn, query, params_len, NULL, params, NULL, NULL, 0);98
ExecStatusType status = PQresultStatus(result);99
if (status != PGRES_COMMAND_OK) {100
fprintf(stderr, "%s\n", PQerrorMessage(conn));101
PQclear(result);102
return;103
}104
PQclear(result);105
PQfinish(conn);106
}108
void glue_fetch(const char *query, size_t params_len, const char *params[params_len], glue_fetch_fn fn, void **data, size_t *len, size_t size) {109
PGconn *conn = PQconnectdb(GLUE_DB_INFO);110
if (PQstatus(conn) != CONNECTION_OK) {111
fprintf(stderr, "%s\n", PQerrorMessage(conn));112
PQfinish(conn);113
return;114
}115
PGresult *result = PQexecParams(conn, query, params_len, NULL, params, NULL, NULL, 0);116
ExecStatusType status = PQresultStatus(result);117
if (status != PGRES_TUPLES_OK) {118
fprintf(stderr, "%s\n", PQerrorMessage(conn));119
PQclear(result);120
PQfinish(conn);121
return;122
}123
size_t rows = PQntuples(result);124
size_t cols = PQnfields(result);125
if (rows > 0) {126
for (size_t i = 0; i < rows; i++) {127
void *ptr = realloc(*data, size * (*len + 1));128
if (ptr == NULL) {129
// TODO error message130
PQclear(result);131
PQfinish(conn);132
return;133
}134
*data = ptr;135
void *item = (char *) *data + size * (*len);136
memset(item, 0, size);137
(*len)++;138
for (size_t j = 0; j < cols; j++) {139
if (PQgetisnull(result, i, j)) {140
continue;141
}142
char *column = PQfname(result, j);143
char *value = PQgetvalue(result, i, j);144
fn(column, value, item);145
}146
}147
}148
PQclear(result);149
PQfinish(conn);150
}152
void glue_get_string(char *src, char **dest) {153
size_t value_len = strlen(src);154
if (value_len == 0) {155
*dest = NULL;156
}157
*dest = malloc(sizeof(char) * (value_len + 1));158
memcpy(*dest, src, value_len);159
(*dest)[value_len] = '\0';160
}162
void glue_get_int(char *src, int *dest) {163
*dest = strtoimax(src, NULL, 10);164
}166
void glue_get_double(char *src, double *dest) {167
*dest = strtod(src, NULL);168
}170
void glue_get_float(char *src, float *dest) {171
*dest = strtof(src, NULL);172
}174
void glue_get_bool(char *src, bool *dest) {175
*dest = strcmp("t", src) == 0;176
}178
#endif /* SO_GLUE_IMPL */179
#endif /* _SO_GLUE_H */