From: František Dvořák Date: Thu, 29 Oct 2009 15:07:20 +0000 (+0000) Subject: Dynamic database backends. Just for code sharing for now, but mysql should work. X-Git-Tag: glite-security-gss_R_2_0_1_1~37 X-Git-Url: http://scientific.zcu.cz/git/?a=commitdiff_plain;h=8dfa9d32dc1a02901945d31c89c3d57ccc7a436d;p=jra1mw.git Dynamic database backends. Just for code sharing for now, but mysql should work. Changes: - reshufle build process + small various fixes - extended DB module API - internal object-oriented API - buffered commands remains in main module - update the mysql backend module + some small other changes --- diff --git a/org.glite.lbjp-common.db/Makefile b/org.glite.lbjp-common.db/Makefile index 265a056..6e96135 100644 --- a/org.glite.lbjp-common.db/Makefile +++ b/org.glite.lbjp-common.db/Makefile @@ -6,13 +6,10 @@ distdir=. globalprefix=glite lbutilsprefix=lbu package=glite-lb-utils-db -version=0.2.0 PREFIX=/opt/glite -flavour=gcc32thr -glite_location=/opt/glite mysql-devel_prefix=/opt/mysql -mysql_version=4.1.11 +postgresql_prefix=/opt cppunit_prefix=/opt/cppunit thrflavour=gcc32pthr nothrflavour=gcc32 @@ -32,23 +29,32 @@ ifeq (${host_cpu},x86_64) archlib:=lib64 endif -MYSQL_SONAME:=$(shell ../project/get_soname.sh ${mysql-devel_prefix}/${archlib} ${mysql_prefix}/${archlib} ${mysql-devel_prefix}/lib ${mysql_prefix}/lib) +MYSQL_SONAME:=$(shell ../project/get_soname.sh mysqlclient ${mysql-devel_prefix}/${archlib} ${mysql_prefix}/${archlib} ${mysql-devel_prefix}/lib ${mysql_prefix}/lib) +PSQL_SONAME:=$(shell ../project/get_soname.sh pq ${postgresql_prefix}/${archlib} ${postgresql_prefix}/lib) + +MYSQL_CPPFLAGS:=-I${mysql-devel_prefix}/include -I${mysql-devel_prefix}/include/mysql +PSQL_CPPFLAGS=-I`pg_config --includedir` -MYSQL_CPPFLAGS:=-I${mysql-devel_prefix}/include -I${mysql-devel_prefix}/include/mysql -DMYSQL_SONAME=\"${MYSQL_SONAME}\" -MYSQL_LIBS=-lz CFLAGS:= \ ${DEBUG} \ - -DVERSION=\"${version}\" \ + -DVERSION=\"${module.version}\" \ -I${stagedir}/include -I${top_srcdir}/src -I. \ -I${top_srcdir}/interface \ ${COVERAGE_FLAGS} \ - ${MYSQL_CPPFLAGS} \ -D_GNU_SOURCE ifdef LBS_DB_PROFILE CFLAGS:=${CFLAGS} -DLBS_DB_PROFILE endif +ifneq (${mysql-devel_prefix},no) + OBJS:=${OBJS} db-mysql.o + CFLAGS:=${CFLAGS} -DMYSQL_SONAME=\"${MYSQL_SONAME}\" +endif +ifneq (${postgresql_prefix},no) + OBJS:=${OBJS} db-pg.o + CFLAGS:=${CFLAGS} -DPSQL_SONAME=\"${PSQL_SONAME}\" +endif TEST_LIBS:=-L${cppunit_prefix}/lib -lcppunit TEST_INC:=-I${cppunit_prefix}/include @@ -59,9 +65,9 @@ COMPILE:=libtool --mode=compile ${CC} ${CFLAGS} LINK:=libtool --mode=link ${CC} -rpath ${stagedir}/lib ${LDFLAGS} INSTALL:=libtool --mode=install install -EXT_LIBS:=${MYSQL_LIBS} -lglite_lbu_trio -lpthread -ldl -OBJS:=db.o -TESTOBJS:=dbtest.o +EXT_LIBS:=-lglite_lbu_trio -lpthread -ldl +TESTOBJS:=${OBJS} dbtest.o +OBJS:=${OBJS} db.o HDRS:=db.h LOBJS:=${OBJS:.o=.lo} LTESTOBJS:=${TESTOBJS:.o=.lo} @@ -69,18 +75,26 @@ LTESTOBJS:=${TESTOBJS:.o=.lo} default all: compile doc check_soname: - if [ "${MYSQL_SONAME}" = notfound ]; then \ - echo "MySQL shared library not found!"; \ - false; \ + if [ "${mysql-devel_prefix}" != no ]; then \ + if [ "${MYSQL_SONAME}" = notfound ]; then \ + echo "MySQL shared library not found!"; \ + false; \ + fi \ + fi + if [ "${postgresql_prefix}" != no ]; then \ + if [ "${PSQL_SONAME}" = notfound ]; then \ + echo "PostgreSQL shared library not found!"; \ + false; \ + fi \ fi db.lo: check_soname libglite_lbu_db.la: ${LOBJS} - ${LINK} -o $@ $< ${EXT_LIBS} + ${LINK} -o $@ $+ ${EXT_LIBS} libglite_lbu_dbtest.la: ${LTESTOBJS} - ${LINK} -o $@ $< ${EXT_LIBS} + ${LINK} -o $@ $+ ${EXT_LIBS} dbtest.lo dbtest.o: db.c db.h ${COMPILE} -DGLITE_LBU_DEFAULT_RESULT_BUFFER_LENGTH=10 -c $< -o $@ @@ -107,7 +121,7 @@ doc: olddoc: cp ${top_srcdir}/doc/*.dox . - echo "PROJECT_NUMBER = ${version}" >> C.dox + echo "PROJECT_NUMBER = ${module.version}" >> C.dox doxygen C.dox stage: compile @@ -116,22 +130,22 @@ stage: compile dist: distsrc distbin distsrc: - mkdir -p ${top_srcdir}/${package}-${version} - cd ${top_srcdir} && GLOBIGNORE="${package}-${version}" && cp -Rf * ${package}-${version} - cd ${top_srcdir} && tar -czf ${distdir}/${package}-${version}_src.tar.gz --exclude-from=project/tar_exclude ${package}-${version} - rm -rf ${top_srcdir}/${package}-${version} + mkdir -p ${top_srcdir}/${package}-${module.version} + cd ${top_srcdir} && GLOBIGNORE="${package}-${module.version}" && cp -Rf * ${package}-${module.version} + cd ${top_srcdir} && tar -czf ${distdir}/${package}-${module.version}_src.tar.gz --exclude-from=project/tar_exclude ${package}-${module.version} + rm -rf ${top_srcdir}/${package}-${module.version} distbin: $(MAKE) install PREFIX=`pwd`/tmpbuilddir${stagedir} - save_dir=`pwd`; cd tmpbuilddir${stagedir} && tar -czf $$save_dir/${top_srcdir}/${distdir}/${package}-${version}_bin.tar.gz *; cd $$save_dir + save_dir=`pwd`; cd tmpbuilddir${stagedir} && tar -czf $$save_dir/${top_srcdir}/${distdir}/${package}-${module.version}_bin.tar.gz *; cd $$save_dir rm -rf tmpbuilddir install: all -mkdir -p ${PREFIX}/lib - -mkdir -p ${PREFIX}/share/doc/${package}-${version} + -mkdir -p ${PREFIX}/share/doc/${package}-${module.version} -mkdir -p ${PREFIX}/include/${globalprefix}/${lbutilsprefix} - ${INSTALL} -m 644 ${top_srcdir}/LICENSE ${PREFIX}/share/doc/${package}-${version} - -cp -r C ${PREFIX}/share/doc/${package}-${version} + ${INSTALL} -m 644 ${top_srcdir}/LICENSE ${PREFIX}/share/doc/${package}-${module.version} + -cp -r C ${PREFIX}/share/doc/${package}-${module.version} ${INSTALL} -m 755 "libglite_lbu_db.la" "${PREFIX}/lib/libglite_lbu_db.la"; \ ${INSTALL} -m 644 ${top_srcdir}/interface/${HDRS} ${PREFIX}/include/${globalprefix}/${lbutilsprefix} @@ -140,10 +154,18 @@ clean: rm -rvf log.xml project/ rpmbuild/ RPMS/ tgz/ rm -rvf db_expire db_test +db-mysql.o db-mysql.lo: db-mysql.c + ${COMPILE} ${MYSQL_CPPFLAGS} -c $< + +db-pg.o db-pg.lo: db-pg.c + ${COMPILE} ${PSQL_CPPFLAGS} -c $< + %.o %.lo: %.c ${COMPILE} -c $< -db.lo: db.c db.h -db_test.lo: libglite_lbu_dbtest.la db.h db_test.c +db.lo: db.c db.h db-int.h +db_test.lo: libglite_lbu_dbtest.la db.h db-int.h db_test.c +db-mysql.lo: db-mysql.c db-int.h db.h +db-pg.lo: db-pg.c db-int.h db.h .PHONY: default all compile check examples doc stage dist distsrc distbin install clean test_coverage diff --git a/org.glite.lbjp-common.db/interface/db-int.h b/org.glite.lbjp-common.db/interface/db-int.h new file mode 100644 index 0000000..4df0a9a --- /dev/null +++ b/org.glite.lbjp-common.db/interface/db-int.h @@ -0,0 +1,59 @@ + +#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); +void glite_lbu_TimeToStr(time_t t, char **str); +void glite_lbu_TimestampToStr(double t, char **str); +time_t glite_lbu_StrToTime(const char *str); +double glite_lbu_StrToTimestamp(const char *str); diff --git a/org.glite.lbjp-common.db/interface/db.h b/org.glite.lbjp-common.db/interface/db.h index bd7d7e0..6c36a4d 100644 --- a/org.glite.lbjp-common.db/interface/db.h +++ b/org.glite.lbjp-common.db/interface/db.h @@ -1,9 +1,6 @@ #ifndef GLITE_LBU_DB_H #define GLITE_LBU_DB_H -#ident "$Header$" - - #include #include @@ -20,12 +17,13 @@ extern "C" { * Database modul module API (LB & JP Utils). * * There are two ways to access DB here: - * - simple: * + * - simple: * SQL commands as single string. All values are incorporated in the SQL command strings. Proper escaping is required. - * - enhanced: * + * - enhanced: * Prepared SQL commands with separated parameters, functions PrepareStmt() and ExecPreparedStmt(). All values are delivered in separated buffers. Its faster for multiple using and more secure. + * * @{ */ @@ -105,6 +103,16 @@ typedef enum { /** + * Supported DB backends. + */ +typedef enum { + GLITE_LBU_DB_BACKEND_MYSQL = 0, + GLITE_LBU_DB_BACKEND_PSQL, + GLITE_LBU_DB_BACKEND_LAST +} glite_lbu_DBBackendNo; + + +/** * Get error state from DB context. * * \param[in] ctx context to work with @@ -115,11 +123,21 @@ int glite_lbu_DBError(glite_lbu_DBContext ctx, char **text, char **desc); /** + * Clear the error from DB context. + * + * \param[in] ctx context to work with + */ +int glite_lbu_DBClearError(glite_lbu_DBContext ctx); + + +/** * Initialize the database context. * * \param[out] ctx result context + * \param[in] backend required database backend + * \return error code */ -int glite_lbu_InitDBContext(glite_lbu_DBContext *ctx); +int glite_lbu_InitDBContext(glite_lbu_DBContext *ctx, int backend); /** @@ -257,7 +275,7 @@ int glite_lbu_QueryIndices(glite_lbu_DBContext ctx, const char *table, char ***k * \param[in] t the converted time * \param[out] str result allocated string */ -void glite_lbu_TimeToDB(time_t t, char **str); +void glite_lbu_TimeToDB(glite_lbu_DBContext ctx, time_t t, char **str); /** @@ -268,7 +286,7 @@ void glite_lbu_TimeToDB(time_t t, char **str); * \param[in] t the converted time * \param[out] str result allocated string */ -void glite_lbu_TimestampToDB(double t, char **str); +void glite_lbu_TimestampToDB(glite_lbu_DBContext ctx, double t, char **str); /** @@ -276,10 +294,21 @@ void glite_lbu_TimestampToDB(double t, char **str); * * String is expected in database for (ISO format). * + * \param[in] ctx context to work with * \param[in] str the converted string * \return result time */ -time_t glite_lbu_DBToTime(const char *str); +time_t glite_lbu_DBToTime(glite_lbu_DBContext ctx, const char *str); + + +/** + * Convert database-specific time string to time (double). + * + * \param[in] ctx context to work with + * \param[in] str the converted string + * \return result time + * */ +double glite_lbu_DBToTimestamp(glite_lbu_DBContext ctx, const char *str); /** diff --git a/org.glite.lbjp-common.db/project/get_soname.sh b/org.glite.lbjp-common.db/project/get_soname.sh index d5f41b3..66c6aab 100755 --- a/org.glite.lbjp-common.db/project/get_soname.sh +++ b/org.glite.lbjp-common.db/project/get_soname.sh @@ -1,9 +1,11 @@ #! /bin/sh lib="" +filename="lib$1.so" +shift for prefix in $@; do for dir in "$prefix" "$prefix/mysql"; do - l=`find $dir -maxdepth 1 -name libmysqlclient.so* | head -n 1` + l=`find $dir -maxdepth 1 -name "${filename}"* 2>/dev/null | head -n 1` if [ -f "$l" ]; then lib=$l break @@ -15,7 +17,7 @@ for prefix in $@; do done if [ x"" != x"$lib" ]; then - readelf -d $lib | grep SONAME | sed 's/.*\(libmysqlclient.so.[0-9]\{1,\}\).*/\1/' + readelf -d $lib | grep SONAME | sed "s/.*\(${filename}.[0-9]\{1,\}\).*/\1/" else echo notfound fi diff --git a/org.glite.lbjp-common.db/src/db-mysql.c b/org.glite.lbjp-common.db/src/db-mysql.c index 1c91526..971616f 100644 --- a/org.glite.lbjp-common.db/src/db-mysql.c +++ b/org.glite.lbjp-common.db/src/db-mysql.c @@ -1,5 +1,3 @@ -#ident "$Header$" - #include #ifdef LBS_DB_PROFILE #include @@ -23,6 +21,7 @@ #include "glite/lbu/trio.h" #include "db.h" +#include "db-int.h" #define GLITE_LBU_MYSQL_INDEX_VERSION 40001 @@ -32,36 +31,31 @@ #define GLITE_LBU_DEFAULT_RESULT_BUFFER_LENGTH 256 #endif -#define CLR_ERR(CTX) lbu_clrerr((CTX)) -#define ERR(CTX, CODE, ARGS...) lbu_err((CTX), (CODE), __FUNCTION__, __LINE__, ##ARGS) -#define STATUS(CTX) ((CTX)->err.code) +#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->caps & GLITE_LBU_DB_CAP_TRANSACTIONS) != 0) -#define LOAD(SYM, SYM2) if ((*(void **)(&db_handle.SYM) = dlsym(db_handle.lib, SYM2)) == NULL) { \ - err = ERR(*ctx, ENOENT, "can't load symbol %s from mysql library (%s)", SYM2, dlerror()); \ +#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; \ } -#define dprintf(CTX, FMT...) if (CTX->caps & GLITE_LBU_DB_CAP_ERRORS) fprintf(stderr, ##FMT) -struct glite_lbu_DBContext_s { - MYSQL *mysql; - const char *cs; - int caps; - struct { - int code; - char *desc; - } err; +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_Statement_s { - glite_lbu_DBContext ctx; +struct glite_lbu_StatementMysql_s { + glite_lbu_Statement_t generic; /* for simple commands */ MYSQL_RES *result; @@ -71,20 +65,7 @@ struct glite_lbu_Statement_s { unsigned long nrfields; char *sql; }; - - -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 */ -}; +typedef struct glite_lbu_StatementMysql_s *glite_lbu_StatementMysql; /* @@ -145,56 +126,93 @@ typedef struct { my_ulonglong (*mysql_stmt_affected_rows)(MYSQL_STMT *stmt); MYSQL_RES *(*mysql_stmt_result_metadata)(MYSQL_STMT *stmt); int (*mysql_stmt_fetch_column)(MYSQL_STMT *stmt, MYSQL_BIND *bind, unsigned int column, unsigned long offset); -} mysql_lib_handle_t; - +} 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_lib_handle_t db_handle = { +static mysql_module_t mysql_module = { lib: NULL, - lock: PTHREAD_MUTEX_INITIALIZER + lock: PTHREAD_MUTEX_INITIALIZER, }; -static int lbu_clrerr(glite_lbu_DBContext ctx); -static int lbu_err(glite_lbu_DBContext ctx, int code, const char *func, int line, const char *desc, ...); -static int myerr(glite_lbu_DBContext ctx, const char *source, int line); -static int myerrstmt(glite_lbu_Statement stmt, const char *source, int line); -static int myisokstmt(glite_lbu_Statement stmt, const char *source, int line, int *retry); -static int db_connect(glite_lbu_DBContext ctx, const char *cs, MYSQL **mysql); +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); -static int FetchRowSimple(glite_lbu_DBContext ctx, MYSQL_RES *result, unsigned long *lengths, char **results); -static int FetchRowPrepared(glite_lbu_DBContext ctx, glite_lbu_Statement stmt, unsigned int n, unsigned long *lengths, char **results); +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_Statement stmt); +static void glite_lbu_FreeStmt_int(glite_lbu_StatementMysql stmt); /* ---- common ---- */ -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 glite_lbu_InitDBContextMysql(glite_lbu_DBContext *ctx_gen) { + glite_lbu_DBContextMysql ctx; int err = 0; - unsigned int ver_u; + int ver_u; - *ctx = calloc(1, sizeof **ctx); - if (!*ctx) return ENOMEM; + ctx = calloc(1, sizeof *ctx); + if (!ctx) return ENOMEM; + *ctx_gen = (glite_lbu_DBContext)ctx; /* dynamic load the mysql library */ - pthread_mutex_lock(&db_handle.lock); - if (!db_handle.lib) { - db_handle.lib = dlopen(MYSQL_SONAME, RTLD_LAZY | RTLD_LOCAL); - if (!db_handle.lib) return ERR(*ctx, ENOENT, "dlopen(): " MYSQL_SONAME ": %s", dlerror()); + 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"); @@ -228,63 +246,68 @@ int glite_lbu_InitDBContext(glite_lbu_DBContext *ctx) { LOAD(mysql_stmt_fetch_column, "mysql_stmt_fetch_column"); // check the runtime version - ver_u = db_handle.mysql_get_client_version(); + ver_u = mysql_module.mysql_get_client_version(); if (ver_u != MYSQL_VERSION_ID) { - fprintf(stderr,"Warning: MySQL library version mismatch (compiled '%lu', runtime '%lu')", MYSQL_VERSION_ID, ver_u); - syslog(LOG_WARNING,"MySQL library version mismatch (compiled '%lu', runtime '%lu')", MYSQL_VERSION_ID, ver_u); + fprintf(stderr,"Warning: MySQL library version mismatch (compiled '%d', runtime '%d')", MYSQL_VERSION_ID, ver_u); + syslog(LOG_WARNING,"MySQL library version mismatch (compiled '%d', runtime '%d')", MYSQL_VERSION_ID, ver_u); } - pthread_mutex_unlock(&db_handle.lock); + pthread_mutex_unlock(&mysql_module.lock); atexit(glite_lbu_DBCleanup); } while(0); if (err) { - dlclose(db_handle.lib); - db_handle.lib = NULL; - pthread_mutex_unlock(&db_handle.lock); + dlclose(mysql_module.lib); + mysql_module.lib = NULL; + pthread_mutex_unlock(&mysql_module.lock); return err; } - } else pthread_mutex_unlock(&db_handle.lock); + } else pthread_mutex_unlock(&mysql_module.lock); return 0; } -void glite_lbu_FreeDBContext(glite_lbu_DBContext ctx) { +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->err.desc); free(ctx); } } -int glite_lbu_DBConnect(glite_lbu_DBContext ctx, const char *cs) { +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_ExecSQL(ctx, "SET AUTOCOMMIT=1", NULL) < 0 || - glite_lbu_ExecSQL(ctx, "SET TRANSACTION ISOLATION LEVEL REPEATABLE READ", NULL) < 0) + glite_lbu_ExecSQL(ctx_gen, "SET AUTOCOMMIT=1", NULL) < 0 || + glite_lbu_ExecSQL(ctx_gen, "SET TRANSACTION ISOLATION LEVEL REPEATABLE READ", NULL) < 0) return STATUS(ctx); else return 0; } -void glite_lbu_DBClose(glite_lbu_DBContext ctx) { +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_DBQueryCaps(glite_lbu_DBContext 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,origcaps; + int major,minor,sub,version,caps; const char *ver_s; - origcaps = ctx->caps; caps = 0; - ver_s = db_handle.mysql_get_server_info(m); + 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; @@ -293,25 +316,25 @@ int glite_lbu_DBQueryCaps(glite_lbu_DBContext ctx) { if (version >= GLITE_LBU_MYSQL_PREPARED_VERSION) caps |= GLITE_LBU_DB_CAP_PREPARED; CLR_ERR(ctx); - transaction_test(ctx); - if ((ctx->caps & GLITE_LBU_DB_CAP_TRANSACTIONS)) caps |= GLITE_LBU_DB_CAP_TRANSACTIONS; + transaction_test(ctx_gen, &caps); - ctx->caps = origcaps; if (STATUS(ctx) == 0) return caps; else return -1; } -void glite_lbu_DBSetCaps(glite_lbu_DBContext ctx, int caps) { - ctx->caps = caps; +void glite_lbu_DBSetCapsMysql(glite_lbu_DBContext ctx_gen, int caps) { + ctx_gen->caps = caps; } -int glite_lbu_Transaction(glite_lbu_DBContext ctx) { +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_ExecSQL(ctx, "SET AUTOCOMMIT=0", NULL) < 0) goto err; - if (glite_lbu_ExecSQL(ctx, "BEGIN", NULL) < 0) goto err; + if (glite_lbu_ExecSQL(ctx_gen, "SET AUTOCOMMIT=0", NULL) < 0) goto err; + if (glite_lbu_ExecSQL(ctx_gen, "BEGIN", NULL) < 0) goto err; ctx->in_transaction = 1; } err: @@ -319,11 +342,13 @@ err: } -int glite_lbu_Commit(glite_lbu_DBContext 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_ExecSQL(ctx, "COMMIT", NULL) < 0) goto err; - if (glite_lbu_ExecSQL(ctx, "SET AUTOCOMMIT=1", NULL) < 0) goto err; + if (glite_lbu_ExecSQL(ctx_gen, "COMMIT", NULL) < 0) goto err; + if (glite_lbu_ExecSQL(ctx_gen, "SET AUTOCOMMIT=1", NULL) < 0) goto err; ctx->in_transaction = 0; } err: @@ -331,11 +356,13 @@ err: } -int glite_lbu_Rollback(glite_lbu_DBContext 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_ExecSQL(ctx, "ROLLBACK", NULL) < 0) goto err; - if (glite_lbu_ExecSQL(ctx, "SET AUTOCOMMIT=1", NULL) < 0) goto err; + if (glite_lbu_ExecSQL(ctx_gen, "ROLLBACK", NULL) < 0) goto err; + if (glite_lbu_ExecSQL(ctx_gen, "SET AUTOCOMMIT=1", NULL) < 0) goto err; ctx->in_transaction = 0; } err: @@ -343,31 +370,37 @@ err: } -int glite_lbu_FetchRow(glite_lbu_Statement stmt, unsigned int n, unsigned long *lengths, char **results) { +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(stmt->ctx, stmt->result, lengths, results); - else return FetchRowPrepared(stmt->ctx, stmt, n, lengths, 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_Statement stmt) { +static void glite_lbu_FreeStmt_int(glite_lbu_StatementMysql stmt) { if (stmt) { - if (stmt->result) db_handle.mysql_free_result(stmt->result); - if (stmt->stmt) db_handle.mysql_stmt_close(stmt->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_FreeStmt(glite_lbu_Statement *stmt) { +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_QueryIndices(glite_lbu_DBContext ctx, const char *table, char ***key_names, char ****column_names) { - glite_lbu_Statement 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; @@ -386,18 +419,18 @@ int glite_lbu_QueryIndices(glite_lbu_DBContext ctx, const char *table, char ***k Key_name = Seq_in_index = Column_name = Sub_part = -1; asprintf(&sql, "show index from %s", table); - if (glite_lbu_ExecSQL(ctx,sql,&stmt)<0) { + if (glite_lbu_ExecSQLMysql(ctx_gen,sql,&stmt)<0) { free(sql); return STATUS(ctx); } free(sql); - while ((ret = glite_lbu_FetchRow(stmt,sizeof(showcol)/sizeof(showcol[0]),NULL,showcol)) > 0) { + 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_QueryColumns(stmt,col_names); + glite_lbu_QueryColumnsMysql(stmt,col_names); for (i=0; imysql, cmd)) { + if (mysql_module.mysql_query(ctx->mysql, cmd)) { /* error occured */ - switch (merr = db_handle.mysql_errno(ctx->mysql)) { + switch (merr = mysql_module.mysql_errno(ctx->mysql)) { case 0: break; case ER_DUP_ENTRY: - ERR(ctx, EEXIST, db_handle.mysql_error(ctx->mysql)); + 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, db_handle.mysql_error(ctx->mysql)); + 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, db_handle.mysql_error(ctx->mysql)); + ERR(ctx, EDEADLOCK, mysql_module.mysql_error(ctx->mysql)); return -1; break; default: @@ -519,24 +555,25 @@ int glite_lbu_ExecSQL(glite_lbu_DBContext ctx, const char *cmd, glite_lbu_Statem retry_nr++; } - if (stmt) { - *stmt = calloc(1, sizeof(**stmt)); - if (!*stmt) { + if (stmt_gen) { + stmt = calloc(1, sizeof(*stmt)); + if (!stmt) { ERR(ctx, ENOMEM, NULL); return -1; } - (**stmt).ctx = ctx; - (**stmt).result = db_handle.mysql_store_result(ctx->mysql); - if (!(**stmt).result) { - if (db_handle.mysql_errno(ctx->mysql)) { + 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); - *stmt = NULL; + free(stmt); return -1; } } + *stmt_gen = (glite_lbu_Statement)stmt; } else { - MYSQL_RES *r = db_handle.mysql_store_result(ctx->mysql); - db_handle.mysql_free_result(r); + MYSQL_RES *r = mysql_module.mysql_store_result(ctx->mysql); + mysql_module.mysql_free_result(r); } #ifdef LBS_DB_PROFILE pid = getpid(); @@ -551,102 +588,76 @@ int glite_lbu_ExecSQL(glite_lbu_DBContext ctx, const char *cmd, glite_lbu_Statem 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 db_handle.mysql_affected_rows(ctx->mysql); + return mysql_module.mysql_affected_rows(ctx->mysql); } -int glite_lbu_QueryColumns(glite_lbu_Statement stmt, char **cols) +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->ctx); - if (!stmt->result) return ERR(stmt->ctx, EINVAL, "QueryColumns implemented only for simple API"); - while ((f = db_handle.mysql_fetch_field(stmt->result))) cols[i++] = f->name; + 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; } -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); -} - /* ---- prepared --- */ -int glite_lbu_PrepareStmt(glite_lbu_DBContext ctx, const char *sql, glite_lbu_Statement *stmt) { +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)->ctx = ctx; + stmt = calloc(1, sizeof(*stmt)); + stmt->generic.ctx = ctx_gen; + *stmt_gen = NULL; // create the SQL command - if (((*stmt)->stmt = db_handle.mysql_stmt_init(ctx->mysql)) == NULL) - return MY_ERRSTMT(*stmt); + if ((stmt->stmt = mysql_module.mysql_stmt_init(ctx->mysql)) == NULL) + return STATUS(ctx); // prepare the SQL command retry = 1; do { - db_handle.mysql_stmt_prepare((*stmt)->stmt, sql, strlen(sql)); - ret = MY_ISOKSTMT(*stmt, &retry); + 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 = db_handle.mysql_stmt_result_metadata((*stmt)->stmt)) != NULL) { - (*stmt)->nrfields = db_handle.mysql_num_fields(meta); - db_handle.mysql_free_result(meta); + 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; + stmt->nrfields = 0; // remember the command - (*stmt)->sql = strdup(sql); + stmt->sql = strdup(sql); + *stmt_gen = (glite_lbu_Statement)stmt; return CLR_ERR(ctx); failed: - glite_lbu_FreeStmt(stmt); + glite_lbu_FreeStmt_int(stmt); + free(stmt); return STATUS(ctx); } -int glite_lbu_ExecPreparedStmt_v(glite_lbu_Statement stmt, int n, va_list ap) { +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; - glite_lbu_DBContext ctx; int ret, retry; MYSQL_BIND *binds = NULL; void **data = NULL; @@ -723,7 +734,7 @@ int glite_lbu_ExecPreparedStmt_v(glite_lbu_Statement stmt, int n, va_list ap) { do { // bind parameters if (n) { - if (db_handle.mysql_stmt_bind_param(stmt->stmt, binds) != 0) { + if (mysql_module.mysql_stmt_bind_param(stmt->stmt, binds) != 0) { MY_ERRSTMT(stmt); ret = -1; goto statement_failed; @@ -731,19 +742,18 @@ int glite_lbu_ExecPreparedStmt_v(glite_lbu_Statement stmt, int n, va_list ap) { } // run - ctx = stmt->ctx; retry = 1; do { - db_handle.mysql_stmt_execute(stmt->stmt); + mysql_module.mysql_stmt_execute(stmt->stmt); ret = MY_ISOKSTMT(stmt, &retry); } while (ret == 0); statement_failed: if (ret == -1) { - if (db_handle.mysql_stmt_errno(stmt->stmt) == ER_UNKNOWN_STMT_HANDLER) { + if (mysql_module.mysql_stmt_errno(stmt->stmt) == ER_UNKNOWN_STMT_HANDLER) { // expired the prepared command ==> restore it - if (glite_lbu_PrepareStmt(stmt->ctx, stmt->sql, &newstmt) == -1) goto failed; + if (glite_lbu_PrepareStmt(stmt->generic.ctx, stmt->sql, &newstmt) == -1) goto failed; glite_lbu_FreeStmt_int(stmt); - memcpy(stmt, newstmt, sizeof(struct glite_lbu_Statement_s)); + memcpy(stmt, newstmt, sizeof(struct glite_lbu_StatementMysql_s)); prepare_retry--; ret = 0; } else goto failed; @@ -753,7 +763,7 @@ int glite_lbu_ExecPreparedStmt_v(glite_lbu_Statement stmt, int n, va_list ap) { // result retry = 1; do { - db_handle.mysql_stmt_store_result(stmt->stmt); + mysql_module.mysql_stmt_store_result(stmt->stmt); ret = MY_ISOKSTMT(stmt, &retry); } while (ret == 0); if (ret == -1) goto failed; @@ -765,8 +775,8 @@ int glite_lbu_ExecPreparedStmt_v(glite_lbu_Statement stmt, int n, va_list ap) { free(binds); free(lens); } - CLR_ERR(ctx); - return db_handle.mysql_stmt_affected_rows(stmt->stmt); + CLR_ERR(stmt->generic.ctx); + return mysql_module.mysql_stmt_affected_rows(stmt->stmt); failed: for (i = 0; i < n; i++) free(data[i]); @@ -777,167 +787,30 @@ failed: } -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; -} - - -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); -} - - -long int glite_lbu_Lastid(glite_lbu_Statement stmt) { +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->ctx); - i = db_handle.mysql_stmt_insert_id(stmt->stmt); + 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 compatibility function: clear error from the context - */ -static int lbu_clrerr(glite_lbu_DBContext ctx) { - ctx->err.code = 0; - if (ctx->err.desc) { - free(ctx->err.desc); - ctx->err.desc = NULL; - } - return 0; -} - - -/* - * helping compatibility function: sets error on the context - */ -static int lbu_err(glite_lbu_DBContext ctx, int code, const char *func, int line, const char *desc, ...) { - va_list ap; - - if (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, desc ? ctx->err.desc : ""); - return code; - } else - return ctx->err.code; -} - - -/* * helping function: find oud mysql error and sets on the context */ -static int myerr(glite_lbu_DBContext ctx, const char *source, int line) { - return lbu_err(ctx, EIO, source, line, db_handle.mysql_error(ctx->mysql)); +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_Statement stmt, const char *source, int line) { - return lbu_err(stmt->ctx, EIO, source, line, db_handle.mysql_stmt_error(stmt->stmt)); +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)); } @@ -948,13 +821,13 @@ static int myerrstmt(glite_lbu_Statement stmt, const char *source, int line) { * \return 0 retry * \return 1 OK */ -static int myisokstmt(glite_lbu_Statement stmt, const char *source, int line, int *retry) { - switch (db_handle.mysql_stmt_errno(stmt->stmt)) { +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: - lbu_err(stmt->ctx, EEXIST, source, line, db_handle.mysql_stmt_error(stmt->stmt)); + glite_lbu_DBSetError(stmt->generic.ctx, EEXIST, source, line, mysql_module.mysql_stmt_error(stmt->stmt)); return -1; break; case CR_SERVER_LOST: @@ -978,7 +851,7 @@ static int myisokstmt(glite_lbu_Statement stmt, const char *source, int line, in /* * mysql connect */ -static int db_connect(glite_lbu_DBContext ctx, const char *cs, MYSQL **mysql) { +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; @@ -992,12 +865,12 @@ static int db_connect(glite_lbu_DBContext ctx, const char *cs, MYSQL **mysql) { if (!cs) return ERR(ctx, EINVAL, "connect string not specified"); - if (!(*mysql = db_handle.mysql_init(NULL))) return ERR(ctx, ENOMEM, NULL); + if (!(*mysql = mysql_module.mysql_init(NULL))) return ERR(ctx, ENOMEM, NULL); - db_handle.mysql_options(*mysql, MYSQL_READ_DEFAULT_FILE, "my"); + 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 */ - db_handle.mysql_options(*mysql, MYSQL_OPT_RECONNECT, &reconnect); + mysql_module.mysql_options(*mysql, MYSQL_OPT_RECONNECT, &reconnect); #endif host = user = pw = db = NULL; @@ -1023,19 +896,15 @@ static int db_connect(glite_lbu_DBContext ctx, const char *cs, MYSQL **mysql) { /* ljocha: CLIENT_FOUND_ROWS added to make authorization check * working in update_notif(). * Hope it does not break anything else */ - if (!db_handle.mysql_real_connect(*mysql,host,user,pw,db,0,NULL,CLIENT_FOUND_ROWS)) { - char *desc; - free(buf); + if (!mysql_module.mysql_real_connect(*mysql,host,user,pw,db,0,NULL,CLIENT_FOUND_ROWS)) { ret = MY_ERR(ctx); - desc = ctx->err.desc; - ctx->err.desc = NULL; - glite_lbu_DBClose(ctx); - ctx->err.desc = desc; - return ctx->err.code = ret; + db_close(*mysql); + *mysql = NULL; + free(buf); + return ret; } free(buf); - ctx->cs = cs; return CLR_ERR(ctx); } @@ -1044,39 +913,39 @@ static int db_connect(glite_lbu_DBContext ctx, const char *cs, MYSQL **mysql) { * mysql close */ static void db_close(MYSQL *mysql) { - if (mysql) db_handle.mysql_close(mysql); + if (mysql) mysql_module.mysql_close(mysql); } /* * test transactions capability: */ -static int transaction_test(glite_lbu_DBContext ctx) { +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; - ctx->caps &= ~GLITE_LBU_DB_CAP_TRANSACTIONS; + (*caps) &= ~GLITE_LBU_DB_CAP_TRANSACTIONS; - if ((retval = glite_lbu_ExecSQL(ctx, "SHOW TABLES", &stmt)) <= 0 || glite_lbu_FetchRow(stmt, 1, NULL, table) < 0) goto quit; + if ((retval = glite_lbu_ExecSQLMysql(ctx, "SHOW TABLES", &stmt)) <= 0 || glite_lbu_FetchRowMysql(stmt, 1, NULL, table) < 0) goto quit; glite_lbu_FreeStmt(&stmt); trio_asprintf(&cmd, "SHOW CREATE TABLE %|Ss", table[0]); - if (glite_lbu_ExecSQL(ctx, cmd, &stmt) <= 0 || (retval = glite_lbu_FetchRow(stmt, 2, NULL, res)) < 0 ) goto quit; + 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")) - ctx->caps |= GLITE_LBU_DB_CAP_TRANSACTIONS; + (*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_FreeStmt(&stmt); + glite_lbu_FreeStmtMysql(&stmt); free(table[0]); free(res[0]); free(res[1]); @@ -1088,22 +957,22 @@ quit: /* * simple version of the fetch */ -static int FetchRowSimple(glite_lbu_DBContext ctx, MYSQL_RES *result, unsigned long *lengths, char **results) { +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 = db_handle.mysql_fetch_row(result))) { - if (db_handle.mysql_errno((MYSQL *) ctx->mysql)) { + 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 = db_handle.mysql_num_fields(result); - len = db_handle.mysql_fetch_lengths(result); + nr = mysql_module.mysql_num_fields(result); + len = mysql_module.mysql_fetch_lengths(result); for (i=0; istmt, binds) != 0) goto failedstmt; + if (mysql_module.mysql_stmt_bind_result(stmt->stmt, binds) != 0) goto failedstmt; // fetch data, all can be truncated retry = 1; do { - switch(db_handle.mysql_stmt_fetch(stmt->stmt)) { + switch(mysql_module.mysql_stmt_fetch(stmt->stmt)) { #ifdef MYSQL_DATA_TRUNCATED case MYSQL_DATA_TRUNCATED: #endif @@ -1179,7 +1048,7 @@ static int FetchRowPrepared(glite_lbu_DBContext ctx, glite_lbu_Statement stmt, u retry = 1; do { - switch (db_handle.mysql_stmt_fetch_column(stmt->stmt, binds + i, i, fetched)) { + 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 */ @@ -1228,12 +1097,12 @@ static void set_time(MYSQL_TIME *mtime, const double time) { static void glite_lbu_DBCleanup(void) { - pthread_mutex_lock(&db_handle.lock); - if (db_handle.lib) { - dlclose(db_handle.lib); - db_handle.lib = NULL; + pthread_mutex_lock(&mysql_module.lock); + if (mysql_module.lib) { + dlclose(mysql_module.lib); + mysql_module.lib = NULL; } - pthread_mutex_unlock(&db_handle.lock); + pthread_mutex_unlock(&mysql_module.lock); } diff --git a/org.glite.lbjp-common.db/src/db.c b/org.glite.lbjp-common.db/src/db.c new file mode 100644 index 0000000..c799165 --- /dev/null +++ b/org.glite.lbjp-common.db/src/db.c @@ -0,0 +1,392 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +#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)); + 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); +} + + +double glite_lbu_StrToTimestamp(const char *str) { + struct tm tm; + double sec; + + memset(&tm,0,sizeof(tm)); + setenv("TZ","UTC",1); 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) { + if (!VALID(backend)) return EINVAL; + if (backends[backend]->backend != backend) return ENOTSUP; + return backends[backend]->initContext(ctx); +} + + +void glite_lbu_FreeDBContext(glite_lbu_DBContext ctx) { + if (!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 (!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); +}