--- /dev/null
+# defaults
+top_srcdir=.
+builddir=build
+top_builddir=${top_srcdir}/${builddir}
+stagedir=.
+distdir=.
+globalprefix=glite
+jpprefix=jp
+package=glite-jp-server-common
+version=0.0.0
+PREFIX=/opt/glite
+
+glite_location=/opt/glite
+globus_prefix=/opt/globus
+nothrflavour=gcc32
+thrflavour=gcc32pthr
+expat_prefix=/opt/expat
+ares_prefix=/opt/ares
+gsoap_prefix=/software/gsoap-2.6
+
+CC=gcc
+
+-include Makefile.inc
+
+
+VPATH=${top_srcdir}/src:${top_srcdir}/examples:${top_srcdir}/test:${top_srcdir}/project:${jpproject}:${stagedir}/interface
+
+DEBUG:=-g -O0 -W -Wall -DDEBUG
+CPPFLAGS:=-I. -I${top_srcdir}/interface -I${top_srcdir}/src -I${stagedir}/include -I${mysql_prefix}/include -I${mysql_prefix}/include/mysql
+CFLAGS:=${DEBUG} -D_GNU_SOURCE
+LDFLAGS:=-L${stagedir}/lib
+
+COMPILE:=libtool --mode=compile ${CC} ${CPPFLAGS} ${CFLAGS}
+LINK:=libtool --mode=link ${CC} -rpath ${stagedir}/lib ${LDFLAGS}
+INSTALL:=libtool --mode=install install
+
+# FIXME: to use libtool versioning correcty, we should have:
+#
+# current = major + minor + offset
+# revision = patch
+# age = minor
+#
+# where offset is a sum of maximal released minor's of all previous major's
+#
+version_info=-version-info `echo ${version} | cut -d. -f1,2 | tr . :`
+
+STATICLIB:=libglite_jp_server_common.a
+LTLIB:=libglite_jp_server_common.la
+
+
+SRCS:=db.c
+HDRS:=db.h
+OBJS:=${SRCS:.c=.o}
+LOBJS:=${OBJS:.o=.lo}
+
+ifneq (${mysql_prefix},/usr)
+ ifeq ($(shell echo ${mysql_version} | cut -d. -f1,2),4.1)
+ MYSQLIB := -L${mysql_prefix}/lib/mysql -lmysqlclient
+ else
+ MYSQLIB := -L${mysql_prefix}/lib -lmysqlclient
+ endif
+else
+ MYSQLIB := -lmysqlclient
+endif
+
+
+default all: compile
+
+compile: ${LTLIB} ${STATICLIB}
+
+${LTLIB} ${STATICLIB}: ${OBJS}
+ ${LINK} ${version_info} -o $@ ${LOBJS} ${MYSQLIB}
+
+check:
+ -echo nothing yet
+
+doc:
+
+stage: compile
+ $(MAKE) install PREFIX=${stagedir}
+
+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}
+
+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
+ rm -rf tmpbuilddir
+
+install:
+ ${INSTALL} -m 755 ${LTLIB} ${PREFIX}/lib
+ for f in ${HDRS}; do \
+ ${INSTALL} -m 644 ${top_srcdir}/interface/"$$f" ${PREFIX}/include/${globalprefix}/${jpprefix}; \
+ done
+
+clean:
+
+%.o: %.c
+ ${COMPILE} -c $< -o $@
+
+.PHONY: default all compile check doc stage dist distsrc distbin install clean
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ Copyright (c) Members of the EGEE Collaboration. 2004
+ See http://eu-egee.org/partners/ for details on the copyright holders
+ For license conditions see the license file or http://eu-egee.org/license.html
+
+ Build file for the gLite JP Server Common module
+
+ Authors: Ales Krenek <ljocha@ics.muni.cz>
+ Version info: $Id$
+ Release: $Name$
+
+ Revision history:
+ $Log$
+ Revision 1.3 2005/05/26 15:13:28 zurek
+ inserted module.build.file
+
+ Revision 1.2 2004/11/22 14:00:37 dimeglio
+ Updated to use standard files
+ Fixed names (was using common instead of real module name)
+
+ Revision 1.1.1.1 2004/10/15 09:49:13 akrenek
+-->
+
+<project name="server-common" default="dist">
+
+ <!-- =========================================
+ Builds the GLite JP Common Server Module
+ ========================================= -->
+
+ <!-- =========================================
+ Import properties (order is important)
+ ========================================= -->
+
+ <!-- import baseline & user properties -->
+ <import file="../org.glite/project/baseline.properties.xml" />
+
+ <!-- import component build properties,
+ component properties &
+ component common properties -->
+ <import file="./project/properties.xml"/>
+
+ <!-- import subsystem build properties,
+ subsystem properties &
+ subsystem common properties -->
+ <import file="${subsystem.properties.file}"/>
+
+ <!-- import global build properties &
+ global properties -->
+ <import file="${global.properties.file}" />
+
+ <!-- =========================================
+ Load dependency property files (order is important)
+ ========================================= -->
+ <property file="${user.dependencies.file}"/>
+ <property file="${component.dependencies.file}" />
+ <property file="${subsystem.dependencies.file}" />
+ <property file="${global.dependencies.file}"/>
+
+ <!-- =========================================
+ Load configure options (order is important)
+ ========================================= -->
+ <import file="${global.configure.options.file}"/>
+ <import file="${component.configure.options.file}"/>
+
+ <!-- =========================================
+ Import task definitions (order is important)
+ ========================================= -->
+ <import file="${subsystem.taskdefs.file}" />
+ <import file="${global.taskdefs.file}" />
+
+ <!-- =========================================
+ Load common targets
+ ========================================= -->
+ <import file="${global.targets-simple_make.file}" />
+
+ <!-- =========================================
+ Load version file
+ ========================================= -->
+ <property file="${module.version.file}"/>
+ <property file="${module.build.file}"/>
+
+ <!-- ==============================================
+ Local private targets
+ ============================================== -->
+
+ <target name="localinit"
+ description="Module specific initialization tasks">
+
+ <antcall target="lbmakefiles" />
+ </target>
+
+ <target name="localcompile"
+ description="Module specific compile tasks">
+ </target>
+
+ <target name="localclean"
+ description="Module specific cleaning tasks">
+ </target>
+
+</project>
--- /dev/null
+#ifndef _DB_H
+#define _DB_H
+
+#ident "$Header$"
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct _glite_jp_db_stmt_t *glite_jp_db_stmt_t;
+
+
+/**
+ * Connect to the database.
+ *
+ * \param[inout] cxt context to work with
+ * \param[in] cs connect string user/password@host:database
+ *
+ \return JP error code
+ */
+int glite_jp_db_connect(glite_jp_context_t,const char *);
+
+
+/**
+ * Close the connection to database.
+ *
+ * \param[inout] ctx context to work with
+ */
+void glite_jp_db_close(glite_jp_context_t);
+
+
+/**
+ * Parse and execute SQL statement.
+ *
+ * \param[inout] ctx context to work with
+ * \param[in] txt SQL statement
+ * \param[out] stmt statement handle, usable for select only
+ *
+ * \return number of rows selected, created or affected by update, or -1 on error
+ */
+int glite_jp_db_execstmt(glite_jp_context_t, const char *, glite_jp_db_stmt_t *);
+
+
+/** Fetch next row of select statement.
+ * All columns are returned as fresh allocated strings
+ *
+ * \param[inout] stmt statement from glite_jp_db_execstmt()
+ * \param[out] array of fetched values.
+ * As number of columns is fixed and known,
+ * expects allocated array of pointers here.
+ *
+ * \retval >0 number of fields of the retrieved row
+ * \retval 0 no more rows
+ * \retval -1 error
+ *
+ * Errors are stored in context passed to previous glite_jp_db_execstmt()
+ */
+int glite_jp_db_fetchrow(glite_jp_db_stmt_t, char **);
+
+
+/**
+ * Retrieve column names of a query statement
+ *
+ * \param[inout] stmt statement
+ * \param[out] cols result set column names. Expects allocated array.
+ *
+ * \return 0 if OK, nonzero on error
+ */
+int glite_jp_db_querycolumns(glite_jp_db_stmt_t, char **);
+
+
+/**
+ * Free the statement structure
+ *
+ * \param[inout] stmt statement
+ */
+void glite_jp_db_freestmt(glite_jp_db_stmt_t *);
+
+
+/**
+ * Convert time_t into database-specific time string.
+ *
+ * \param[in] t the converted time
+ * \return XXX: pointer to static area that is changed by subsequent calls
+ */
+char *glite_jp_db_timetodb(time_t);
+
+
+/**
+ * Convert database-specific time string into time_t.
+ *
+ * \param[in] t the converted string
+ *
+ * \return result time
+ */
+time_t glite_jp_db_dbtotime(const char *);
+
+
+/**
+ * Check database version.
+ *
+ * \param[inout] ctx context to work with
+ *
+ * \return JP error code
+ */
+int glite_jp_db_dbcheckversion(glite_jp_context_t);
+
+
+/**
+ * Assign parameters to mysql bind structure.
+ *
+ * \param[inout] param mysql bind strusture array
+ * \param[in] type mysql type
+ *
+ * Variable parameters:
+ * MYSQL_TYPE_TINY: char *buffer
+ * MYSQL_TYPE_LONG: long int *buffer
+ * MYSQL_TYPE_*_BLOB: void *buffer, unsigned long *length
+ * MYSQL_TYPE_*STRING: char *buffer, unsigned long *length
+ * MYSQL_TYPE_NULL: -
+ */
+void glite_jp_db_assign_param(MYSQL_BIND *param, enum enum_field_types type, ...);
+
+
+/**
+ * Assign result variables to mysql bind structure.
+ *
+ * \param[inout] result mysql bind strusture array
+ * \param[in] type mysql type
+ * \param[in] is_null pointer to is_null boolean
+ *
+ * Variable parameters:
+ * MYSQL_TYPE_TINY: char *buffer
+ * MYSQL_TYPE_LONG: long int *buffer
+ * MYSQL_TYPE_*_BLOB: void *buffer, unsigned long max_length, unsigned long *length
+ * MYSQL_TYPE_*STRING: char *buffer, unsigned long max_length, unsigned long *length
+ */
+void glite_jp_db_assign_result(MYSQL_BIND *result, enum enum_field_types type, my_bool *is_null, ...);
+
+/**
+ * Prepare the SQL statement. Use glite_jp_db_freestmt() to free it.
+ *
+ * \param[inout] ctx context to work with
+ * \param[in] sql SQL command
+ * \param[out] jpstmt returned JP SQL statement
+ * \param[inout] params mysql static structure with parameters
+ * \param[inout] cols mysql static structure with result buffer
+ *
+ * \return JP error code
+ */
+int glite_jpis_db_prepare(glite_jp_context_t ctx, const char *sql, glite_jp_db_stmt_t *jpstmt, MYSQL_BIND *params, MYSQL_BIND *cols);
+
+/**
+ * Execute prepared SQL statement.
+ *
+ * \param[inout] jpstmt JP SQL statement
+ *
+ * \return number of affected rows, -1 on error
+ */
+int glite_jp_db_execute(glite_jp_db_stmt_t jpstmt);
+
+/**
+ *
+ * \param[inout] jpstmt JP SQL statement
+ *
+ * \return JP error code (ENODATA when no more row are available)
+ */
+int glite_jp_db_fetch(glite_jp_db_stmt_t jpstmt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ Copyright (c) Members of the EGEE Collaboration. 2004
+ See http://eu-egee.org/partners/ for details on the copyright holders
+ For license conditions see the license file or http://eu-egee.org/license.html
+
+ Configuration options for the gLite JP Index module
+
+ Authors: Ales Krenek <ljocha@ics.muni.cz>
+ Version info: $Id$
+ Release: $Name$
+
+ Revision history:
+ $Log$
+ Revision 1.4 2005/08/12 10:56:25 mmulac
+ void IS server
+ - seems compiling
+
+ Revision 1.3 2004/12/01 18:45:38 zsalvet
+ *** empty log message ***
+
+ Revision 1.2 2004/11/22 14:00:37 dimeglio
+ Updated to use standard files
+ Fixed names (was using common instead of real module name)
+
+ Revision 1.1.1.1 2004/10/15 09:49:13 akrenek
+-->
+
+ <!-- ======================================================
+ Define extra properties here ...
+ ====================================================== -->
+
+ <project name="JP Common configuration options">
+ <target name="lbmakefiles">
+ <exec executable="ln" failonerror="true">
+ <arg line="-fs ${component.dir}/Makefile ${module.build.dir}/Makefile"/>
+ </exec>
+ <echo file="${module.build.dir}/Makefile.inc">
+top_srcdir=..
+builddir=build
+stagedir=${stage.abs.dir}
+distdir=${dist.dir}
+globalprefix=${global.prefix}
+jpprefix=${subsystem.prefix}
+package=${module.package.name}
+PREFIX=${install.dir}
+version=${module.version}
+glite_location=${with.glite.location}
+globus_prefix=${with.globus.prefix}
+expat_prefix=${with.expat.prefix}
+gsoap_prefix=${with.gsoap.prefix}
+ares_prefix=${with.ares.prefix}
+mysql_prefix=${with.mysql.prefix}
+mysql_version=${ext.mysql.version}
+thrflavour=${with.globus.thr.flavor}
+nothrflavour=${with.globus.nothr.flavor}
+cppunit=${with.cppunit.prefix}
+jpproject=${subsystem.project.dir}
+project=${component.project.dir}
+ </echo>
+ </target>
+ </project>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) Members of the EGEE Collaboration. 2004
+ See http://eu-egee.org/partners/ for details on the copyright holders
+ For license conditions see the license file or http://eu-egee.org/license.html
+
+ Common build properties file for the gLite JP Common Server component
+
+ Authors: Ales Krenek <ljocha@ics.muni.cz>
+ Version info: $Id$
+ Release: $Name$
+
+ Revision history:
+ $Log$
+ Revision 1.2 2004/11/22 14:00:37 dimeglio
+ Updated to use standard files
+ Fixed names (was using common instead of real module name)
+
+ Revision 1.1.1.1 2004/10/15 09:49:13 akrenek
+-->
+
+<project name="JP Common Server component common properties">
+
+ <!-- Include build properties to allow overwriting
+ of properties for subsystem -->
+ <property file="project/build.properties" />
+
+ <!-- ======================================================
+ Define corresponding subsystem properties
+ ====================================================== -->
+
+ <!-- Subsystem name -->
+ <property name="subsystem.name" value="${jp.subsystem.name}"/>
+
+ <!-- Subsystem prefix -->
+ <property name="subsystem.prefix" value="${jp.subsystem.prefix}"/>
+
+ <!-- ======================================================
+ Define component properties
+ ====================================================== -->
+
+ <!-- Component name prefix -->
+ <property name="component.prefix" value="server-common" />
+
+ <!-- ======================================================
+ Define general component properties
+ ====================================================== -->
+
+ <import file="${component.general.properties.file}" />
+
+ <!-- ======================================================
+ Define extra properties here ...
+ ====================================================== -->
+
+
+</project>
--- /dev/null
+tar_exclude
+CVS
+build.xml
+build
+build.properties
+properties.xml
+configure.properties.xml
+.cvsignore
+.project
+.cdtproject
--- /dev/null
+module.version=1.0.0
+module.age=1
--- /dev/null
+#ident "$Header$"
+
+#include "mysql.h"
+#include "mysqld_error.h"
+#include "errmsg.h"
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <time.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <assert.h>
+
+#include "glite/jp/types.h"
+#include "glite/jp/context.h"
+
+#include "db.h"
+
+#define GLITE_JP_LB_MYSQL_VERSION 40018
+
+#define JP_ERR(CTX, CODE, DESC) jp_err((CTX), (CODE), (DESC), __FUNCTION__, __LINE__)
+#define MY_ERR(CTX) my_err((CTX), __FUNCTION__, __LINE__)
+#define MY_ERRSTMT(JPSTMT) my_errstmt((JPSTMT), __FUNCTION__, __LINE__)
+#define MY_ISOKSTMT(JPSTMT, RETRY) my_isokstmt((JPSTMT), __FUNCTION__, __LINE__, (RETRY))
+
+
+struct _glite_jp_db_stmt_t {
+ glite_jp_context_t ctx;
+ MYSQL_RES *result;
+ MYSQL_STMT *stmt;
+};
+
+
+static int jp_err(glite_jp_context_t ctx, int code, const char *desc, const char *source, int line)
+{
+ glite_jp_error_t err;
+ char *fullsource;
+ int ret;
+
+ asprintf(&fullsource, "%s:%d", source, line);
+ memset(&err,0,sizeof err);
+ err.code = code;
+ err.source = fullsource;
+ err.desc = desc;
+
+ ret = glite_jp_stack_error(ctx,&err);
+ free(fullsource);
+ return ret;
+}
+
+
+static int my_err(glite_jp_context_t ctx, const char *source, int line)
+{
+ return jp_err(ctx, EIO, mysql_error((MYSQL *)ctx->dbhandle), source, line);
+}
+
+
+static int my_errstmt(glite_jp_db_stmt_t jpstmt, const char *source, int line) {
+ return jp_err(jpstmt->ctx, EIO, mysql_stmt_error(jpstmt->stmt), source, line);
+}
+
+
+/*
+ * Error handle.
+ *
+ * \return -1 failed
+ * \return 0 retry
+ * \return 1 OK
+ */
+static int my_isokstmt(glite_jp_db_stmt_t jpstmt, const char *source, int line, int *retry) {
+ switch (mysql_stmt_errno(jpstmt->stmt)) {
+ case 0:
+ return 1;
+ break;
+ case ER_DUP_ENTRY:
+ jp_err(jpstmt->ctx, EEXIST, mysql_stmt_error(jpstmt->stmt), source, line);
+ return -1;
+ break;
+ case CR_SERVER_LOST:
+ if (*retry > 0) {
+ (*retry)--;
+ return 0;
+ } else
+ return -1;
+ break;
+ default:
+ my_errstmt(jpstmt, source, line);
+ return -1;
+ break;
+ }
+}
+
+
+int glite_jp_db_connect(glite_jp_context_t ctx,const char *cs)
+{
+ char *buf = NULL;
+ char *host,*user,*pw,*db;
+ char *slash,*at,*colon;
+ int ret;
+
+ glite_jp_clear_error(ctx);
+
+ if (!cs) return JP_ERR(ctx, EINVAL, "connect string not specified");
+
+ if (!(ctx->dbhandle = (void *) mysql_init(NULL))) return JP_ERR(ctx, ENOMEM, NULL);
+
+ mysql_options(ctx->dbhandle, MYSQL_READ_DEFAULT_FILE, "my");
+
+ host = user = pw = db = NULL;
+
+ buf = strdup(cs);
+ slash = strchr(buf,'/');
+ at = strrchr(buf,'@');
+ colon = strrchr(buf,':');
+
+ if (!slash || !at || !colon) {
+ free(buf);
+ mysql_close((MYSQL *)ctx->dbhandle);
+ return JP_ERR(ctx, EINVAL, "Invalid DB connect string");
+ }
+
+ *slash = *at = *colon = 0;
+ host = at+1;
+ user = buf;
+ pw = slash+1;
+ db = colon+1;
+
+ if (!mysql_real_connect((MYSQL *) ctx->dbhandle,host,user,pw,db,0,NULL,CLIENT_FOUND_ROWS)) {
+ free(buf);
+ ret = MY_ERR(ctx);
+ mysql_close((MYSQL *)ctx->dbhandle);
+ return ret;
+ }
+
+ free(buf);
+ return 0;
+}
+
+
+void glite_jp_db_close(glite_jp_context_t ctx)
+{
+ mysql_close((MYSQL *) ctx->dbhandle);
+ ctx->dbhandle = NULL;
+}
+
+
+int glite_jp_db_execstmt(glite_jp_context_t ctx,const char *txt,glite_jp_db_stmt_t *stmt)
+{
+ int merr;
+ int retry_nr = 0;
+ int do_reconnect = 0;
+
+ glite_jp_clear_error(ctx);
+
+ if (stmt) {
+ *stmt = NULL;
+ }
+
+ while (retry_nr == 0 || do_reconnect) {
+ do_reconnect = 0;
+ if (mysql_query((MYSQL *) ctx->dbhandle,txt)) {
+ /* error occured */
+ switch (merr = mysql_errno((MYSQL *) ctx->dbhandle)) {
+ case 0:
+ break;
+ case ER_DUP_ENTRY:
+ JP_ERR(ctx, EEXIST, mysql_error((MYSQL *) ctx->dbhandle));
+ return -1;
+ break;
+ case CR_SERVER_LOST:
+ if (retry_nr <= 0)
+ do_reconnect = 1;
+ break;
+ default:
+ MY_ERR(ctx);
+ return -1;
+ break;
+ }
+ }
+ retry_nr++;
+ }
+
+ if (stmt) {
+ *stmt = malloc(sizeof(**stmt));
+ if (!*stmt) {
+ JP_ERR(ctx, ENOMEM, NULL);
+ return -1;
+ }
+ memset(*stmt,0,sizeof(**stmt));
+ (**stmt).ctx = ctx;
+ (**stmt).result = mysql_store_result((MYSQL *) ctx->dbhandle);
+ if (!(**stmt).result) {
+ if (mysql_errno((MYSQL *) ctx->dbhandle)) {
+ MY_ERR(ctx);
+ return -1;
+ }
+ }
+ } else {
+ MYSQL_RES *r = mysql_store_result((MYSQL *) ctx->dbhandle);
+ mysql_free_result(r);
+ }
+
+ return mysql_affected_rows((MYSQL *) ctx->dbhandle);
+}
+
+
+int glite_jp_db_fetchrow(glite_jp_db_stmt_t stmt,char **res)
+{
+ MYSQL_ROW row;
+ glite_jp_context_t ctx = stmt->ctx;
+ int nr,i;
+ unsigned long *len;
+
+ glite_jp_clear_error(ctx);
+
+ if (!stmt->result) return 0;
+
+ if (!(row = mysql_fetch_row(stmt->result))) {
+ if (mysql_errno((MYSQL *) ctx->dbhandle)) {
+ MY_ERR(ctx);
+ return -1;
+ } else return 0;
+ }
+
+ nr = mysql_num_fields(stmt->result);
+ len = mysql_fetch_lengths(stmt->result);
+ for (i=0; i<nr; i++) res[i] = len[i] ? strdup(row[i]) : strdup("");
+
+ return nr;
+}
+
+
+int glite_jp_db_querycolumns(glite_jp_db_stmt_t stmt,char **cols)
+{
+ int i = 0;
+ MYSQL_FIELD *f;
+
+ while ((f = mysql_fetch_field(stmt->result))) cols[i++] = f->name;
+ return i == 0;
+}
+
+
+void glite_jp_db_freestmt(glite_jp_db_stmt_t *stmt)
+{
+ if (*stmt) {
+ if ((**stmt).result) mysql_free_result((**stmt).result);
+ if ((*stmt)->stmt) mysql_stmt_close((*stmt)->stmt);
+ free(*stmt);
+ *stmt = NULL;
+ }
+}
+
+
+char *glite_jp_db_timetodb(time_t t)
+{
+ struct tm *tm = gmtime(&t);
+ char tbuf[256];
+
+ /* XXX: the very end of our days */
+ if (!tm && t == (time_t) LONG_MAX) return strdup("9999-12-31 23:59:59");
+
+ sprintf(tbuf,"'%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);
+
+ return strdup(tbuf);
+}
+
+
+time_t glite_jp_db_dbtotime(const char *t)
+{
+ struct tm tm;
+
+ memset(&tm,0,sizeof(tm));
+ setenv("TZ","UTC",1); tzset();
+ sscanf(t,"%4d-%02d-%02d %02d:%02d:%02d",
+ &tm.tm_year,&tm.tm_mon,&tm.tm_mday,
+ &tm.tm_hour,&tm.tm_min,&tm.tm_sec);
+ tm.tm_year -= 1900;
+ tm.tm_mon--;
+
+ return mktime(&tm);
+}
+
+
+int glite_jp_db_dbcheckversion(glite_jp_context_t ctx)
+{
+ MYSQL *m = (MYSQL *) ctx->dbhandle;
+ const char *ver_s = mysql_get_server_info(m);
+ int major,minor,sub,version;
+
+ glite_jp_clear_error(ctx);
+
+ if (!ver_s || 3 != sscanf(ver_s,"%d.%d.%d",&major,&minor,&sub)) {
+ return JP_ERR(ctx, EINVAL, "problem checking MySQL version");
+ }
+
+ version = 10000*major + 100*minor + sub;
+
+ if (version < GLITE_JP_LB_MYSQL_VERSION) {
+ char msg[300];
+
+ return JP_ERR(ctx, EINVAL, msg);
+ }
+
+ return 0;
+}
+
+
+void glite_jp_db_assign_param(MYSQL_BIND *param, enum enum_field_types type, ...) {
+ va_list ap;
+
+ memset(param, 0, sizeof(*param));
+ param->buffer_type = type;
+
+ va_start(ap, type);
+
+ switch (type) {
+ case MYSQL_TYPE_TINY:
+ param->buffer = va_arg(ap, char *);
+ break;
+
+ case MYSQL_TYPE_LONG:
+ param->buffer = va_arg(ap, long int *);
+ break;
+
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ param->buffer = va_arg(ap, void *);
+ param->length = va_arg(ap, unsigned long *);
+ break;
+
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_STRING:
+ param->buffer = va_arg(ap, char *);
+ param->length = va_arg(ap, unsigned long *);
+ break;
+
+ case MYSQL_TYPE_NULL:
+ break;
+
+ default:
+ assert("unimplemented parameter assign" == NULL);
+ break;
+ }
+
+ va_end(ap);
+}
+
+void glite_jp_db_assign_result(MYSQL_BIND *param, enum enum_field_types type, my_bool *is_null, ...) {
+ va_list ap;
+
+ memset(param, 0, sizeof(*param));
+ param->buffer_type = type;
+ param->is_null = is_null;
+
+ va_start(ap, is_null);
+
+ switch(type) {
+ case MYSQL_TYPE_TINY:
+ param->buffer = va_arg(ap, char *);
+ param->buffer_length = sizeof(char);
+ break;
+
+ case MYSQL_TYPE_LONG:
+ param->buffer = va_arg(ap, long int *);
+ param->buffer_length = sizeof(long int);
+ break;
+
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ param->buffer = va_arg(ap, void *);
+ param->buffer_length = va_arg(ap, unsigned long);
+ param->length = va_arg(ap, unsigned long *);
+ break;
+
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_STRING:
+ param->buffer = va_arg(ap, char *);
+ param->buffer_length = va_arg(ap, unsigned long);
+ param->length = va_arg(ap, unsigned long *);
+ break;
+
+ default:
+ assert("unimplemented result assign" == NULL);
+ }
+ if (param->buffer && param->buffer_length) memset(param->buffer, 0, param->buffer_length);
+
+ va_end(ap);
+}
+
+
+int glite_jp_db_prepare(glite_jp_context_t ctx, const char *sql, glite_jp_db_stmt_t *jpstmt, MYSQL_BIND *params, MYSQL_BIND *cols) {
+ int ret, retry;
+
+ glite_jp_clear_error(ctx);
+
+ // init
+ *jpstmt = malloc(sizeof(struct _glite_jp_db_stmt_t));
+ (*jpstmt)->ctx = ctx;
+ (*jpstmt)->result = NULL;
+
+ // create the SQL command
+ if (((*jpstmt)->stmt = mysql_stmt_init((MYSQL *)ctx->dbhandle)) == NULL)
+ return MY_ERRSTMT(*jpstmt);
+
+ // prepare the SQL command
+ retry = 1;
+ do {
+ mysql_stmt_prepare((*jpstmt)->stmt, sql, strlen(sql));
+ ret = MY_ISOKSTMT(*jpstmt, &retry);
+ } while (ret == 0);
+ if (ret == -1) goto failed;
+
+ // parameters
+ if (params) {
+ if (mysql_stmt_bind_param((*jpstmt)->stmt, params) != 0)
+ return MY_ERRSTMT(*jpstmt);
+ }
+
+ // results
+ if (cols) {
+ if (mysql_stmt_bind_result((*jpstmt)->stmt, cols) != 0)
+ return MY_ERRSTMT(*jpstmt);
+ }
+
+ return 0;
+
+failed:
+ return ctx->error->code;
+}
+
+
+int glite_jp_db_execute(glite_jp_db_stmt_t jpstmt) {
+ glite_jp_context_t ctx;
+ int ret, retry;
+
+ ctx = jpstmt->ctx;
+ glite_jp_clear_error(ctx);
+
+ // run
+ retry = 1;
+ do {
+ mysql_stmt_execute(jpstmt->stmt);
+ ret = MY_ISOKSTMT(jpstmt, &retry);
+ } while (ret == 0);
+ if (ret == -1) goto failed;
+
+ // result
+ mysql_stmt_store_result(jpstmt->stmt);
+ if (mysql_stmt_errno(jpstmt->stmt)) {
+ MY_ERRSTMT(jpstmt);
+ goto failed;
+ }
+
+ return mysql_stmt_affected_rows(jpstmt->stmt);
+
+failed:
+ return -1;
+}
+
+
+int glite_jp_db_fetch(glite_jp_db_stmt_t jpstmt) {
+ int ret, retry;
+
+ glite_jp_clear_error(jpstmt->ctx);
+
+ retry = 1;
+ do {
+ switch(mysql_stmt_fetch(jpstmt->stmt)) {
+ case 0: ret = 1; break;
+ case 1: ret = MY_ISOKSTMT(jpstmt, &retry); break;
+ case MYSQL_NO_DATA: JP_ERR(jpstmt->ctx, ENODATA, "no more rows"); ret = -1; break;
+ default: JP_ERR(jpstmt->ctx, EIO, "other fetch error"); ret = -1; break;
+ }
+ } while (ret == 0);
+ if (ret == -1) goto failed;
+
+ return 0;
+
+failed:
+ return jpstmt->ctx->error->code;
+}