*/
#include <sys/types.h>
+#include <assert.h>
+#include <dlfcn.h>
#include <errno.h>
+#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libpq-fe.h>
#include "glite/lbu/trio.h"
-#include "glite/lbu/db.h"
+#include "db.h"
+#include "db-int.h"
#define DB_CONNECT_TIMEOUT "20"
+#define LOG 1
#ifdef LOG
- #define lprintf(ARGS...) printf("[db-pg] %s: ", __FUNCTION__); printf(##ARGS)
+ #define lprintf(FMT...) fprintf(stdout, "[db-pg] %s: ", __FUNCTION__); fprintf(stdout, ##FMT);
#else
- #define lprintf(ARGS...)
+ #define lprintf(FMT...)
#endif
+#define set_error(CTX, CODE, DESC...) glite_lbu_DBSetError((glite_lbu_DBContext)(CTX), (CODE), __FUNCTION__, __LINE__, ##DESC)
-struct glite_lbu_DBContext_s {
- int caps;
- struct {
- int code;
- char *desc;
- } err;
+#define LOAD(SYM, SYM2) if ((*(void **)(&psql_module.SYM) = dlsym(psql_module.lib, SYM2)) == NULL) { \
+ err = set_error(ctx, ENOENT, "can't load symbol '%s' from psql library (%s)", SYM2, dlerror()); \
+ break; \
+}
+
+
+struct glite_lbu_DBContextPsql_s {
+ struct glite_lbu_DBContext_s generic;
PGconn *conn;
int prepared_counts[4];
};
+typedef struct glite_lbu_DBContextPsql_s *glite_lbu_DBContextPsql;
-struct glite_lbu_Statement_s {
- glite_lbu_DBContext ctx;
+struct glite_lbu_StatementPsql_s {
+ glite_lbu_Statement_t generic;
PGresult *res;
int row, nrows;
char *sql, *name;
};
+typedef struct glite_lbu_StatementPsql_s *glite_lbu_StatementPsql;
+
+typedef struct {
+ void *lib;
+ pthread_mutex_t lock;
+
+ /* functions from 8.3.8 client library version (libpq-fe.h) */
+ PGconn *(*PQconnectdb)(const char *conninfo);
+ ConnStatusType (*PQstatus)(const PGconn *conn);
+ void (*PQfinish)(PGconn *conn);
+ char *(*PQerrorMessage)(const PGconn *conn);
+ int (*PQnfields)(const PGresult *res);
+ char *(*PQgetvalue)(const PGresult *res, int tup_num, int field_num);
+ int (*PQgetlength)(const PGresult *res, int tup_num, int field_num);
+ void (*PQclear)(PGresult *res);
+ PGresult *(*PQexec)(PGconn *conn, const char *query);
+ ExecStatusType (*PQresultStatus)(const PGresult *res);
+ char *(*PQresultErrorMessage)(const PGresult *res);
+ char *(*PQcmdTuples)(PGresult *res);
+ int (*PQntuples)(const PGresult *res);
+ char *(*PQfname)(const PGresult *res, int field_num);
+ unsigned char *(*PQescapeByteaConn)(PGconn *conn,
+ const unsigned char *from, size_t from_length,
+ size_t *to_length);
+ unsigned char *(*PQunescapeBytea)(const unsigned char *strtext,
+ size_t *retbuflen);
+ void (*PQfreemem)(void *ptr);
+} psql_module_t;
+
+
+static void glite_lbu_DBCleanup(void);
+
+/* backend module declaration */
+int glite_lbu_InitDBContextPsql(glite_lbu_DBContext *ctx_gen);
+void glite_lbu_FreeDBContextPsql(glite_lbu_DBContext ctx_gen);
+int glite_lbu_DBConnectPsql(glite_lbu_DBContext ctx_gen, const char *cs);
+void glite_lbu_DBClosePsql(glite_lbu_DBContext ctx_gen);
+int glite_lbu_DBQueryCapsPsql(glite_lbu_DBContext ctx_gen);
+void glite_lbu_DBSetCapsPsql(glite_lbu_DBContext commmon_ctx, int caps);
+int glite_lbu_TransactionPsql(glite_lbu_DBContext ctx_gen);
+int glite_lbu_CommitPsql(glite_lbu_DBContext ctx_gen);
+int glite_lbu_RollbackPsql(glite_lbu_DBContext ctx_gen);
+int glite_lbu_FetchRowPsql(glite_lbu_Statement stmt, unsigned int n, unsigned long *lengths, char **results);
+void glite_lbu_FreeStmtPsql(glite_lbu_Statement *stmt);
+//int glite_lbu_QueryIndicesPsql(glite_lbu_DBContext ctx_gen, const char *table, char ***key_names, char ****column_names);
+int glite_lbu_ExecSQLPsql(glite_lbu_DBContext ctx_gen, const char *cmd, glite_lbu_Statement *stmt);
+int glite_lbu_QueryColumnsPsql(glite_lbu_Statement stmt_gen, char **cols);
+int glite_lbu_PrepareStmtPsql(glite_lbu_DBContext ctx_gen, const char *sql, glite_lbu_Statement *stmt_gen);
+int glite_lbu_ExecPreparedStmtPsql_v(glite_lbu_Statement stmt_gen, int n, va_list ap);
+//long int glite_lbu_LastidPsql(glite_lbu_Statement stmt_gen);
+
+glite_lbu_DBBackend_t psql_backend = {
+ backend: GLITE_LBU_DB_BACKEND_PSQL,
+
+ initContext: glite_lbu_InitDBContextPsql,
+ freeContext: glite_lbu_FreeDBContextPsql,
+ connect: glite_lbu_DBConnectPsql,
+ close: glite_lbu_DBClosePsql,
+ queryCaps: glite_lbu_DBQueryCapsPsql,
+ setCaps: glite_lbu_DBSetCapsPsql,
+ transaction: glite_lbu_TransactionPsql,
+ commit: glite_lbu_CommitPsql,
+ rollback: glite_lbu_RollbackPsql,
+ fetchRow: glite_lbu_FetchRowPsql,
+ freeStmt: glite_lbu_FreeStmtPsql,
+ queryIndices: NULL /*glite_lbu_QueryIndicesPsql*/,
+ execSQL: glite_lbu_ExecSQLPsql,
+ queryColumns: glite_lbu_QueryColumnsPsql,
+
+ timeToDB: glite_lbu_TimeToStr,
+ timestampToDB: glite_lbu_TimestampToStr,
+ DBToTime: glite_lbu_StrToTime,
+ DBToTimestamp: glite_lbu_StrToTimestamp,
+
+ prepareStmt: glite_lbu_PrepareStmtPsql,
+ execPreparedStmt_v: glite_lbu_ExecPreparedStmtPsql_v,
+ lastid: NULL/*glite_lbu_LastidPsql*/,
+};
+
+static psql_module_t psql_module = {
+ lib: NULL,
+ lock: PTHREAD_MUTEX_INITIALIZER,
+};
/* nicer identifiers in PREPARE/EXECUTE commands */
static const char *prepared_names[4] = {"select", "update", "insert", "other"};
-//static void time2str(time_t, char **str);
-
-
-#define set_error(CTX, CODE, DESC) set_error_func((CTX), (CODE), (DESC), __FUNCTION__, __LINE__)
-static int set_error_func(glite_lbu_DBContext ctx, int code, const char *desc, const char *func, int line) {
- char *pos;
-
- if (ctx->err.desc) free(ctx->err.desc);
- ctx->err.code = code;
- ctx->err.desc = strdup(desc ? desc : "(null)");
- pos = strrchr(desc, '\n'); if (pos) pos[0] = '\0';
-
- if ((ctx->caps & GLITE_LBU_DB_CAP_ERRORS) != 0) fprintf(stderr, "[db %d] %s:%d %s\n", getpid(), func, line, desc);
- return code;
-}
-
-
-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) {
- *ctx = calloc(1, sizeof **ctx);
- if (!*ctx) return ENOMEM;
+int glite_lbu_InitDBContextPsql(glite_lbu_DBContext *ctx_gen) {
+ glite_lbu_DBContextPsql ctx;
+ int err = 0;
+
+ ctx = calloc(1, sizeof *ctx);
+ if (!ctx) return ENOMEM;
+ *ctx_gen = (glite_lbu_DBContext)ctx;
+
+ /* dynamic load of the client library */
+ pthread_mutex_lock(&psql_module.lock);
+ if (!psql_module.lib) {
+ psql_module.lib = dlopen(PSQL_SONAME, RTLD_LAZY | RTLD_LOCAL);
+ if (!psql_module.lib) return set_error(ctx, ENOENT, "dlopen(): " PSQL_SONAME ": %s", dlerror());
+ do {
+ LOAD(PQconnectdb, "PQconnectdb");
+ LOAD(PQstatus, "PQstatus");
+ LOAD(PQfinish, "PQfinish");
+ LOAD(PQerrorMessage, "PQerrorMessage");
+ LOAD(PQnfields, "PQnfields");
+ LOAD(PQgetvalue, "PQgetvalue");
+ LOAD(PQgetlength, "PQgetlength");
+ LOAD(PQclear, "PQclear");
+ LOAD(PQexec, "PQexec");
+ LOAD(PQresultStatus, "PQresultStatus");
+ LOAD(PQresultErrorMessage, "PQresultErrorMessage");
+ LOAD(PQcmdTuples, "PQcmdTuples");
+ LOAD(PQntuples, "PQntuples");
+ LOAD(PQfname, "PQfname");
+ LOAD(PQescapeByteaConn, "PQescapeByteaConn");
+ LOAD(PQunescapeBytea, "PQunescapeBytea");
+ LOAD(PQfreemem, "PQfreemem");
+
+ pthread_mutex_unlock(&psql_module.lock);
+ atexit(glite_lbu_DBCleanup);
+ } while(0);
+
+ if (err) {
+ dlclose(psql_module.lib);
+ psql_module.lib = NULL;
+ pthread_mutex_unlock(&psql_module.lock);
+ return err;
+ }
+ } else pthread_mutex_unlock(&psql_module.lock);
return 0;
}
-void glite_lbu_FreeDBContext(glite_lbu_DBContext ctx) {
+void glite_lbu_FreeDBContextPsql(glite_lbu_DBContext ctx_gen) {
+ glite_lbu_DBContextPsql ctx = (glite_lbu_DBContextPsql)ctx_gen;
+
if (ctx) {
- free(ctx->err.desc);
+ assert(ctx->conn == NULL);
free(ctx);
}
}
-int glite_lbu_DBConnect(glite_lbu_DBContext ctx, const char *cs) {
+int glite_lbu_DBConnectPsql(glite_lbu_DBContext ctx_gen, const char *cs) {
+ glite_lbu_DBContextPsql ctx = (glite_lbu_DBContextPsql)ctx_gen;
char *buf, *slash, *at, *colon, *host, *user, *pw, *db, *pgcsbuf, *pgcs;
char *err;
free(buf);
lprintf("connection string = %s\n", pgcs);
- ctx->conn = PQconnectdb(pgcs);
+ ctx->conn = psql_module.PQconnectdb(pgcs);
free(pgcsbuf);
if (!ctx->conn) return ENOMEM;
- if (PQstatus(ctx->conn) != CONNECTION_OK) {
- asprintf(&err, "Can't connect, %s", PQerrorMessage(ctx->conn));
- PQfinish(ctx->conn);
+ if (psql_module.PQstatus(ctx->conn) != CONNECTION_OK) {
+ asprintf(&err, "Can't connect, %s", psql_module.PQerrorMessage(ctx->conn));
+ psql_module.PQfinish(ctx->conn);
ctx->conn = NULL;
set_error(ctx, EIO, err);
free(err);
- return ctx->err.code;
+ return EIO;
}
return 0;
}
-void glite_lbu_DBClose(glite_lbu_DBContext ctx) {
- if (ctx->conn) PQfinish(ctx->conn);
+void glite_lbu_DBClosePsql(glite_lbu_DBContext ctx_gen) {
+ glite_lbu_DBContextPsql ctx = (glite_lbu_DBContextPsql)ctx_gen;
+
+ if (ctx->conn) {
+ psql_module.PQfinish(ctx->conn);
+ ctx->conn = NULL;
+ }
}
-int glite_lbu_DBQueryCaps(glite_lbu_DBContext ctx) {
+int glite_lbu_DBQueryCapsPsql(glite_lbu_DBContext ctx_gen) {
+ glite_lbu_DBContextPsql ctx = (glite_lbu_DBContextPsql)ctx_gen;
glite_lbu_Statement stmt;
int major, minor, sub, version;
int has_prepared = 0;
char *res = NULL;
- if (glite_lbu_ExecSQL(ctx, "SHOW server_version", &stmt) == -1) return -1;
- switch (glite_lbu_FetchRow(stmt, 1, NULL, &res)) {
+ if (glite_lbu_ExecSQLPsql(ctx_gen, "SHOW server_version", &stmt) == -1) return -1;
+ switch (glite_lbu_FetchRowPsql(stmt, 1, NULL, &res)) {
case 1:
break;
case -1:
quit:
free(res);
- glite_lbu_FreeStmt(&stmt);
+ glite_lbu_FreeStmtPsql(&stmt);
return has_prepared;
}
-void glite_lbu_DBSetCaps(glite_lbu_DBContext ctx, int caps) {
- ctx->caps = caps;
+void glite_lbu_DBSetCapsPsql(glite_lbu_DBContext ctx_gen, int caps) {
+ ctx_gen->caps = caps;
}
-int glite_lbu_Transaction(glite_lbu_DBContext ctx) {
+int glite_lbu_TransactionPsql(glite_lbu_DBContext ctx_gen __attribute((unused))) {
return 0;
}
-int glite_lbu_Commit(glite_lbu_DBContext ctx) {
+int glite_lbu_CommitPsql(glite_lbu_DBContext ctx_gen __attribute((unused))) {
return 0;
}
-int glite_lbu_Rollback(glite_lbu_DBContext ctx) {
+int glite_lbu_RollbackPsql(glite_lbu_DBContext ctx_gen __attribute((unused))) {
return 0;
}
-int glite_lbu_FetchRow(glite_lbu_Statement stmt, unsigned int maxn, unsigned long *lengths, char **results) {
+int glite_lbu_FetchRowPsql(glite_lbu_Statement stmt_gen, unsigned int maxn, unsigned long *lengths, char **results) {
+ glite_lbu_StatementPsql stmt = (glite_lbu_StatementPsql)stmt_gen;
unsigned int i, n;
if (stmt->row >= stmt->nrows) return 0;
- n = PQnfields(stmt->res);
+ n = psql_module.PQnfields(stmt->res);
if (n <= 0) {
- set_error(stmt->ctx, EINVAL, "Result set w/o columns");
+ set_error(stmt->generic.ctx, EINVAL, "Result set w/o columns");
return -1;
}
if (n > maxn) {
- set_error(stmt->ctx, EINVAL, "Not enough room for the result");
+ set_error(stmt->generic.ctx, EINVAL, "Not enough room for the result");
return -1;
}
for (i = 0; i < n; i++) {
- results[i] = PQgetvalue(stmt->res, stmt->row, i);
+ results[i] = psql_module.PQgetvalue(stmt->res, stmt->row, i);
/* sanity check for internal error (NULL when invalid row) */
results[i] = strdup(results[i] ? : "");
- if (lengths) lengths[i] = PQgetlength(stmt->res, stmt->row, i);
+ if (lengths) lengths[i] = psql_module.PQgetlength(stmt->res, stmt->row, i);
}
stmt->row++;
}
-void glite_lbu_FreeStmt(glite_lbu_Statement *stmt) {
+void glite_lbu_FreeStmtPsql(glite_lbu_Statement *stmt_gen) {
+ glite_lbu_DBContextPsql ctx;
+ glite_lbu_StatementPsql stmt;
char *sql;
- if (!*stmt) return;
- if ((*stmt)->res) PQclear((*stmt)->res);
- if ((*stmt)->name) {
- asprintf(&sql, "DEALLOCATE %s", (*stmt)->name);
- (*stmt)->res = PQexec((*stmt)->ctx->conn, sql);
+ if (!*stmt_gen) return;
+ stmt = (glite_lbu_StatementPsql)(*stmt_gen);
+ ctx = (glite_lbu_DBContextPsql)stmt->generic.ctx;
+ if (stmt->res) psql_module.PQclear(stmt->res);
+ if (stmt->name) {
+ asprintf(&sql, "DEALLOCATE %s", stmt->name);
+ stmt->res = psql_module.PQexec(ctx->conn, sql);
free(sql);
- PQclear((*stmt)->res);
+ psql_module.PQclear(stmt->res);
}
- free((*stmt)->name);
- free((*stmt)->sql);
- free(*stmt);
- *stmt = NULL;
+ free(stmt->name);
+ free(stmt->sql);
+ free(stmt);
+ *stmt_gen = NULL;
}
-int glite_lbu_ExecSQL(glite_lbu_DBContext ctx, const char *cmd, glite_lbu_Statement *stmt_out) {
- glite_lbu_Statement stmt = NULL;
+int glite_lbu_ExecSQLPsql(glite_lbu_DBContext ctx_gen, const char *cmd, glite_lbu_Statement *stmt_out) {
+ glite_lbu_DBContextPsql ctx = (glite_lbu_DBContextPsql)ctx_gen;
+ glite_lbu_StatementPsql stmt = NULL;
int status, n;
- char *nstr;
+ char *nstr, *errmsg, *pos;
PGresult *res;
lprintf("command = %s\n", cmd);
if (stmt_out) *stmt_out = NULL;
- if ((res = PQexec(ctx->conn, cmd)) == NULL) {
- ctx->err.code = ENOMEM;
+ if ((res = psql_module.PQexec(ctx->conn, cmd)) == NULL) {
+ ctx->generic.err.code = ENOMEM;
return -1;
}
- status = PQresultStatus(res);
+ status = psql_module.PQresultStatus(res);
if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) {
- set_error(ctx, EIO, PQresultErrorMessage(res));
- PQclear(res);
+ errmsg = psql_module.PQresultErrorMessage(res);
+ if (errmsg) {
+ errmsg = strdup(errmsg);
+ if ((pos = strrchr(errmsg, '\n')) != NULL) pos[0] = '\0';
+ }
+ set_error(ctx, EIO, errmsg);
+ free(errmsg);
+ psql_module.PQclear(res);
return -1;
}
- nstr = PQcmdTuples(res);
+ nstr = psql_module.PQcmdTuples(res);
if (nstr && nstr[0]) n = atoi(nstr);
- else n = PQntuples(res);
+ else n = psql_module.PQntuples(res);
if (stmt_out) {
stmt = calloc(1, sizeof(*stmt));
- stmt->ctx = ctx;
+ stmt->generic.ctx = ctx_gen;
stmt->res = res;
stmt->nrows = n;
- *stmt_out = stmt;
+ *stmt_out = (glite_lbu_Statement)stmt;
} else {
- PQclear(res);
+ psql_module.PQclear(res);
}
return n;
}
-int glite_lbu_QueryColumns(glite_lbu_Statement stmt, char **cols) {
+int glite_lbu_QueryColumnsPsql(glite_lbu_Statement stmt_gen, char **cols) {
+ glite_lbu_StatementPsql stmt = (glite_lbu_StatementPsql)stmt_gen;
int n, i;
- n = PQnfields(stmt->res);
+ n = psql_module.PQnfields(stmt->res);
for (i = 0; i < n; i++) {
- cols[i] = PQfname(stmt->res, i);
+ cols[i] = psql_module.PQfname(stmt->res, i);
}
return -1;
}
-#if 0
-static void time2str(time_t t, char **str) {
- struct tm *tm = gmtime(&t);
-
- asprintf(str,"%4d-%02d-%02d %02d:%02d:%02d",tm->tm_year+1900,tm->tm_mon+1,
- tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec);
-}
-#endif
-
-
-void glite_lbu_TimeToDB(time_t t, char **str) {
- struct tm *tm = gmtime(&t);
-
- asprintf(str,"'%4d-%02d-%02d %02d:%02d:%02d'",tm->tm_year+1900,tm->tm_mon+1,
- tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec);
-}
-
-
-void glite_lbu_TimestampToDB(double t, char **str) {
- time_t tsec = t;
- struct tm *tm = gmtime(&tsec);
-
- t = t - tsec + tm->tm_sec;
- asprintf(str,"'%4d-%02d-%02d %02d:%02d:%02.09f'",tm->tm_year+1900,tm->tm_mon+1,
- tm->tm_mday,tm->tm_hour,tm->tm_min,t);
-}
-
-
-time_t glite_lbu_DBToTime(const char *str) {
- struct tm tm;
-
- memset(&tm,0,sizeof(tm));
- setenv("TZ","UTC",1); 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);
-}
-
-
-/*
-int glite_lbu_QueryIndices(glite_lbu_DBContext ctx, const char *table, char ***key_names, char ****column_names) { }
-long int glite_lbu_Lastid(glite_lbu_Statement stmt) {}
-*/
-
-
-int glite_lbu_PrepareStmt(glite_lbu_DBContext ctx, const char *sql, glite_lbu_Statement *stmtout) {
+int glite_lbu_PrepareStmtPsql(glite_lbu_DBContext ctx_gen, const char *sql, glite_lbu_Statement *stmt_out) {
+ glite_lbu_DBContextPsql ctx = (glite_lbu_DBContextPsql)ctx_gen;
int i, retval = -1;
const char *selectp, *updatep, *insertp, *minp;
char *sqlPrep = NULL, *s = NULL;
- glite_lbu_Statement stmt;
+ glite_lbu_StatementPsql stmt;
PGresult *res = NULL;
// init
stmt = calloc(1, sizeof(*stmt));
- stmt->ctx = ctx;
+ stmt->generic.ctx = ctx_gen;
stmt->sql = strdup(sql);
// name of the prepared command used as ID in postgres
if (updatep && updatep < minp) { minp = updatep; i = 1; }
if (insertp && insertp < minp) { minp = insertp; i = 2; }
if (i == -1 || minp[0] == '\0') i = 3;
- asprintf(&stmt->name, "%s%d", prepared_names[i], ++stmt->ctx->prepared_counts[i]);
+ asprintf(&stmt->name, "%s%d", prepared_names[i], ++ctx->prepared_counts[i]);
asprintf(&sqlPrep, "PREPARE %s AS %s", stmt->name, stmt->sql);
lprintf("prepare = %s\n", sqlPrep);
- res = PQexec(stmt->ctx->conn, sqlPrep);
- if (PQresultStatus(res) != PGRES_COMMAND_OK) {
- asprintf(&s, "error preparing command: %s", PQerrorMessage(stmt->ctx->conn));
- set_error(stmt->ctx, EIO, s);
+ res = psql_module.PQexec(ctx->conn, sqlPrep);
+ if (psql_module.PQresultStatus(res) != PGRES_COMMAND_OK) {
+ asprintf(&s, "error preparing command: %s", psql_module.PQerrorMessage(ctx->conn));
+ set_error(ctx, EIO, s);
free(s); s = NULL;
goto quit;
}
- *stmtout = stmt;
+ *stmt_out = (glite_lbu_Statement)stmt;
retval = 0;
quit:
free(sqlPrep);
- if (res) PQclear(res);
+ if (res) psql_module.PQclear(res);
if (!retval) return 0;
free(stmt->name);
}
-int glite_lbu_ExecPreparedStmt_v(glite_lbu_Statement stmt, int n, va_list ap) {
+int glite_lbu_ExecPreparedStmtPsql_v(glite_lbu_Statement stmt_gen, int n, va_list ap) {
+ glite_lbu_StatementPsql stmt = (glite_lbu_StatementPsql)stmt_gen;
+ glite_lbu_DBContextPsql ctx = (glite_lbu_DBContextPsql)stmt_gen->ctx;
int i, retval = -1, status;
char **tmpdata = NULL;
char *sql = NULL, *s, *nstr;
glite_lbu_DBType type;
if (!stmt || !stmt->sql || !stmt->name)
- return set_error(stmt->ctx, EINVAL, "PrepareStmt() not called");
+ return set_error(ctx, EINVAL, "PrepareStmt() not called");
if (stmt->res) {
- PQclear(stmt->res);
+ psql_module.PQclear(stmt->res);
stmt->res = NULL;
}
s = (unsigned char *)va_arg(ap, char *);
binary_len = va_arg(ap, unsigned long);
+ lprintf("blob, len = %lu, ptr = %p\n", binary_len, s);
if (s) {
- tmp = PQescapeByteaConn(stmt->ctx->conn, s, binary_len, &result_len);
+ tmp = psql_module.PQescapeByteaConn(ctx->conn, s, binary_len, &result_len);
asprintf(&tmpdata[i], "'%s'", tmp);
- PQfreemem(tmp);
+ lprintf("escaped: '%s'\n", tmpdata[i]);
+ psql_module.PQfreemem(tmp);
} else
tmpdata[i] = strdup("NULL");
break;
case GLITE_LBU_DB_TYPE_DATE:
case GLITE_LBU_DB_TYPE_TIME:
case GLITE_LBU_DB_TYPE_DATETIME:
- glite_lbu_TimeToDB(va_arg(ap, time_t), &tmpdata[i]);
+ glite_lbu_TimeToStr(va_arg(ap, time_t), &tmpdata[i]);
break;
case GLITE_LBU_DB_TYPE_TIMESTAMP:
- glite_lbu_TimestampToDB(va_arg(ap, double), &tmpdata[i]);
+ glite_lbu_TimestampToStr(va_arg(ap, double), &tmpdata[i]);
break;
case GLITE_LBU_DB_TYPE_NULL:
default:
lprintf("unknown type %d\n", type);
- set_error(stmt->ctx, EINVAL, "unimplemented type");
+ set_error(ctx, EINVAL, "unimplemented type");
goto quit;
}
if (n) strcat(sql, ")");
lprintf("exec prepared: n = %d, sql = '%s'\n", n, sql);
- stmt->res = PQexec(stmt->ctx->conn, sql);
- status = PQresultStatus(stmt->res);
+ stmt->res = psql_module.PQexec(ctx->conn, sql);
+ status = psql_module.PQresultStatus(stmt->res);
if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) {
- asprintf(&s, "error executing prepared command '%s' parameters '%s': %s", stmt->sql, sql, PQerrorMessage(stmt->ctx->conn));
- set_error(stmt->ctx, EIO, s);
+ asprintf(&s, "error executing prepared command '%s' parameters '%s': %s", stmt->sql, sql, psql_module.PQerrorMessage(ctx->conn));
+ set_error(ctx, EIO, s);
free(s); s = NULL;
goto quit;
}
- nstr = PQcmdTuples(stmt->res);
+ nstr = psql_module.PQcmdTuples(stmt->res);
//lprintf("cmdtuples: '%s'\n", nstr);
if (nstr && nstr[0]) retval = atoi(nstr);
- else retval = PQntuples(stmt->res);
+ else retval = psql_module.PQntuples(stmt->res);
stmt->nrows = retval;
stmt->row = 0;
//lprintf("ntuples/retval: %d\n", retval);
}
-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;
-}
-
-
-/*
-struct glite_lbu_bufInsert_s {
- glite_lbu_DBContext ctx;
+static void glite_lbu_DBCleanup(void) {
+ pthread_mutex_lock(&psql_module.lock);
+ if (psql_module.lib) {
+ dlclose(psql_module.lib);
+ psql_module.lib = NULL;
+ }
+ pthread_mutex_unlock(&psql_module.lock);
}
-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)
-{}
-int glite_lbu_bufferedInsert(glite_lbu_bufInsert bi, const char *row) {}
-int glite_lbu_bufferedInsertClose(glite_lbu_bufInsert bi) {}
-*/