Backport new DB module and subsequent changes to branch - add new version of the...
authorFrantišek Dvořák <valtri@civ.zcu.cz>
Tue, 22 Dec 2009 14:26:33 +0000 (14:26 +0000)
committerFrantišek Dvořák <valtri@civ.zcu.cz>
Tue, 22 Dec 2009 14:26:33 +0000 (14:26 +0000)
org.glite.lbjp-common.db/src/db.c [new file with mode: 0644]

diff --git a/org.glite.lbjp-common.db/src/db.c b/org.glite.lbjp-common.db/src/db.c
new file mode 100644 (file)
index 0000000..d65d5a8
--- /dev/null
@@ -0,0 +1,396 @@
+#include <sys/types.h>
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <glite/lbu/trio.h>
+
+#include "db.h"
+#include "db-int.h"
+
+
+#define VALID(BACKEND) ((BACKEND) >= 0 && (BACKEND) < GLITE_LBU_DB_BACKEND_LAST)
+
+
+struct glite_lbu_bufInsert_s {
+       glite_lbu_DBContext ctx;
+       char    *table_name;
+       char    *columns;       /* names of columns to be inserted into 
+                                * (values separated with commas) */
+       char    **rows;         /* each row hold string of one row to be inserted
+                                * (values separated with commas) */
+       long    rec_num,        /* actual number of rows in structure */
+               rec_size;       /* approx. size of a real insert string */
+       long    size_limit,     /* size and # of records limit which trigger */
+               record_limit;   /* real insert; zero means unlimitted */
+};
+
+
+/* possible backends */
+#ifdef MYSQL_SONAME
+extern glite_lbu_DBBackend_t mysql_backend;
+#else
+#define mysql_backend no_backend
+#endif
+#ifdef PSQL_SONAME
+extern glite_lbu_DBBackend_t psql_backend;
+#else
+#define psql_backend no_backend
+#endif
+
+glite_lbu_DBBackend_t no_backend = {
+       backend: -1,
+
+       /* functions unspecified */
+};
+
+glite_lbu_DBBackend_t *backends[GLITE_LBU_DB_BACKEND_LAST] = {
+       &mysql_backend,
+       &psql_backend
+};
+
+
+/* --- internal functions ---- */
+
+int glite_lbu_DBClearError(glite_lbu_DBContext ctx) {
+       ctx->err.code = 0;
+       if (ctx->err.desc) {
+               free(ctx->err.desc);
+               ctx->err.desc = NULL;
+       }
+       return 0;
+}
+
+
+int glite_lbu_DBSetError(glite_lbu_DBContext ctx, int code, const char *func, int line, const char *desc, ...) {
+       va_list ap;
+
+       if (!code) return ctx->err.code;
+
+       ctx->err.code = code;
+       free(ctx->err.desc);
+       if (desc) {
+               va_start(ap, desc);
+               vasprintf(&ctx->err.desc, desc, ap);
+               va_end(ap);
+       } else
+               ctx->err.desc = NULL;
+       dprintf(ctx, "[db %d] %s:%d %s\n", getpid(), func, line, ctx->err.desc);
+       return code;
+}
+
+
+void glite_lbu_TimeToStrGeneric(time_t t, char **str, const char *amp) {
+       struct tm       *tm = gmtime(&t);
+
+       asprintf(str,"%s%4d-%02d-%02d %02d:%02d:%02d%s",amp,tm->tm_year+1900,tm->tm_mon+1,
+               tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec,amp);
+}
+
+
+void glite_lbu_TimeToStr(time_t t, char **str) {
+       glite_lbu_TimeToStrGeneric(t, str, "'");
+}
+
+
+void glite_lbu_TimestampToStrGeneric(double t, char **str, const char *amp) {
+       time_t tsec = t;
+       struct tm *tm = gmtime(&tsec);
+
+       t = t - tsec + tm->tm_sec;
+       asprintf(str,"%s%4d-%02d-%02d %02d:%02d:%02.09f%s",amp,tm->tm_year+1900,tm->tm_mon+1,
+                tm->tm_mday,tm->tm_hour,tm->tm_min,t,amp);
+}
+
+
+void glite_lbu_TimestampToStr(double t, char **str) {
+       glite_lbu_TimestampToStrGeneric(t, str, "'");
+}
+
+
+time_t glite_lbu_StrToTime(const char *str) {
+       struct tm       tm;
+
+       memset(&tm,0,sizeof(tm));
+       putenv("TZ=UTC"); tzset();
+       sscanf(str,"%4d-%02d-%02d %02d:%02d:%02d",
+               &tm.tm_year,&tm.tm_mon,&tm.tm_mday,
+               &tm.tm_hour,&tm.tm_min,&tm.tm_sec);
+       tm.tm_year -= 1900;
+       tm.tm_mon--;
+
+       return mktime(&tm);
+}
+
+
+double glite_lbu_StrToTimestamp(const char *str) {
+       struct tm       tm;
+       double  sec;
+
+       memset(&tm,0,sizeof(tm));
+       putenv("TZ=UTC"); tzset();
+       sscanf(str,"%4d-%02d-%02d %02d:%02d:%lf",
+               &tm.tm_year,&tm.tm_mon,&tm.tm_mday,
+               &tm.tm_hour,&tm.tm_min,&sec);
+       tm.tm_year -= 1900;
+       tm.tm_mon--;
+       tm.tm_sec = sec;
+
+       return (sec - tm.tm_sec) + mktime(&tm);
+}
+
+
+/* ---- API ---- */
+
+
+int glite_lbu_DBError(glite_lbu_DBContext ctx, char **text, char **desc) {
+       if (text) *text = strdup(strerror(ctx->err.code));
+       if (desc) {
+               if (ctx->err.desc) *desc = strdup(ctx->err.desc);
+               else *desc = NULL;
+       }
+
+       return ctx->err.code;
+}
+
+
+int glite_lbu_InitDBContext(glite_lbu_DBContext *ctx, int backend) {
+       int ret;
+
+       if (!VALID(backend)) return EINVAL;
+       if (backends[backend]->backend != backend) return ENOTSUP;
+       ret = backends[backend]->initContext(ctx);
+       if (ctx && *ctx) (*ctx)->backend = backend;
+       return ret;
+}
+
+
+void glite_lbu_FreeDBContext(glite_lbu_DBContext ctx) {
+       if (!ctx || !VALID(ctx->backend)) return;
+
+       free(ctx->err.desc);
+       ctx->err.desc = NULL;
+       backends[ctx->backend]->freeContext(ctx);
+}
+
+
+int glite_lbu_DBConnect(glite_lbu_DBContext ctx, const char *cs) {
+       if (!VALID(ctx->backend)) return EINVAL;
+       return backends[ctx->backend]->connect(ctx, cs);
+}
+
+
+void glite_lbu_DBClose(glite_lbu_DBContext ctx) {
+       if (!VALID(ctx->backend)) return;
+       backends[ctx->backend]->close(ctx);
+}
+
+
+int glite_lbu_DBQueryCaps(glite_lbu_DBContext ctx) {
+       if (!VALID(ctx->backend)) return EINVAL;
+       return backends[ctx->backend]->queryCaps(ctx);
+}
+
+
+void glite_lbu_DBSetCaps(glite_lbu_DBContext ctx, int caps) {
+       if (!VALID(ctx->backend)) return;
+       return backends[ctx->backend]->setCaps(ctx, caps);
+}
+
+
+int glite_lbu_Transaction(glite_lbu_DBContext ctx) {
+       if (!VALID(ctx->backend)) return EINVAL;
+       return backends[ctx->backend]->transaction(ctx);
+}
+
+
+int glite_lbu_Commit(glite_lbu_DBContext ctx) {
+       if (!VALID(ctx->backend)) return EINVAL;
+       return backends[ctx->backend]->commit(ctx);
+}
+
+
+int glite_lbu_Rollback(glite_lbu_DBContext ctx) {
+       if (!VALID(ctx->backend)) return EINVAL;
+       return backends[ctx->backend]->rollback(ctx);
+}
+
+
+int glite_lbu_FetchRow(glite_lbu_Statement stmt, unsigned int n, unsigned long *lengths, char **results) {
+       if (!VALID(stmt->ctx->backend)) return EINVAL;
+       return backends[stmt->ctx->backend]->fetchRow(stmt, n, lengths, results);
+}
+
+
+void glite_lbu_FreeStmt(glite_lbu_Statement *stmt) {
+       if (!stmt || !*stmt || !VALID((*stmt)->ctx->backend)) return;
+       return backends[(*stmt)->ctx->backend]->freeStmt(stmt);
+}
+
+
+int glite_lbu_QueryIndices(glite_lbu_DBContext ctx, const char *table, char ***key_names, char ****column_names) {
+       if (!VALID(ctx->backend)) return EINVAL;
+       return backends[ctx->backend]->queryIndices(ctx, table, key_names, column_names);
+}
+
+
+int glite_lbu_ExecSQL(glite_lbu_DBContext ctx, const char *cmd, glite_lbu_Statement *stmt) {
+       if (!VALID(ctx->backend)) return EINVAL;
+       return backends[ctx->backend]->execSQL(ctx, cmd, stmt);
+}
+
+
+int glite_lbu_QueryColumns(glite_lbu_Statement stmt, char **cols) {
+       if (!VALID(stmt->ctx->backend)) return EINVAL;
+       return backends[stmt->ctx->backend]->queryColumns(stmt, cols);
+}
+
+
+int glite_lbu_PrepareStmt(glite_lbu_DBContext ctx, const char *sql, glite_lbu_Statement *stmt) {
+       if (!VALID(ctx->backend)) return EINVAL;
+       return backends[ctx->backend]->prepareStmt(ctx, sql, stmt);
+}
+
+
+int glite_lbu_ExecPreparedStmt_v(glite_lbu_Statement stmt, int n, va_list ap) {
+       if (!VALID(stmt->ctx->backend)) return EINVAL;
+       return backends[stmt->ctx->backend]->execPreparedStmt_v(stmt, n, ap);
+}
+
+
+int glite_lbu_ExecPreparedStmt(glite_lbu_Statement stmt, int n, ...) {
+       va_list ap;
+       int retval;
+
+       va_start(ap, n);
+       retval = glite_lbu_ExecPreparedStmt_v(stmt, n, ap);
+       va_end(ap);
+
+       return retval;
+}
+
+
+long int glite_lbu_Lastid(glite_lbu_Statement stmt) {
+       if (!VALID(stmt->ctx->backend)) return EINVAL;
+       return backends[stmt->ctx->backend]->lastid(stmt);
+}
+
+
+void glite_lbu_TimeToDB(glite_lbu_DBContext ctx, time_t t, char **str) {
+       if (!VALID(ctx->backend)) return;
+       return backends[ctx->backend]->timeToDB(t, str);
+}
+
+
+void glite_lbu_TimestampToDB(glite_lbu_DBContext ctx, double t, char **str) {
+       if (!VALID(ctx->backend)) return;
+       return backends[ctx->backend]->timestampToDB(t, str);
+}
+
+
+time_t glite_lbu_DBToTime(glite_lbu_DBContext ctx, const char *str) {
+       if (!VALID(ctx->backend)) return (time_t)-1;
+       return backends[ctx->backend]->DBToTime(str);
+}
+
+
+double glite_lbu_DBToTimestamp(glite_lbu_DBContext ctx, const char *str) {
+       if (!VALID(ctx->backend)) return -1;
+       return backends[ctx->backend]->DBToTimestamp(str);
+}
+
+
+#define STATUS(CTX) ((CTX)->err.code)
+#define CLR_ERR(CTX) glite_lbu_DBClearError((CTX))
+int glite_lbu_bufferedInsertInit(glite_lbu_DBContext ctx, glite_lbu_bufInsert *bi, const char *table_name, long size_limit, long record_limit, const char *columns)
+{
+       *bi = calloc(1, sizeof(*bi));
+       (*bi)->ctx = ctx;
+       (*bi)->table_name = strdup(table_name);
+       (*bi)->columns = strdup(columns);
+       (*bi)->rec_num = 0;
+       (*bi)->rec_size = 0;
+       (*bi)->rows = calloc(record_limit, sizeof(*((*bi)->rows)) );
+       (*bi)->size_limit = size_limit;
+       (*bi)->record_limit = record_limit;
+
+        return CLR_ERR(ctx);
+}
+
+
+static int flush_bufferd_insert(glite_lbu_bufInsert bi)
+{
+       char *stmt, *vals, *temp;
+       long i;
+
+
+       if (!bi->rec_num)
+               return STATUS(bi->ctx);
+
+       asprintf(&vals,"(%s)", bi->rows[0]);
+       for (i=1; i < bi->rec_num; i++) {
+               // XXX:  use string add (preallocated memory)
+               asprintf(&temp,"%s,(%s)", vals, bi->rows[i]);
+               free(vals); vals = temp; temp = NULL;
+               free(bi->rows[i]);
+               bi->rows[i] = NULL;
+       }
+       
+       trio_asprintf(&stmt, "insert into %|Ss(%|Ss) values %s;",
+               bi->table_name, bi->columns, vals);
+
+       if (glite_lbu_ExecSQL(bi->ctx,stmt,NULL) < 0) {
+                if (STATUS(bi->ctx) == EEXIST)
+                        CLR_ERR(bi->ctx);
+        }
+
+       /* reset bi counters */
+       bi->rec_size = 0;
+       bi->rec_num = 0;
+       
+       free(vals);
+       free(stmt);
+
+       return STATUS(bi->ctx);
+}
+
+
+int glite_lbu_bufferedInsert(glite_lbu_bufInsert bi, const char *row)
+{
+       bi->rows[bi->rec_num++] = strdup(row);
+       bi->rec_size += strlen(row);
+
+       if ((bi->size_limit && bi->rec_size >= bi->size_limit) ||
+               (bi->record_limit && bi->rec_num >= bi->record_limit))
+       {
+               if (flush_bufferd_insert(bi))
+                       return STATUS(bi->ctx);
+       }
+
+       return CLR_ERR(bi->ctx);
+}
+
+
+static void free_buffered_insert(glite_lbu_bufInsert bi) {
+       long i;
+
+       free(bi->table_name);
+       free(bi->columns);
+       for (i=0; i < bi->rec_num; i++) {
+               free(bi->rows[i]);
+       }
+       free(bi->rows);
+}
+
+
+int glite_lbu_bufferedInsertClose(glite_lbu_bufInsert bi)
+{
+       if (flush_bufferd_insert(bi))
+               return STATUS(bi->ctx);
+       free_buffered_insert(bi);
+
+       return CLR_ERR(bi->ctx);
+}