+++ /dev/null
-#ifdef WIN32
-#define asprintf(STR, FMT...) trio_asprintf((STR), ##FMT)
-#define vasprintf(STR, FMT, VARGS) trio_asprintf((STR), (FMT), (VARGS))
-#define strcasestr(H,N) strstr((H), (N))
-#endif
-
-#define dprintf(CTX, FMT...) if ((CTX)->caps & GLITE_LBU_DB_CAP_ERRORS) fprintf(stderr, ##FMT)
-
-struct glite_lbu_DBContext_s {
- int backend;
- struct {
- int code;
- char *desc;
- } err;
- int caps;
-};
-typedef struct glite_lbu_DBContext_s glite_lbu_DBContext_t;
-
-struct glite_lbu_Statement_s {
- glite_lbu_DBContext ctx;
-};
-typedef struct glite_lbu_Statement_s glite_lbu_Statement_t;
-
-
-
-typedef struct {
- int backend;
-
- int (*initContext)(glite_lbu_DBContext *ctx);
- void (*freeContext)(glite_lbu_DBContext ctx);
- int (*connect)(glite_lbu_DBContext ctx, const char *cs);
- void (*close)(glite_lbu_DBContext ctx);
- int (*queryCaps)(glite_lbu_DBContext ctx);
- void (*setCaps)(glite_lbu_DBContext ctx, int caps);
-
- int (*transaction)(glite_lbu_DBContext ctx);
- int (*commit)(glite_lbu_DBContext ctx);
- int (*rollback)(glite_lbu_DBContext ctx);
-
- int (*fetchRow)(glite_lbu_Statement stmt, unsigned int n, unsigned long *lengths, char **results);
- void (*freeStmt)(glite_lbu_Statement *stmt);
-
- int (*queryIndices)(glite_lbu_DBContext ctx, const char *table, char ***key_names, char ****column_names);
- int (*execSQL)(glite_lbu_DBContext ctx, const char *cmd, glite_lbu_Statement *stmt);
- int (*queryColumns)(glite_lbu_Statement stmt_gen, char **cols);
-
- int (*prepareStmt)(glite_lbu_DBContext ctx, const char *sql, glite_lbu_Statement *stmt);
- int (*execPreparedStmt_v)(glite_lbu_Statement stmt, int n, va_list ap);
- long int (*lastid)(glite_lbu_Statement stmt);
-
- void (*timeToDB)(time_t, char **str);
- void (*timestampToDB)(double t, char **str);
- time_t (*DBToTime)(const char *str);
- double (*DBToTimestamp)(const char *str);
-} glite_lbu_DBBackend_t;
-
-int glite_lbu_DBSetError(glite_lbu_DBContext ctx, int code, const char *func, int line, const char *desc, ...);
-
-void glite_lbu_TimeToStrGeneric(time_t t, char **str, const char *amp);
-void glite_lbu_TimestampToStrGeneric(double t, char **str, const char *amp);
+++ /dev/null
-#include <sys/types.h>
-#ifdef LBS_DB_PROFILE
-#include <sys/time.h>
-#endif
-#include <unistd.h>
-#include <time.h>
-#include <assert.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <dlfcn.h>
-#include <pthread.h>
-#ifdef HAVE_SYSLOG_H
-#include <syslog.h>
-#endif
-
-#ifdef WIN32
-#include <windows.h>
-#ifndef STDCALL
-#define STDCALL __stdcall
-#endif
-#else
-#define STDCALL
-#endif
-
-#include <mysql.h>
-#include <mysqld_error.h>
-#include <mysql_version.h>
-#include <errmsg.h>
-
-#include "glite/lbu/trio.h"
-#include "db.h"
-#include "db-int.h"
-
-
-#define GLITE_LBU_MYSQL_INDEX_VERSION 40001
-#define GLITE_LBU_MYSQL_PREPARED_VERSION 40102
-#define BUF_INSERT_ROW_ALLOC_BLOCK 1000
-#ifndef GLITE_LBU_DEFAULT_RESULT_BUFFER_LENGTH
-#define GLITE_LBU_DEFAULT_RESULT_BUFFER_LENGTH 256
-#endif
-
-#define CLR_ERR(CTX) glite_lbu_DBClearError((glite_lbu_DBContext)(CTX))
-#define ERR(CTX, CODE, ARGS...) glite_lbu_DBSetError((glite_lbu_DBContext)((CTX)), (CODE), __FUNCTION__, __LINE__, ##ARGS)
-#define STATUS(CTX) glite_lbu_DBError((glite_lbu_DBContext)((CTX)), NULL, NULL)
-#define MY_ERR(CTX) myerr((CTX), __FUNCTION__, __LINE__)
-#define MY_ERRSTMT(STMT) myerrstmt((STMT), __FUNCTION__, __LINE__)
-#define MY_ISOKSTMT(STMT, RETRY) myisokstmt((STMT), __FUNCTION__, __LINE__, (RETRY))
-
-#define USE_TRANS(CTX) ((CTX->generic.caps & GLITE_LBU_DB_CAP_TRANSACTIONS) != 0)
-#define LOAD(SYM, SYM2) if ((*(void **)(&mysql_module.SYM) = dlsym(mysql_module.lib, SYM2)) == NULL) { \
- err = ERR(ctx, ENOENT, "can't load symbol '%s' from mysql library (%s)", SYM2, dlerror()); \
- break; \
-}
-
-
-
-struct glite_lbu_DBContextMysql_s {
- struct glite_lbu_DBContext_s generic;
- int in_transaction; /* this flag is set whenever we are in DB transaction */
- MYSQL *mysql;
-};
-typedef struct glite_lbu_DBContextMysql_s *glite_lbu_DBContextMysql;
-
-
-struct glite_lbu_StatementMysql_s {
- glite_lbu_Statement_t generic;
-
- /* for simple commands */
- MYSQL_RES *result;
-
- /* for prepared commands */
- MYSQL_STMT *stmt;
- unsigned long nrfields;
- char *sql;
-};
-typedef struct glite_lbu_StatementMysql_s *glite_lbu_StatementMysql;
-
-
-/*
- * mapping glite DB types to mysql types
- */
-int glite_type_to_mysql[] = {
- MYSQL_TYPE_NULL,
- MYSQL_TYPE_TINY,
- MYSQL_TYPE_LONG,
- MYSQL_TYPE_TINY_BLOB,
- MYSQL_TYPE_TINY_BLOB,
- MYSQL_TYPE_BLOB,
- MYSQL_TYPE_BLOB,
- MYSQL_TYPE_MEDIUM_BLOB,
- MYSQL_TYPE_MEDIUM_BLOB,
- MYSQL_TYPE_LONG_BLOB,
- MYSQL_TYPE_LONG_BLOB,
- MYSQL_TYPE_VAR_STRING,
- MYSQL_TYPE_STRING,
- MYSQL_TYPE_DATE,
- MYSQL_TYPE_TIME,
- MYSQL_TYPE_DATETIME,
- MYSQL_TYPE_TIMESTAMP,
-};
-
-
-typedef struct {
- void *lib;
- pthread_mutex_t lock;
-
- void * STDCALL(*mysql_init)(void *);
- unsigned long STDCALL(*mysql_get_client_version)(void);
- int STDCALL(*mysql_options)(MYSQL *mysql, enum mysql_option option, const char *arg);
- unsigned int STDCALL(*mysql_errno)(MYSQL *mysql);
- const char *STDCALL(*mysql_error)(MYSQL *mysql);
- unsigned int STDCALL(*mysql_stmt_errno)(MYSQL_STMT *stmt);
- const char *STDCALL(*mysql_stmt_error)(MYSQL_STMT *stmt);
- MYSQL * STDCALL(*mysql_real_connect)(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag);
- void STDCALL(*mysql_close)(MYSQL *mysql);
- int STDCALL(*mysql_query)(MYSQL *mysql, const char *stmt_str);
- MYSQL_RES *STDCALL(*mysql_store_result)(MYSQL *mysql);
- void STDCALL(*mysql_free_result)(MYSQL_RES *result);
- my_ulonglong STDCALL(*mysql_affected_rows)(MYSQL *mysql);
- my_bool STDCALL(*mysql_stmt_close)(MYSQL_STMT *);
- unsigned int STDCALL(*mysql_num_fields)(MYSQL_RES *result);
- unsigned long *STDCALL(*mysql_fetch_lengths)(MYSQL_RES *result);
- my_bool STDCALL(*mysql_stmt_bind_result)(MYSQL_STMT *stmt, MYSQL_BIND *bind);
- int STDCALL(*mysql_stmt_prepare)(MYSQL_STMT *stmt, const char *stmt_str, unsigned long length);
- int STDCALL(*mysql_stmt_store_result)(MYSQL_STMT *stmt);
- MYSQL_ROW STDCALL(*mysql_fetch_row)(MYSQL_RES *result);
- MYSQL_FIELD *STDCALL(*mysql_fetch_field)(MYSQL_RES *result);
- const char *STDCALL(*mysql_get_server_info)(MYSQL *mysql);
- MYSQL_STMT *STDCALL(*mysql_stmt_init)(MYSQL *mysql);
- my_bool STDCALL(*mysql_stmt_bind_param)(MYSQL_STMT *stmt, MYSQL_BIND *bind);
- int STDCALL(*mysql_stmt_execute)(MYSQL_STMT *stmt);
- int STDCALL(*mysql_stmt_fetch)(MYSQL_STMT *stmt);
- my_ulonglong STDCALL(*mysql_stmt_insert_id)(MYSQL_STMT *stmt);
- my_ulonglong STDCALL(*mysql_stmt_affected_rows)(MYSQL_STMT *stmt);
- MYSQL_RES *STDCALL(*mysql_stmt_result_metadata)(MYSQL_STMT *stmt);
- int STDCALL(*mysql_stmt_fetch_column)(MYSQL_STMT *stmt, MYSQL_BIND *bind, unsigned int column, unsigned long offset);
-} mysql_module_t;
-
-
-/* backend module declaration */
-int glite_lbu_InitDBContextMysql(glite_lbu_DBContext *ctx_gen);
-void glite_lbu_FreeDBContextMysql(glite_lbu_DBContext ctx_gen);
-int glite_lbu_DBConnectMysql(glite_lbu_DBContext ctx_gen, const char *cs);
-void glite_lbu_DBCloseMysql(glite_lbu_DBContext ctx_gen);
-int glite_lbu_DBQueryCapsMysql(glite_lbu_DBContext ctx_gen);
-void glite_lbu_DBSetCapsMysql(glite_lbu_DBContext commmon_ctx, int caps);
-int glite_lbu_TransactionMysql(glite_lbu_DBContext ctx_gen);
-int glite_lbu_CommitMysql(glite_lbu_DBContext ctx_gen);
-int glite_lbu_RollbackMysql(glite_lbu_DBContext ctx_gen);
-int glite_lbu_FetchRowMysql(glite_lbu_Statement stmt, unsigned int n, unsigned long *lengths, char **results);
-void glite_lbu_FreeStmtMysql(glite_lbu_Statement *stmt);
-int glite_lbu_QueryIndicesMysql(glite_lbu_DBContext ctx_gen, const char *table, char ***key_names, char ****column_names);
-int glite_lbu_ExecSQLMysql(glite_lbu_DBContext ctx_gen, const char *cmd, glite_lbu_Statement *stmt);
-int glite_lbu_QueryColumnsMysql(glite_lbu_Statement stmt_gen, char **cols);
-int glite_lbu_PrepareStmtMysql(glite_lbu_DBContext ctx_gen, const char *sql, glite_lbu_Statement *stmt_gen);
-int glite_lbu_ExecPreparedStmtMysql_v(glite_lbu_Statement stmt_gen, int n, va_list ap);
-long int glite_lbu_LastidMysql(glite_lbu_Statement stmt_gen);
-
-glite_lbu_DBBackend_t mysql_backend = {
- backend: GLITE_LBU_DB_BACKEND_MYSQL,
-
- initContext: glite_lbu_InitDBContextMysql,
- freeContext: glite_lbu_FreeDBContextMysql,
- connect: glite_lbu_DBConnectMysql,
- close: glite_lbu_DBCloseMysql,
- queryCaps: glite_lbu_DBQueryCapsMysql,
- setCaps: glite_lbu_DBSetCapsMysql,
- transaction: glite_lbu_TransactionMysql,
- commit: glite_lbu_CommitMysql,
- rollback: glite_lbu_RollbackMysql,
- fetchRow: glite_lbu_FetchRowMysql,
- freeStmt: glite_lbu_FreeStmtMysql,
- queryIndices: glite_lbu_QueryIndicesMysql,
- execSQL: glite_lbu_ExecSQLMysql,
- queryColumns: glite_lbu_QueryColumnsMysql,
-
- timeToDB: glite_lbu_TimeToStr,
- timestampToDB: glite_lbu_TimestampToStr,
- DBToTime: glite_lbu_StrToTime,
- DBToTimestamp: glite_lbu_StrToTimestamp,
-
- prepareStmt: glite_lbu_PrepareStmtMysql,
- execPreparedStmt_v: glite_lbu_ExecPreparedStmtMysql_v,
- lastid: glite_lbu_LastidMysql,
-};
-
-static mysql_module_t mysql_module = {
- lib: NULL,
- lock: PTHREAD_MUTEX_INITIALIZER,
-};
-
-
-static int myerr(glite_lbu_DBContextMysql ctx, const char *source, int line);
-static int myerrstmt(glite_lbu_StatementMysql stmt, const char *source, int line);
-static int myisokstmt(glite_lbu_StatementMysql stmt, const char *source, int line, int *retry);
-static int db_connect(glite_lbu_DBContextMysql ctx, const char *cs, MYSQL **mysql);
-static void db_close(MYSQL *mysql);
-static int transaction_test(glite_lbu_DBContext ctx, int *caps);
-static int FetchRowSimple(glite_lbu_DBContextMysql ctx, MYSQL_RES *result, unsigned long *lengths, char **results);
-static int FetchRowPrepared(glite_lbu_DBContextMysql ctx, glite_lbu_StatementMysql stmt, unsigned int n, unsigned long *lengths, char **results);
-static void set_time(MYSQL_TIME *mtime, const double time);
-static void glite_lbu_DBCleanup(void);
-static void glite_lbu_FreeStmt_int(glite_lbu_StatementMysql stmt);
-
-
-/* ---- common ---- */
-
-
-
-int glite_lbu_InitDBContextMysql(glite_lbu_DBContext *ctx_gen) {
- glite_lbu_DBContextMysql ctx;
- int err = 0;
- int ver_u;
-
- ctx = calloc(1, sizeof *ctx);
- if (!ctx) return ENOMEM;
- *ctx_gen = (glite_lbu_DBContext)ctx;
-
- /* dynamic load the client library */
- pthread_mutex_lock(&mysql_module.lock);
- if (!mysql_module.lib) {
- mysql_module.lib = dlopen(MYSQL_SONAME, RTLD_LAZY | RTLD_LOCAL);
- if (!mysql_module.lib) return ERR(ctx, ENOENT, "dlopen(): " MYSQL_SONAME ": %s", dlerror());
- do {
- LOAD(mysql_init, "mysql_init");
- LOAD(mysql_get_client_version, "mysql_get_client_version");
- LOAD(mysql_options, "mysql_options");
- LOAD(mysql_errno, "mysql_errno");
- LOAD(mysql_error, "mysql_error");
- LOAD(mysql_stmt_errno, "mysql_stmt_errno");
- LOAD(mysql_stmt_error, "mysql_stmt_error");
- LOAD(mysql_real_connect, "mysql_real_connect");
- LOAD(mysql_close, "mysql_close");
- LOAD(mysql_query, "mysql_query");
- LOAD(mysql_store_result, "mysql_store_result");
- LOAD(mysql_free_result, "mysql_free_result");
- LOAD(mysql_affected_rows, "mysql_affected_rows");
- LOAD(mysql_stmt_close, "mysql_stmt_close");
- LOAD(mysql_num_fields, "mysql_num_fields");
- LOAD(mysql_fetch_lengths, "mysql_fetch_lengths");
- LOAD(mysql_stmt_bind_result, "mysql_stmt_bind_result");
- LOAD(mysql_stmt_prepare, "mysql_stmt_prepare");
- LOAD(mysql_stmt_store_result, "mysql_stmt_store_result");
- LOAD(mysql_fetch_row, "mysql_fetch_row");
- LOAD(mysql_fetch_field, "mysql_fetch_field");
- LOAD(mysql_get_server_info, "mysql_get_server_info");
- LOAD(mysql_stmt_init, "mysql_stmt_init");
- LOAD(mysql_stmt_bind_param, "mysql_stmt_bind_param");
- LOAD(mysql_stmt_execute, "mysql_stmt_execute");
- LOAD(mysql_stmt_fetch, "mysql_stmt_fetch");
- LOAD(mysql_stmt_insert_id, "mysql_stmt_insert_id");
- LOAD(mysql_stmt_affected_rows, "mysql_stmt_affected_rows");
- LOAD(mysql_stmt_result_metadata, "mysql_stmt_result_metadata");
- LOAD(mysql_stmt_fetch_column, "mysql_stmt_fetch_column");
-
- // check the runtime version
- ver_u = mysql_module.mysql_get_client_version();
- if (ver_u != MYSQL_VERSION_ID) {
- fprintf(stderr,"Warning: MySQL library version mismatch (compiled '%d', runtime '%d')", MYSQL_VERSION_ID, ver_u);
-#ifdef SYSLOG_H
- syslog(LOG_WARNING,"MySQL library version mismatch (compiled '%d', runtime '%d')", MYSQL_VERSION_ID, ver_u);
-#endif
- }
-
- pthread_mutex_unlock(&mysql_module.lock);
- atexit(glite_lbu_DBCleanup);
- } while(0);
-
- if (err) {
- dlclose(mysql_module.lib);
- mysql_module.lib = NULL;
- pthread_mutex_unlock(&mysql_module.lock);
- return err;
- }
- } else pthread_mutex_unlock(&mysql_module.lock);
-
- return 0;
-}
-
-
-void glite_lbu_FreeDBContextMysql(glite_lbu_DBContext ctx_gen) {
- glite_lbu_DBContextMysql ctx = (glite_lbu_DBContextMysql)ctx_gen;
-
- if (ctx) {
- assert(ctx->mysql == NULL);
- free(ctx);
- }
-}
-
-
-int glite_lbu_DBConnectMysql(glite_lbu_DBContext ctx_gen, const char *cs) {
- glite_lbu_DBContextMysql ctx = (glite_lbu_DBContextMysql)ctx_gen;
-
- if (db_connect(ctx, cs, &ctx->mysql) != 0 ||
- glite_lbu_ExecSQLMysql(ctx_gen, "SET AUTOCOMMIT=1", NULL) < 0 ||
- glite_lbu_ExecSQLMysql(ctx_gen, "SET TRANSACTION ISOLATION LEVEL REPEATABLE READ", NULL) < 0)
- return STATUS(ctx);
- else
- return 0;
-}
-
-
-void glite_lbu_DBCloseMysql(glite_lbu_DBContext ctx_gen) {
- glite_lbu_DBContextMysql ctx = (glite_lbu_DBContextMysql)ctx_gen;
-
- db_close(ctx->mysql);
- ctx->mysql = NULL;
- CLR_ERR(ctx);
-}
-
-
-int glite_lbu_DBQueryCapsMysql(glite_lbu_DBContext ctx_gen) {
- glite_lbu_DBContextMysql ctx = (glite_lbu_DBContextMysql)ctx_gen;
- MYSQL *m = ctx->mysql;
- int major,minor,sub,version,caps;
- const char *ver_s;
-
- caps = 0;
-
- ver_s = mysql_module.mysql_get_server_info(m);
- if (!ver_s || 3 != sscanf(ver_s,"%d.%d.%d",&major,&minor,&sub))
- return ERR(ctx, EINVAL, "problem retreiving MySQL version");
- version = 10000*major + 100*minor + sub;
-
- if (version >= GLITE_LBU_MYSQL_INDEX_VERSION) caps |= GLITE_LBU_DB_CAP_INDEX;
- if (version >= GLITE_LBU_MYSQL_PREPARED_VERSION) caps |= GLITE_LBU_DB_CAP_PREPARED;
-
- CLR_ERR(ctx);
- transaction_test(ctx_gen, &caps);
-
- if (STATUS(ctx) == 0) return caps;
- else return -1;
-}
-
-
-void glite_lbu_DBSetCapsMysql(glite_lbu_DBContext ctx_gen, int caps) {
- ctx_gen->caps = caps;
-}
-
-
-int glite_lbu_TransactionMysql(glite_lbu_DBContext ctx_gen) {
- glite_lbu_DBContextMysql ctx = (glite_lbu_DBContextMysql)ctx_gen;
-
- CLR_ERR(ctx);
- if (USE_TRANS(ctx)) {
- if (glite_lbu_ExecSQLMysql(ctx_gen, "SET AUTOCOMMIT=0", NULL) < 0) goto err;
- if (glite_lbu_ExecSQLMysql(ctx_gen, "BEGIN", NULL) < 0) goto err;
- ctx->in_transaction = 1;
- }
-err:
- return STATUS(ctx);
-}
-
-
-int glite_lbu_CommitMysql(glite_lbu_DBContext ctx_gen) {
- glite_lbu_DBContextMysql ctx = (glite_lbu_DBContextMysql)ctx_gen;
-
- CLR_ERR(ctx);
- if (USE_TRANS(ctx)) {
- if (glite_lbu_ExecSQLMysql(ctx_gen, "COMMIT", NULL) < 0) goto err;
- if (glite_lbu_ExecSQLMysql(ctx_gen, "SET AUTOCOMMIT=1", NULL) < 0) goto err;
- ctx->in_transaction = 0;
- }
-err:
- return STATUS(ctx);
-}
-
-
-int glite_lbu_RollbackMysql(glite_lbu_DBContext ctx_gen) {
- glite_lbu_DBContextMysql ctx = (glite_lbu_DBContextMysql)ctx_gen;
-
- CLR_ERR(ctx);
- if (USE_TRANS(ctx)) {
- if (glite_lbu_ExecSQLMysql(ctx_gen, "ROLLBACK", NULL) < 0) goto err;
- if (glite_lbu_ExecSQLMysql(ctx_gen, "SET AUTOCOMMIT=1", NULL) < 0) goto err;
- ctx->in_transaction = 0;
- }
-err:
- return STATUS(ctx);
-}
-
-
-int glite_lbu_FetchRowMysql(glite_lbu_Statement stmt_gen, unsigned int n, unsigned long *lengths, char **results) {
- glite_lbu_StatementMysql stmt = (glite_lbu_StatementMysql)stmt_gen;
- glite_lbu_DBContextMysql ctx = (glite_lbu_DBContextMysql)stmt->generic.ctx;
-
- memset(results, 0, n * sizeof(*results));
- if (stmt->result) return FetchRowSimple(ctx, stmt->result, lengths, results);
- else return FetchRowPrepared(ctx, stmt, n, lengths, results);
-}
-
-
-static void glite_lbu_FreeStmt_int(glite_lbu_StatementMysql stmt) {
- if (stmt) {
- if (stmt->result) mysql_module.mysql_free_result(stmt->result);
- if (stmt->stmt) mysql_module.mysql_stmt_close(stmt->stmt);
- free(stmt->sql);
- }
-}
-
-
-void glite_lbu_FreeStmtMysql(glite_lbu_Statement *stmt_gen) {
- glite_lbu_StatementMysql *stmt = (glite_lbu_StatementMysql*)stmt_gen;
-
- glite_lbu_FreeStmt_int(*stmt);
- free(*stmt);
- *stmt = NULL;
-}
-
-
-int glite_lbu_QueryIndicesMysql(glite_lbu_DBContext ctx_gen, const char *table, char ***key_names, char ****column_names) {
- glite_lbu_DBContextMysql ctx = (glite_lbu_DBContextMysql)ctx_gen;
- glite_lbu_Statement stmt;
-
- size_t i,j,ret;
-
-/* XXX: "show index from" columns. Matches at least MySQL 4.0.11 */
- char *sql, *showcol[12];
- int Key_name,Seq_in_index,Column_name,Sub_part;
-
- char **keys = NULL;
- size_t *cols = NULL;
- char **col_names = NULL;
-
- size_t nkeys = 0;
-
- char ***idx = NULL;
-
- Key_name = Seq_in_index = Column_name = Sub_part = -1;
-
- asprintf(&sql, "show index from %s", table);
- if (glite_lbu_ExecSQLMysql(ctx_gen,sql,&stmt)<0) {
- free(sql);
- return STATUS(ctx);
- }
- free(sql);
-
- while ((ret = glite_lbu_FetchRowMysql(stmt,sizeof(showcol)/sizeof(showcol[0]),NULL,showcol)) > 0) {
- assert(ret <= (int)(sizeof showcol/sizeof showcol[0]));
-
- if (!col_names) {
- col_names = malloc(ret * sizeof col_names[0]);
- glite_lbu_QueryColumnsMysql(stmt,col_names);
- for (i=0; i<ret; i++)
- if (!strcasecmp(col_names[i],"Key_name")) Key_name = i;
- else if (!strcasecmp(col_names[i],"Seq_in_index")) Seq_in_index = i;
- else if (!strcasecmp(col_names[i],"Column_name")) Column_name = i;
- else if (!strcasecmp(col_names[i],"Sub_part")) Sub_part = i;
-
- assert(Key_name >= 0 && Seq_in_index >= 0 &&
- Column_name >= 0 && Sub_part >= 0);
-
- }
-
- for (i=0; i<nkeys && strcasecmp(showcol[Key_name],keys[i]); i++);
-
- if (i == nkeys) {
- keys = realloc(keys,(i+2) * sizeof keys[0]);
- keys[i] = strdup(showcol[Key_name]);
-//printf("** KEY [%d] %s\n", i, keys[i]);
- keys[i+1] = NULL;
- cols = realloc(cols,(i+1) * sizeof cols[0]);
- cols[i] = 0;
- idx = realloc(idx,(i+2) * sizeof idx[0]);
- idx[i] = idx[i+1] = NULL;
- nkeys++;
- }
-
- j = atoi(showcol[Seq_in_index])-1;
- if (cols[i] <= j) {
- cols[i] = j+1;
- idx[i] = realloc(idx[i],(j+2)*sizeof idx[i][0]);
- memset(&idx[i][j+1],0,sizeof idx[i][0]);
- }
- idx[i][j] = strdup(showcol[Column_name]);
-//printf("****** [%d, %d] %s\n", i, j, idx[i][j]);
-//FIXME: needed?idx[i][j].value.i = atoi(showcol[Sub_part]);
- for (i = 0; i<ret; i++) free(showcol[i]);
- }
-
- glite_lbu_FreeStmtMysql(&stmt);
- free(cols);
- free(col_names);
-
- if (ret == 0) CLR_ERR(ctx);
- else {
- free(keys);
- keys = NULL;
- for (i = 0; idx[i]; i++) {
- for (j = 0; idx[i][j]; j++) free(idx[i][j]);
- free(idx[i]);
- }
- free(idx);
- idx = NULL;
- }
-
- if (key_names) *key_names = keys;
- else {
- for (i = 0; keys[i]; i++) free(keys[i]);
- free(keys);
- }
- *column_names = idx;
-
- return STATUS(ctx);
-}
-
-
-/* ---- simple ---- */
-
-int glite_lbu_ExecSQLMysql(glite_lbu_DBContext ctx_gen, const char *cmd, glite_lbu_Statement *stmt_gen) {
- glite_lbu_DBContextMysql ctx = (glite_lbu_DBContextMysql)ctx_gen;
- glite_lbu_StatementMysql stmt;
- int merr;
- int retry_nr = 0;
- int do_reconnect = 0;
-#ifdef LBS_DB_PROFILE
- struct timeval start,end;
- int pid;
-
- static struct timeval sum = {
- tv_sec: 0,
- tv_usec: 0
- };
-#endif
-
- CLR_ERR(ctx);
-
- if (stmt_gen) *stmt_gen = NULL;
- stmt = NULL;
-
-#ifdef LBS_DB_PROFILE
- gettimeofday(&start,NULL);
-#endif
-
- while (retry_nr == 0 || do_reconnect) {
- do_reconnect = 0;
- if (mysql_module.mysql_query(ctx->mysql, cmd)) {
- /* error occured */
- switch (merr = mysql_module.mysql_errno(ctx->mysql)) {
- case 0:
- break;
- case ER_DUP_ENTRY:
- ERR(ctx, EEXIST, mysql_module.mysql_error(ctx->mysql));
- return -1;
- break;
- case CR_SERVER_LOST:
- case CR_SERVER_GONE_ERROR:
- if (ctx->in_transaction) {
- ERR(ctx, ERESTART, mysql_module.mysql_error(ctx->mysql));
- return -1;
- }
- else if (retry_nr <= 0)
- do_reconnect = 1;
- break;
- case ER_LOCK_DEADLOCK:
- ERR(ctx, EDEADLOCK, mysql_module.mysql_error(ctx->mysql));
- return -1;
- break;
- default:
- MY_ERR(ctx);
- return -1;
- break;
- }
- }
- retry_nr++;
- }
-
- if (stmt_gen) {
- stmt = calloc(1, sizeof(*stmt));
- if (!stmt) {
- ERR(ctx, ENOMEM, NULL);
- return -1;
- }
- stmt->generic.ctx = ctx_gen;
- stmt->result = mysql_module.mysql_store_result(ctx->mysql);
- if (!stmt->result) {
- if (mysql_module.mysql_errno(ctx->mysql)) {
- MY_ERR(ctx);
- free(stmt);
- return -1;
- }
- }
- *stmt_gen = (glite_lbu_Statement)stmt;
- } else {
- MYSQL_RES *r = mysql_module.mysql_store_result(ctx->mysql);
- mysql_module.mysql_free_result(r);
- }
-#ifdef LBS_DB_PROFILE
- pid = getpid();
- gettimeofday(&end,NULL);
- end.tv_usec -= start.tv_usec;
- end.tv_sec -= start.tv_sec;
- if (end.tv_usec < 0) { end.tv_sec--; end.tv_usec += 1000000; }
-
- sum.tv_usec += end.tv_usec;
- sum.tv_sec += end.tv_sec + sum.tv_usec / 1000000;
- sum.tv_usec -= 1000000 * (sum.tv_usec / 1000000);
- fprintf(stderr,"[%d] %s\n[%d] %3ld.%06ld (sum: %3ld.%06ld)\n",pid,cmd,pid,end.tv_sec,end.tv_usec,sum.tv_sec,sum.tv_usec);
-#endif
-
- return mysql_module.mysql_affected_rows(ctx->mysql);
-}
-
-
-int glite_lbu_QueryColumnsMysql(glite_lbu_Statement stmt_gen, char **cols)
-{
- glite_lbu_StatementMysql stmt = (glite_lbu_StatementMysql)stmt_gen;
- int i = 0;
- MYSQL_FIELD *f;
-
- CLR_ERR(stmt->generic.ctx);
- if (!stmt->result) return ERR(stmt->generic.ctx, ENOTSUP, "QueryColumns implemented only for simple API");
- while ((f = mysql_module.mysql_fetch_field(stmt->result))) cols[i++] = f->name;
- return i == 0;
-}
-
-
-/* ---- prepared --- */
-
-int glite_lbu_PrepareStmtMysql(glite_lbu_DBContext ctx_gen, const char *sql, glite_lbu_Statement *stmt_gen) {
- glite_lbu_DBContextMysql ctx = (glite_lbu_DBContextMysql)ctx_gen;
- glite_lbu_StatementMysql stmt;
- int ret, retry;
- MYSQL_RES *meta;
-
- // init
- stmt = calloc(1, sizeof(*stmt));
- stmt->generic.ctx = ctx_gen;
- *stmt_gen = NULL;
-
- // create the SQL command
- if ((stmt->stmt = mysql_module.mysql_stmt_init(ctx->mysql)) == NULL)
- return STATUS(ctx);
-
- // prepare the SQL command
- retry = 1;
- do {
- mysql_module.mysql_stmt_prepare(stmt->stmt, sql, strlen(sql));
- ret = MY_ISOKSTMT(stmt, &retry);
- } while (ret == 0);
- if (ret == -1) goto failed;
-
- // number of fields (0 for no results)
- if ((meta = mysql_module.mysql_stmt_result_metadata(stmt->stmt)) != NULL) {
- stmt->nrfields = mysql_module.mysql_num_fields(meta);
- mysql_module.mysql_free_result(meta);
- } else
- stmt->nrfields = 0;
-
- // remember the command
- stmt->sql = strdup(sql);
-
- *stmt_gen = (glite_lbu_Statement)stmt;
- return CLR_ERR(ctx);
-
-failed:
- glite_lbu_FreeStmt_int(stmt);
- free(stmt);
- return STATUS(ctx);
-}
-
-
-int glite_lbu_ExecPreparedStmtMysql_v(glite_lbu_Statement stmt_gen, int n, va_list ap) {
- glite_lbu_StatementMysql stmt = (glite_lbu_StatementMysql)stmt_gen;
- int i, prepare_retry;
- glite_lbu_DBType type;
- char *pchar;
- int *pint;
- long int *plint;
- MYSQL_TIME *ptime;
- int ret, retry;
- MYSQL_BIND *binds = NULL;
- void **data = NULL;
- unsigned long *lens;
- glite_lbu_Statement newstmt;
-
- // gather parameters
- if (n) {
- binds = calloc(n, sizeof(MYSQL_BIND));
- data = calloc(n, sizeof(void *));
- lens = calloc(n, sizeof(unsigned long *));
- }
- for (i = 0; i < n; i++) {
- type = va_arg(ap, glite_lbu_DBType);
- switch (type) {
- case GLITE_LBU_DB_TYPE_TINYINT:
- pchar = binds[i].buffer = data[i] = malloc(sizeof(char));
- *pchar = va_arg(ap, int);
- break;
-
- case GLITE_LBU_DB_TYPE_INT:
- plint = binds[i].buffer = data[i] = malloc(sizeof(long int));
- *plint = va_arg(ap, long int);
- break;
-
- case GLITE_LBU_DB_TYPE_BOOLEAN:
- pint = binds[i].buffer = data[i] = malloc(sizeof(int));
- *pint = va_arg(ap, int) ? 1 : 0;
- break;
-
- case GLITE_LBU_DB_TYPE_TINYBLOB:
- case GLITE_LBU_DB_TYPE_TINYTEXT:
- case GLITE_LBU_DB_TYPE_BLOB:
- case GLITE_LBU_DB_TYPE_TEXT:
- case GLITE_LBU_DB_TYPE_MEDIUMBLOB:
- case GLITE_LBU_DB_TYPE_MEDIUMTEXT:
- case GLITE_LBU_DB_TYPE_LONGBLOB:
- case GLITE_LBU_DB_TYPE_LONGTEXT:
- binds[i].buffer = va_arg(ap, void *);
- binds[i].length = &lens[i];
- lens[i] = va_arg(ap, unsigned long);
- break;
-
- case GLITE_LBU_DB_TYPE_VARCHAR:
- case GLITE_LBU_DB_TYPE_CHAR:
- binds[i].buffer = va_arg(ap, char *);
- binds[i].length = &lens[i];
- lens[i] = binds[i].buffer ? strlen((char *)binds[i].buffer) : 0;
- break;
-
- case GLITE_LBU_DB_TYPE_DATE:
- case GLITE_LBU_DB_TYPE_TIME:
- case GLITE_LBU_DB_TYPE_DATETIME:
- ptime = binds[i].buffer = data[i] = malloc(sizeof(MYSQL_TIME));
- set_time(ptime, va_arg(ap, time_t));
- break;
-
- case GLITE_LBU_DB_TYPE_TIMESTAMP:
- ptime = binds[i].buffer = data[i] = malloc(sizeof(MYSQL_TIME));
- set_time(ptime, va_arg(ap, double));
- break;
-
- case GLITE_LBU_DB_TYPE_NULL:
- break;
-
- default:
- assert("unimplemented parameter assign" == NULL);
- break;
- }
- binds[i].buffer_type = glite_type_to_mysql[type];
- }
-
- prepare_retry = 2;
- do {
- // bind parameters
- if (n) {
- if (mysql_module.mysql_stmt_bind_param(stmt->stmt, binds) != 0) {
- MY_ERRSTMT(stmt);
- ret = -1;
- goto statement_failed;
- }
- }
-
- // run
- retry = 1;
- do {
- mysql_module.mysql_stmt_execute(stmt->stmt);
- ret = MY_ISOKSTMT(stmt, &retry);
- } while (ret == 0);
- statement_failed:
- if (ret == -1) {
- if (mysql_module.mysql_stmt_errno(stmt->stmt) == ER_UNKNOWN_STMT_HANDLER) {
- // expired the prepared command ==> restore it
- if (glite_lbu_PrepareStmtMysql(stmt->generic.ctx, stmt->sql, &newstmt) == -1) goto failed;
- glite_lbu_FreeStmt_int(stmt);
- memcpy(stmt, newstmt, sizeof(struct glite_lbu_StatementMysql_s));
- prepare_retry--;
- ret = 0;
- } else goto failed;
- }
- } while (ret == 0 && prepare_retry > 0);
-
- // result
- retry = 1;
- do {
- mysql_module.mysql_stmt_store_result(stmt->stmt);
- ret = MY_ISOKSTMT(stmt, &retry);
- } while (ret == 0);
- if (ret == -1) goto failed;
-
- // free params
- if (n) {
- for (i = 0; i < n; i++) free(data[i]);
- free(data);
- free(binds);
- free(lens);
- }
- CLR_ERR(stmt->generic.ctx);
- return mysql_module.mysql_stmt_affected_rows(stmt->stmt);
-
-failed:
- for (i = 0; i < n; i++) free(data[i]);
- free(data);
- free(binds);
- free(lens);
- return -1;
-}
-
-
-long int glite_lbu_LastidMysql(glite_lbu_Statement stmt_gen) {
- glite_lbu_StatementMysql stmt = (glite_lbu_StatementMysql)stmt_gen;
- my_ulonglong i;
-
- CLR_ERR(stmt_gen->ctx);
- i = mysql_module.mysql_stmt_insert_id(stmt->stmt);
- assert(i < ((unsigned long int)-1) >> 1);
- return (long int)i;
-}
-
-
-/*
- * helping function: find oud mysql error and sets on the context
- */
-static int myerr(glite_lbu_DBContextMysql ctx, const char *source, int line) {
- return glite_lbu_DBSetError(&ctx->generic, EIO, source, line, mysql_module.mysql_error(ctx->mysql));
-}
-
-
-/*
- * helping function: find oud mysql stmt error and sets on the context
- */
-static int myerrstmt(glite_lbu_StatementMysql stmt, const char *source, int line) {
- return glite_lbu_DBSetError(stmt->generic.ctx, EIO, source, line, mysql_module.mysql_stmt_error(stmt->stmt));
-}
-
-
-/*
- * helping function: error handle
- *
- * \return -1 failed
- * \return 0 retry
- * \return 1 OK
- */
-static int myisokstmt(glite_lbu_StatementMysql stmt, const char *source, int line, int *retry) {
- switch (mysql_module.mysql_stmt_errno(stmt->stmt)) {
- case 0:
- return 1;
- break;
- case ER_DUP_ENTRY:
- glite_lbu_DBSetError(stmt->generic.ctx, EEXIST, source, line, mysql_module.mysql_stmt_error(stmt->stmt));
- return -1;
- break;
- case CR_SERVER_LOST:
- case CR_SERVER_GONE_ERROR:
- if (*retry > 0) {
- (*retry)--;
- return 0;
- } else {
- myerrstmt(stmt, source, line);
- return -1;
- }
- break;
- default:
- myerrstmt(stmt, source, line);
- return -1;
- break;
- }
-}
-
-
-/*
- * mysql connect
- */
-static int db_connect(glite_lbu_DBContextMysql ctx, const char *cs, MYSQL **mysql) {
- char *buf = NULL;
- char *host,*user,*pw,*db;
- char *slash,*at,*colon;
- int ret;
-#if MYSQL_VERSION_ID >= 50013
- my_bool reconnect = 1;
-#endif
-
- // needed for SQL result parameters
- assert(sizeof(int) >= sizeof(my_bool));
-
- if (!cs) return ERR(ctx, EINVAL, "connect string not specified");
-
- if (!(*mysql = mysql_module.mysql_init(NULL))) return ERR(ctx, ENOMEM, NULL);
-
- mysql_module.mysql_options(*mysql, MYSQL_READ_DEFAULT_FILE, "my");
-#if MYSQL_VERSION_ID >= 50013
- /* XXX: may result in weird behaviour in the middle of transaction */
- mysql_module.mysql_options(*mysql, MYSQL_OPT_RECONNECT, &reconnect);
-#endif
-
- host = user = pw = db = NULL;
-
- buf = strdup(cs);
- slash = strchr(buf,'/');
- at = strrchr(buf,'@');
- colon = strrchr(buf,':');
-
- if (!slash || !at || !colon) {
- free(buf);
- db_close(*mysql);
- *mysql = NULL;
- return ERR(ctx, EINVAL, "Invalid DB connect string");
- }
-
- *slash = *at = *colon = 0;
- host = at+1;
- user = buf;
- pw = slash+1;
- db = colon+1;
-
- /* ljocha: CLIENT_FOUND_ROWS added to make authorization check
- * working in update_notif().
- * Hope it does not break anything else */
- if (!mysql_module.mysql_real_connect(*mysql,host,user,pw,db,0,NULL,CLIENT_FOUND_ROWS)) {
- ret = MY_ERR(ctx);
- db_close(*mysql);
- *mysql = NULL;
- free(buf);
- return ret;
- }
- free(buf);
-
- return CLR_ERR(ctx);
-}
-
-
-/*
- * mysql close
- */
-static void db_close(MYSQL *mysql) {
- if (mysql) mysql_module.mysql_close(mysql);
-}
-
-
-/*
- * test transactions capability:
- */
-static int transaction_test(glite_lbu_DBContext ctx, int *caps) {
- glite_lbu_Statement stmt;
- char *table[1] = { NULL }, *res[2] = { NULL, NULL }, *cmd = NULL;
- int retval;
-
- (*caps) &= ~GLITE_LBU_DB_CAP_TRANSACTIONS;
-
- if ((retval = glite_lbu_ExecSQLMysql(ctx, "SHOW TABLES", &stmt)) <= 0 || glite_lbu_FetchRowMysql(stmt, 1, NULL, table) < 0) goto quit;
- glite_lbu_FreeStmtMysql(&stmt);
-
- trio_asprintf(&cmd, "SHOW CREATE TABLE %|Ss", table[0]);
- if (glite_lbu_ExecSQLMysql(ctx, cmd, &stmt) <= 0 || (retval = glite_lbu_FetchRowMysql(stmt, 2, NULL, res)) < 0 ) goto quit;
- if (retval != 2 || strcmp(res[0], table[0])) {
- ERR(ctx, EIO, "unexpected show create result");
- goto quit;
- }
-
- if (strstr(res[1],"ENGINE=InnoDB"))
- (*caps) |= GLITE_LBU_DB_CAP_TRANSACTIONS;
-
-#ifdef LBS_DB_PROFILE
- fprintf(stderr, "[%d] use_transactions = %d\n", getpid(), USE_TRANS(ctx));
-#endif
-
-quit:
- glite_lbu_FreeStmtMysql(&stmt);
- free(table[0]);
- free(res[0]);
- free(res[1]);
- free(cmd);
- return STATUS(ctx);
-}
-
-
-/*
- * simple version of the fetch
- */
-static int FetchRowSimple(glite_lbu_DBContextMysql ctx, MYSQL_RES *result, unsigned long *lengths, char **results) {
- MYSQL_ROW row;
- unsigned int nr, i;
- unsigned long *len;
-
- CLR_ERR(ctx);
-
- if (!(row = mysql_module.mysql_fetch_row(result))) {
- if (mysql_module.mysql_errno((MYSQL *) ctx->mysql)) {
- MY_ERR(ctx);
- return -1;
- } else return 0;
- }
-
- nr = mysql_module.mysql_num_fields(result);
- len = mysql_module.mysql_fetch_lengths(result);
- for (i=0; i<nr; i++) {
- if (lengths) lengths[i] = len[i];
- if (len[i]) {
- results[i] = malloc(len[i] + 1);
- memcpy(results[i], row[i], len[i]);
- results[i][len[i]] = '\000';
- } else
- results[i] = strdup("");
- }
-
- return nr;
-}
-
-
-/*
- * prepared version of the fetch
- */
-static int FetchRowPrepared(glite_lbu_DBContextMysql ctx, glite_lbu_StatementMysql stmt, unsigned int n, unsigned long *lengths, char **results) {
- int ret, retry;
- unsigned int i;
- MYSQL_BIND *binds = NULL;
- unsigned long *lens = NULL;
-
- if (n != stmt->nrfields) {
- ERR(ctx, EINVAL, "bad number of result fields");
- return -1;
- }
-
- // space for results
- if (n) binds = calloc(n, sizeof(MYSQL_BIND));
- if (!lengths) {
- lens = calloc(n, sizeof(unsigned long));
- lengths = lens;
- }
- for (i = 0; i < n; i++) {
- binds[i].buffer_type = MYSQL_TYPE_VAR_STRING;
- binds[i].buffer_length = GLITE_LBU_DEFAULT_RESULT_BUFFER_LENGTH - 1;
- binds[i].length = &lengths[i];
- binds[i].buffer = results[i] = calloc(1, GLITE_LBU_DEFAULT_RESULT_BUFFER_LENGTH);
- }
- if (mysql_module.mysql_stmt_bind_result(stmt->stmt, binds) != 0) goto failedstmt;
-
- // fetch data, all can be truncated
- retry = 1;
- do {
- switch(mysql_module.mysql_stmt_fetch(stmt->stmt)) {
-#ifdef MYSQL_DATA_TRUNCATED
- case MYSQL_DATA_TRUNCATED:
-#endif
- case 0:
- ret = 1; break;
- case 1: ret = MY_ISOKSTMT(stmt, &retry); break;
- case MYSQL_NO_DATA: ret = 0; goto quit; /* it's OK */
- default: ERR(ctx, EIO, "other fetch error"); goto failed;
- }
- } while (ret == 0);
- if (ret == -1) goto failed;
-
- // check if all fileds had enough buffer space
- for (i = 0; i < n; i++) {
- // fetch the rest if needed
- if (lengths[i] > binds[i].buffer_length) {
- unsigned int fetched;
-
- fetched = binds[i].buffer_length;
- if ((results[i] = realloc(results[i], lengths[i] + 1)) == NULL) {
- ERR(ctx, ENOMEM, "insufficient memory for field data");
- goto failed;
- }
- results[i][lengths[i]] = '\000';
- binds[i].buffer = results[i] + fetched;
- binds[i].buffer_length = lengths[i] - fetched;
-
- retry = 1;
- do {
- switch (mysql_module.mysql_stmt_fetch_column(stmt->stmt, binds + i, i, fetched)) {
- case 0: ret = 1; break;
- case 1: ret = MY_ISOKSTMT(stmt, &retry); break;
- case MYSQL_NO_DATA: ret = 0; goto quit; /* it's OK */
- default: ERR(ctx, EIO, "other fetch error"); goto failed;
- }
- } while (ret == 0);
- if (ret == -1) goto failed;
- }
- }
-
- CLR_ERR(ctx);
- free(binds);
- free(lens);
- return n;
-
-failedstmt:
- MY_ERRSTMT(stmt);
-failed:
- ret = -1;
-quit:
- free(binds);
- free(lens);
- for (i = 0; i < n; i++) {
- free(results[i]);
- results[i] = NULL;
- }
- return ret;
-}
-
-
-static void set_time(MYSQL_TIME *mtime, const double time) {
- struct tm tm;
- time_t itime;
-
- itime = time;
- gmtime_r(&itime, &tm);
- memset(mtime, 0, sizeof *mtime);
- mtime->year = tm.tm_year + 1900;
- mtime->month = tm.tm_mon + 1;
- mtime->day = tm.tm_mday;
- mtime->hour = tm.tm_hour;
- mtime->minute = tm.tm_min;
- mtime->second = tm.tm_sec;
- mtime->second_part = (time - itime) * 1000;
-}
-
-
-static void glite_lbu_DBCleanup(void) {
- pthread_mutex_lock(&mysql_module.lock);
- if (mysql_module.lib) {
- dlclose(mysql_module.lib);
- mysql_module.lib = NULL;
- }
- pthread_mutex_unlock(&mysql_module.lock);
-}
-
-
+++ /dev/null
-/**
- * Simple postgres module with org.glite.lbjp-common.db interface.
- *
- * PostgreSQL limitations:
- * - prepared commands requires server >= 8.2
- * - binary data need to be handled manually (libpq limitation)
- */
-
-#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 <time.h>
-#include <unistd.h>
-
-#include <libpq-fe.h>
-
-#include "glite/lbu/trio.h"
-#include "db.h"
-#include "db-int.h"
-
-#ifdef WIN32
-#define STDCALL __stdcall
-#else
-#define STDCALL
-#endif
-
-#define DB_CONNECT_TIMEOUT "20"
-
-#ifdef LOG
- #define lprintf(FMT...) fprintf(stdout, "[db-pg] %s: ", __FUNCTION__); fprintf(stdout, ##FMT);
-#else
- #define lprintf(FMT...)
-#endif
-
-#define set_error(CTX, CODE, DESC...) glite_lbu_DBSetError((glite_lbu_DBContext)(CTX), (CODE), __FUNCTION__, __LINE__, ##DESC)
-
-#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_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 *STDCALL(*PQconnectdb)(const char *conninfo);
- ConnStatusType STDCALL(*PQstatus)(const PGconn *conn);
- void STDCALL(*PQfinish)(PGconn *conn);
- char *STDCALL(*PQerrorMessage)(const PGconn *conn);
- int STDCALL(*PQnfields)(const PGresult *res);
- char *STDCALL(*PQgetvalue)(const PGresult *res, int tup_num, int field_num);
- int STDCALL(*PQgetlength)(const PGresult *res, int tup_num, int field_num);
- void STDCALL(*PQclear)(PGresult *res);
- PGresult *STDCALL(*PQexec)(PGconn *conn, const char *query);
- ExecStatusType STDCALL(*PQresultStatus)(const PGresult *res);
- char *STDCALL(*PQresultErrorMessage)(const PGresult *res);
- char *STDCALL(*PQcmdTuples)(PGresult *res);
- int STDCALL(*PQntuples)(const PGresult *res);
- char *STDCALL(*PQfname)(const PGresult *res, int field_num);
- size_t STDCALL(*PQescapeStringConn)(PGconn *conn,
- char *to, const char *from, size_t length,
- int *error);
- void STDCALL(*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"};
-
-
-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(PQescapeStringConn, "PQescapeStringConn");
- 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_FreeDBContextPsql(glite_lbu_DBContext ctx_gen) {
- glite_lbu_DBContextPsql ctx = (glite_lbu_DBContextPsql)ctx_gen;
-
- if (ctx) {
- assert(ctx->conn == NULL);
- free(ctx);
- }
-}
-
-
-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;
-
- host = user = pw = db = NULL;
- buf = strdup(cs);
- slash = strchr(buf,'/');
- at = strrchr(buf,'@');
- colon = strrchr(buf,':');
- if (!slash || !at || !colon) {
- free(buf);
- return set_error(ctx, EINVAL, "Invalid DB connect string");
- }
- *slash = *at = *colon = 0;
- host = at+1;
- user = buf;
- pw = slash+1;
- db = colon+1;
-
- trio_asprintf(&pgcsbuf, "host='%|Ss' dbname='%|Ss' user='%|Ss' password='%|Ss' connect_timeout=" DB_CONNECT_TIMEOUT, host, db, user, pw);
- /* simulate socket acces via localhost similar to MySQL */
- if (strcmp(host, "localhost") == 0) pgcs = pgcsbuf + strlen("host='localhost' ");
- else pgcs = pgcsbuf;
- free(buf);
-
- lprintf("connection string = %s\n", pgcs);
- ctx->conn = psql_module.PQconnectdb(pgcs);
- free(pgcsbuf);
- if (!ctx->conn) return ENOMEM;
-
-
-
- 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 EIO;
- }
-
- return 0;
-}
-
-
-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_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_ExecSQLPsql(ctx_gen, "SHOW server_version", &stmt) == -1) return -1;
- switch (glite_lbu_FetchRowPsql(stmt, 1, NULL, &res)) {
- case 1:
- break;
- case -1:
- has_prepared = -1;
- goto quit;
- default:
- goto quit;
- }
- if (sscanf(res, "%d.%d.%d", &major, &minor, &sub) != 3) {
- set_error(ctx, EIO, "can't parse PostgreSQL version string");
- goto quit;
- }
- version = 10000*major + 100*minor + sub;
- has_prepared = version >= 80200 ? GLITE_LBU_DB_CAP_PREPARED : 0;
-
-quit:
- free(res);
- glite_lbu_FreeStmtPsql(&stmt);
- return has_prepared;
-}
-
-
-void glite_lbu_DBSetCapsPsql(glite_lbu_DBContext ctx_gen, int caps) {
- ctx_gen->caps = caps;
-}
-
-
-int glite_lbu_TransactionPsql(glite_lbu_DBContext ctx_gen __attribute((unused))) {
- return 0;
-}
-
-
-int glite_lbu_CommitPsql(glite_lbu_DBContext ctx_gen __attribute((unused))) {
- return 0;
-}
-
-
-int glite_lbu_RollbackPsql(glite_lbu_DBContext ctx_gen __attribute((unused))) {
- return 0;
-}
-
-
-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;
- char *s;
-
- if (stmt->row >= stmt->nrows) return 0;
-
- n = psql_module.PQnfields(stmt->res);
- if (n <= 0) {
- set_error(stmt->generic.ctx, EINVAL, "Result set w/o columns");
- return -1;
- }
- if (n > maxn) {
- set_error(stmt->generic.ctx, EINVAL, "Not enough room for the result");
- return -1;
- }
- for (i = 0; i < n; i++) {
- /* sanity check for internal error (NULL when invalid row) */
- s = psql_module.PQgetvalue(stmt->res, stmt->row, i) ? : "";
- results[i] = strdup(s);
- if (lengths) lengths[i] = strlen(s);
- }
-
- stmt->row++;
- return n;
-}
-
-
-void glite_lbu_FreeStmtPsql(glite_lbu_Statement *stmt_gen) {
- glite_lbu_DBContextPsql ctx;
- glite_lbu_StatementPsql stmt;
- char *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);
- psql_module.PQclear(stmt->res);
- }
- free(stmt->name);
- free(stmt->sql);
- free(stmt);
- *stmt_gen = 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, *errmsg, *pos;
- PGresult *res;
-
- lprintf("command = %s\n", cmd);
- if (stmt_out) *stmt_out = NULL;
- if ((res = psql_module.PQexec(ctx->conn, cmd)) == NULL) {
- ctx->generic.err.code = ENOMEM;
- return -1;
- }
-
- status = psql_module.PQresultStatus(res);
- if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) {
- 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 = psql_module.PQcmdTuples(res);
- if (nstr && nstr[0]) n = atoi(nstr);
- else n = psql_module.PQntuples(res);
- if (stmt_out) {
- stmt = calloc(1, sizeof(*stmt));
- stmt->generic.ctx = ctx_gen;
- stmt->res = res;
- stmt->nrows = n;
- *stmt_out = (glite_lbu_Statement)stmt;
- } else {
- psql_module.PQclear(res);
- }
- return n;
-}
-
-
-int glite_lbu_QueryColumnsPsql(glite_lbu_Statement stmt_gen, char **cols) {
- glite_lbu_StatementPsql stmt = (glite_lbu_StatementPsql)stmt_gen;
- int n, i;
-
- n = psql_module.PQnfields(stmt->res);
- for (i = 0; i < n; i++) {
- cols[i] = psql_module.PQfname(stmt->res, i);
- }
- return -1;
-}
-
-
-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_StatementPsql stmt;
- PGresult *res = NULL;
-
- // init
- stmt = calloc(1, sizeof(*stmt));
- stmt->generic.ctx = ctx_gen;
- stmt->sql = strdup(sql);
-
- // name of the prepared command used as ID in postgres
- i = -1;
- minp = stmt->sql + strlen(stmt->sql);
- selectp = strcasestr(stmt->sql, "SELECT");
- updatep = strcasestr(stmt->sql, "UPDATE");
- insertp = strcasestr(stmt->sql, "INSERT");
- if (selectp && selectp < minp) { minp = selectp; i = 0; }
- 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], ++ctx->prepared_counts[i]);
-
- asprintf(&sqlPrep, "PREPARE %s AS %s", stmt->name, stmt->sql);
- lprintf("prepare = %s\n", sqlPrep);
- 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;
- }
-
- *stmt_out = (glite_lbu_Statement)stmt;
- retval = 0;
-
-quit:
- free(sqlPrep);
- if (res) psql_module.PQclear(res);
- if (!retval) return 0;
-
- free(stmt->name);
- free(stmt->sql);
- free(stmt);
- return retval;
-}
-
-
-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;
- size_t data_len = 0;
-
- glite_lbu_DBType type;
-
- if (!stmt || !stmt->sql || !stmt->name)
- return set_error(ctx, EINVAL, "PrepareStmt() not called");
-
- if (stmt->res) {
- psql_module.PQclear(stmt->res);
- stmt->res = NULL;
- }
-
- // gather parameters
- if (n) {
- tmpdata = calloc(n, sizeof(char *));
- }
- for (i = 0; i < n; i++) {
- type = va_arg(ap, glite_lbu_DBType);
-
- switch(type) {
- case GLITE_LBU_DB_TYPE_TINYINT:
- asprintf(&tmpdata[i], "%d", va_arg(ap, int));
- break;
-
- case GLITE_LBU_DB_TYPE_INT:
- asprintf(&tmpdata[i], "%ld", va_arg(ap, long int));
- break;
-
- case GLITE_LBU_DB_TYPE_TINYBLOB:
- case GLITE_LBU_DB_TYPE_TINYTEXT:
- case GLITE_LBU_DB_TYPE_BLOB:
- case GLITE_LBU_DB_TYPE_TEXT:
- case GLITE_LBU_DB_TYPE_MEDIUMBLOB:
- case GLITE_LBU_DB_TYPE_MEDIUMTEXT:
- case GLITE_LBU_DB_TYPE_LONGBLOB:
- case GLITE_LBU_DB_TYPE_LONGTEXT: {
- char *tmp, *s;
- unsigned long binary_len;
-
- s = va_arg(ap, char *);
- binary_len = va_arg(ap, unsigned long);
- lprintf("blob, len = %lu, ptr = %p\n", binary_len, s);
- if (s) {
- tmp = malloc(2*binary_len + 1);
- psql_module.PQescapeStringConn(ctx->conn, tmp, s, binary_len, NULL);
- asprintf(&tmpdata[i], "'%s'", tmp);
- lprintf("escaped: '%s'\n", tmpdata[i]);
- free(tmp);
- } else
- tmpdata[i] = strdup("NULL");
- break;
- }
-
-
- case GLITE_LBU_DB_TYPE_VARCHAR:
- case GLITE_LBU_DB_TYPE_CHAR:
- s = va_arg(ap, char *);
- if (s) trio_asprintf(&tmpdata[i], "'%|Ss'", s);
- 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_TimeToStr(va_arg(ap, time_t), &tmpdata[i]);
- break;
-
- case GLITE_LBU_DB_TYPE_TIMESTAMP:
- glite_lbu_TimestampToStr(va_arg(ap, double), &tmpdata[i]);
- break;
-
- case GLITE_LBU_DB_TYPE_NULL:
- tmpdata[i] = strdup("NULL");
- break;
-
- case GLITE_LBU_DB_TYPE_BOOLEAN:
- tmpdata[i] = strdup(va_arg(ap, int) ? "true" : "false");
- break;
-
- default:
- lprintf("unknown type %d\n", type);
- set_error(ctx, EINVAL, "unimplemented type");
- goto quit;
- }
-
- data_len += strlen(tmpdata[i]);
- }
-
- asprintf(&sql, "EXECUTE %s", stmt->name);
- s = realloc(sql, strlen(sql) + (2 * n - 2) + strlen(" ()") + data_len + 1);
- if (!s) goto quit;
- sql = s;
- for (i = 0; i < n; i++) {
- strcat(sql, i ? ", " : " (" ); s += 2;
- strcat(sql, tmpdata[i]);
- }
- if (n) strcat(sql, ")");
-
- lprintf("exec prepared: n = %d, sql = '%s'\n", n, sql);
- 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, psql_module.PQerrorMessage(ctx->conn));
- set_error(ctx, EIO, s);
- free(s); s = NULL;
- goto quit;
- }
- nstr = psql_module.PQcmdTuples(stmt->res);
- //lprintf("cmdtuples: '%s'\n", nstr);
- if (nstr && nstr[0]) retval = atoi(nstr);
- else retval = psql_module.PQntuples(stmt->res);
- stmt->nrows = retval;
- stmt->row = 0;
- //lprintf("ntuples/retval: %d\n", retval);
-
-quit:
- for (i = 0; i < n; i++) free(tmpdata[i]);
- free(tmpdata);
- free(sql);
- return retval;
-}
-
-
-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);
-}
+++ /dev/null
-#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);
-}