From dab9af0072f060b2f12813c21b031bcaed0c406a Mon Sep 17 00:00:00 2001 From: =?utf8?q?Franti=C5=A1ek=20Dvo=C5=99=C3=A1k?= Date: Mon, 10 Oct 2005 09:10:41 +0000 Subject: [PATCH] More changes from out of CVS tree: - get rid of mysql from public header - added time types - added testing example - runtime and compile check for minimal mysql version: 4.1.2 - more free on error in db_prepare, NULLing on DB close --- org.glite.jp.server-common/Makefile | 13 +- org.glite.jp.server-common/examples/db-test-int.c | 112 +++++++ org.glite.jp.server-common/interface/db.h | 113 +++++-- org.glite.jp.server-common/src/db.c | 354 ++++++++++++++++------ 4 files changed, 477 insertions(+), 115 deletions(-) create mode 100644 org.glite.jp.server-common/examples/db-test-int.c diff --git a/org.glite.jp.server-common/Makefile b/org.glite.jp.server-common/Makefile index cb1f049..e916efd 100644 --- a/org.glite.jp.server-common/Makefile +++ b/org.glite.jp.server-common/Makefile @@ -34,6 +34,10 @@ COMPILE:=libtool --mode=compile ${CC} ${CPPFLAGS} ${CFLAGS} LINK:=libtool --mode=link ${CC} -rpath ${stagedir}/lib ${LDFLAGS} INSTALL:=libtool --mode=install install +GLOBUS_LIBS:=-L${globus_prefix}/lib \ + -lglobus_common_${nothrflavour} \ + -lglobus_gssapi_gsi_${nothrflavour} + # FIXME: to use libtool versioning correcty, we should have: # # current = major + minor + offset @@ -64,13 +68,18 @@ else endif -default all: compile +default all: compile examples compile: ${LTLIB} ${STATICLIB} ${LTLIB} ${STATICLIB}: ${OBJS} ${LINK} ${version_info} -o $@ ${LOBJS} ${MYSQLIB} +examples: db-test-int + +db-test-int: db-test-int.o + ${LINK} -o $@ $+ ${STATICLIB} ${MYSQLIB} -lglite_jp_common ${GLOBUS_LIBS} + check: -echo nothing yet @@ -103,4 +112,4 @@ clean: %.o: %.c ${COMPILE} -c $< -o $@ -.PHONY: default all compile check doc stage dist distsrc distbin install clean +.PHONY: default all compile examples check doc stage dist distsrc distbin install clean diff --git a/org.glite.jp.server-common/examples/db-test-int.c b/org.glite.jp.server-common/examples/db-test-int.c new file mode 100644 index 0000000..e58b5c2 --- /dev/null +++ b/org.glite.jp.server-common/examples/db-test-int.c @@ -0,0 +1,112 @@ +#include +#include + +#include "db.h" + + +static void print_err(glite_jp_context_t ctx) { + glite_jp_error_t *e; + + e = ctx->error; + while (e) { + printf("%s(%s)\n", e->desc, e->source); + e = e->reason; + } + printf("\n"); +} + + +int main() { + glite_jp_context_t ctx; + glite_jp_db_stmt_t jpstmt; + + glite_jp_init_context(&ctx); + + printf("connecting...\n"); + if (glite_jp_db_connect(ctx, "jpis/@localhost:jpis1") != 0) goto fail; + + // "trio" queries +{ + int nr, i; + char **res; + + printf("selecting...\n"); + if ((glite_jp_db_execstmt(ctx, "SELECT uniqueid, feedid, state, source, condition FROM feeds", &jpstmt)) == -1) goto fail; + + printf("fetching...\n"); + res = calloc(4, sizeof(char *)); + while ((nr = glite_jp_db_fetchrow(jpstmt, res)) > 0) { + printf("Result: n=%d, res=%p\n", nr, res); + i = 0; + if (res) while(i < nr) {printf("p=%p(%s)\n", res[i], res[i]);free(res[i]);i++;} + } + free(res); + printf("closing stmt...\n"); + glite_jp_db_freestmt(&jpstmt); +} + + // param queries +{ + char res_feedid[33]; + long int res_state; + char res_source[256]; + char res_condition[1024]; + unsigned long res_condition_length; + long int param_state; + + void *my_res, *my_param; + + glite_jp_db_create_params(&my_param, 1, GLITE_JP_DB_TYPE_INT, ¶m_state); + glite_jp_db_create_results(&my_res, 4, + GLITE_JP_DB_TYPE_VARCHAR, NULL, res_feedid, sizeof(res_feedid), NULL, + GLITE_JP_DB_TYPE_INT, NULL, &res_state, + GLITE_JP_DB_TYPE_VARCHAR, NULL, res_source, sizeof(res_source), NULL, + GLITE_JP_DB_TYPE_MEDIUMBLOB, NULL, res_condition, sizeof(res_condition), &res_condition_length + ); + printf("preparing...\n"); + if ((glite_jp_db_prepare(ctx, "SELECT feedid, state, source, condition FROM feeds WHERE state = ?", &jpstmt, my_param, my_res)) != 0) goto fail_close; + + param_state = 1; + printf("executing state %ld...\n", param_state); + if (glite_jp_db_execute(jpstmt) == -1) { + glite_jp_db_freestmt(&jpstmt); + goto fail_stmtclose; + } + printf("fetching...\n"); + while (glite_jp_db_fetch(jpstmt) == 0) { + printf("feedid:%s, state:%ld, source:%s, condition:%s\n", res_feedid, res_state, res_source, res_condition); + } + + param_state = 2; + printf("executing state %ld...\n", param_state); + if (glite_jp_db_execute(jpstmt) == -1) { + glite_jp_db_freestmt(&jpstmt); + goto fail_stmtclose; + } + printf("fetching...\n"); + while (glite_jp_db_fetch(jpstmt) == 0) { + printf("feedid:%s, state:%ld, source:%s, condition:%s\n", res_feedid, res_state, res_source, res_condition); + } +} + + printf("closing stmt...\n"); + glite_jp_db_freestmt(&jpstmt); + printf("closing...\n"); + glite_jp_db_close(ctx); + + glite_jp_free_context(ctx); + return 0; + +fail_stmtclose: + printf("closing stmt...\n"); + glite_jp_db_freestmt(&jpstmt); +fail_close: + printf("closing...\n"); + glite_jp_db_close(ctx); +fail: + printf("failed\n"); + print_err(ctx); + glite_jp_free_context(ctx); + + return 1; +} diff --git a/org.glite.jp.server-common/interface/db.h b/org.glite.jp.server-common/interface/db.h index c5eca7f..7e51553 100644 --- a/org.glite.jp.server-common/interface/db.h +++ b/org.glite.jp.server-common/interface/db.h @@ -10,9 +10,31 @@ extern "C" { #endif +#include +#include typedef struct _glite_jp_db_stmt_t *glite_jp_db_stmt_t; +typedef enum { + GLITE_JP_DB_TYPE_NULL = 0, + GLITE_JP_DB_TYPE_TINYINT = 1, + GLITE_JP_DB_TYPE_INT = 2, + GLITE_JP_DB_TYPE_TINYBLOB = 3, + GLITE_JP_DB_TYPE_TINYTEXT = 4, + GLITE_JP_DB_TYPE_BLOB = 5, + GLITE_JP_DB_TYPE_TEXT = 6, + GLITE_JP_DB_TYPE_MEDIUMBLOB = 7, + GLITE_JP_DB_TYPE_MEDIUMTEXT = 8, + GLITE_JP_DB_TYPE_LONGBLOB = 9, + GLITE_JP_DB_TYPE_LONGTEXT = 10, + GLITE_JP_DB_TYPE_VARCHAR = 11, + GLITE_JP_DB_TYPE_CHAR = 12, + GLITE_JP_DB_TYPE_DATE = 13, + GLITE_JP_DB_TYPE_TIME = 14, + GLITE_JP_DB_TYPE_DATETIME = 15, + GLITE_JP_DB_TYPE_TIMESTAMP = 16, + GLITE_JP_DB_TYPE_LAST = 17 +} glite_jp_db_type_t; /** * Connect to the database. @@ -22,7 +44,7 @@ typedef struct _glite_jp_db_stmt_t *glite_jp_db_stmt_t; * \return JP error code */ -int glite_jp_db_connect(glite_jp_context_t,const char *); +int glite_jp_db_connect(glite_jp_context_t, const char *); /** @@ -74,7 +96,7 @@ int glite_jp_db_querycolumns(glite_jp_db_stmt_t, char **); /** - * Free the statement structure + * Free the statement structure and destroy its parameters. * * \param[inout] stmt statement */ @@ -111,35 +133,82 @@ int glite_jp_db_dbcheckversion(glite_jp_context_t); /** - * Assign parameters to mysql bind structure. + * Create and assign parameters for mysql prepared commands. * - * \param[inout] param mysql bind strusture array - * \param[in] type mysql type + * \param[out] params internal structure array * * 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: - + * always: + * glite_jp_db_type_t type DB item type + * then one of them: + * GLITE_JP_DB_TYPE_TINYINT: char *buffer + * GLITE_JP_DB_TYPE_INT: int *buffer + * GLITE_JP_DB_TYPE_*BLOB/TEXT: void *buffer, unsigned long *length + * GLITE_JP_DB_TYPE_[VAR]CHAR: char *buffer, unsigned long *length + * GLITE_JP_DB_TYPE_DATE: void **buffer + * GLITE_JP_DB_TYPE_TIME: void **buffer + * GLITE_JP_DB_TYPE_DATETIME: void **buffer + * GLITE_JP_DB_TYPE_TIMESTAMP: void **buffer + * GLITE_JP_DB_TYPE_NULL: - */ -void glite_jp_db_assign_param(MYSQL_BIND *param, enum enum_field_types type, ...); - +void glite_jp_db_create_params(void **params, int n, ...); /** - * Assign result variables to mysql bind structure. + * Create and assign result variables for mysql prepared commands. * * \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 + * always: + * \param[in] glite_jp_db_type_t type DB item type + * \param[in] int *is_null pointer to is_null boolean or NULL + * then one of them: + * GLITE_JP_DB_TYPE_TINYINT: char *buffer + * GLITE_JP_DB_TYPE_INT: long int *buffer + * GLITE_JP_DB_TYPE_*BLOB/TEXT: void *buffer, unsigned long max_length, unsigned long *length + * GLITE_JP_DB_TYPE_[VAR]CHAR: char *buffer, unsigned long max_length, unsigned long *length + * GLITE_JP_DB_TYPE_DATE: void **buffer + * GLITE_JP_DB_TYPE_TIME: void **buffer + * GLITE_JP_DB_TYPE_DATETIME: void **buffer + * GLITE_JP_DB_TYPE_TIMESTAMP: void **buffer + */ +void glite_jp_db_create_results(void **results, int n, ...); + +/** + * Destroy prepared parameters. + */ +void glite_jp_db_destroy_params(void *params); + +/** + * Destroy prepared results. */ +void glite_jp_db_destroy_results(void *results); + +#if 0 +void glite_jp_db_assign_param(MYSQL_BIND *param, enum enum_field_types type, ...); void glite_jp_db_assign_result(MYSQL_BIND *result, enum enum_field_types type, my_bool *is_null, ...); +#endif + +/** + * Assign time_t to buffer. + */ +void glite_jp_db_set_time(void *buffer, const time_t time); + +/** + * Get the time from buffer. + */ +time_t glite_jp_db_get_time(const void *buffer); + +/** + * Rebind the parameters and/or results. + * + * \param[inout] jpstmt JP SQL statement to work with + * \param[inout] params mysql static structure with parameters or NULL + * \param[inout] cols mysql static structure with result buffer or NULL + * + * \return JP error code + */ +int glite_jp_db_rebind(glite_jp_db_stmt_t jpstmt, void *params, void *cols); /** * Prepare the SQL statement. Use glite_jp_db_freestmt() to free it. @@ -147,12 +216,12 @@ void glite_jp_db_assign_result(MYSQL_BIND *result, enum enum_field_types type, m * \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 + * \param[inout] params mysql static structure with parameters or NULL + * \param[inout] cols mysql static structure with result buffer or NULL * * \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); +int glite_jp_db_prepare(glite_jp_context_t ctx, const char *sql, glite_jp_db_stmt_t *jpstmt, void *params, void *cols); /** * Execute prepared SQL statement. diff --git a/org.glite.jp.server-common/src/db.c b/org.glite.jp.server-common/src/db.c index de024dd..3ef2738 100644 --- a/org.glite.jp.server-common/src/db.c +++ b/org.glite.jp.server-common/src/db.c @@ -1,8 +1,8 @@ #ident "$Header$" -#include "mysql.h" -#include "mysqld_error.h" -#include "errmsg.h" +#include +#include +#include #include #include @@ -19,7 +19,12 @@ #include "db.h" -#define GLITE_JP_LB_MYSQL_VERSION 40018 + +#define GLITE_JP_DB_MYSQL_VERSION 40102 + +#if !defined(MYSQL_VERSION_ID) || MYSQL_VERSION_ID < GLITE_JP_DB_MYSQL_VERSION +#error required MySQL version 4.1.2 +#endif #define JP_ERR(CTX, CODE, DESC) jp_err((CTX), (CODE), (DESC), __FUNCTION__, __LINE__) #define MY_ERR(CTX) my_err((CTX), __FUNCTION__, __LINE__) @@ -27,10 +32,37 @@ #define MY_ISOKSTMT(JPSTMT, RETRY) my_isokstmt((JPSTMT), __FUNCTION__, __LINE__, (RETRY)) +typedef struct { + int n; + MYSQL_BIND params[1]; +} params_t; + struct _glite_jp_db_stmt_t { glite_jp_context_t ctx; MYSQL_RES *result; MYSQL_STMT *stmt; + params_t *params, *results; +}; + + +static int glite_to_mysql_type[] = { + 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, }; @@ -101,6 +133,9 @@ int glite_jp_db_connect(glite_jp_context_t ctx,const char *cs) char *slash,*at,*colon; int ret; + // needed for SQL result parameters + assert(sizeof(int) >= sizeof(my_bool)); + glite_jp_clear_error(ctx); if (!cs) return JP_ERR(ctx, EINVAL, "connect string not specified"); @@ -118,7 +153,7 @@ int glite_jp_db_connect(glite_jp_context_t ctx,const char *cs) if (!slash || !at || !colon) { free(buf); - mysql_close((MYSQL *)ctx->dbhandle); + glite_jp_db_close(ctx); return JP_ERR(ctx, EINVAL, "Invalid DB connect string"); } @@ -131,19 +166,26 @@ int glite_jp_db_connect(glite_jp_context_t ctx,const char *cs) 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); + glite_jp_db_close(ctx); return ret; } - free(buf); + + if ((ret = glite_jp_db_dbcheckversion(ctx)) != 0) { + glite_jp_db_close(ctx); + return ret; + } + return 0; } void glite_jp_db_close(glite_jp_context_t ctx) { - mysql_close((MYSQL *) ctx->dbhandle); - ctx->dbhandle = NULL; + if (ctx->dbhandle) { + mysql_close((MYSQL *) ctx->dbhandle); + ctx->dbhandle = NULL; + } } @@ -248,6 +290,8 @@ 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); + if ((*stmt)->params) glite_jp_db_destroy_params((*stmt)->params); + if ((*stmt)->results) glite_jp_db_destroy_results((*stmt)->results); free(*stmt); *stmt = NULL; } @@ -299,7 +343,7 @@ int glite_jp_db_dbcheckversion(glite_jp_context_t ctx) version = 10000*major + 100*minor + sub; - if (version < GLITE_JP_LB_MYSQL_VERSION) { + if (version < GLITE_JP_DB_MYSQL_VERSION) { char msg[300]; return JP_ERR(ctx, EINVAL, msg); @@ -309,106 +353,240 @@ int glite_jp_db_dbcheckversion(glite_jp_context_t ctx) } -void glite_jp_db_assign_param(MYSQL_BIND *param, enum enum_field_types type, ...) { +void glite_jp_db_create_params(void **params, int n, ...) { + params_t *myparams; + MYSQL_BIND *myparam; + MYSQL_TIME **mytime; + int i; va_list ap; + glite_jp_db_type_t type; - memset(param, 0, sizeof(*param)); - param->buffer_type = type; + myparams = calloc(n, sizeof(params_t) + (n - 1) * sizeof(MYSQL_BIND)); + va_start(ap, n); - va_start(ap, type); + for (i = 0; i < n; i++) { + myparam = myparams->params + i; + type = va_arg(ap, glite_jp_db_type_t); - switch (type) { - case MYSQL_TYPE_TINY: - param->buffer = va_arg(ap, char *); - break; + switch (type) { + case GLITE_JP_DB_TYPE_TINYINT: + myparam->buffer = va_arg(ap, char *); + break; - case MYSQL_TYPE_LONG: - param->buffer = va_arg(ap, long int *); - break; + case GLITE_JP_DB_TYPE_INT: + myparam->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 GLITE_JP_DB_TYPE_TINYBLOB: + case GLITE_JP_DB_TYPE_TINYTEXT: + case GLITE_JP_DB_TYPE_BLOB: + case GLITE_JP_DB_TYPE_TEXT: + case GLITE_JP_DB_TYPE_MEDIUMBLOB: + case GLITE_JP_DB_TYPE_MEDIUMTEXT: + case GLITE_JP_DB_TYPE_LONGBLOB: + case GLITE_JP_DB_TYPE_LONGTEXT: + myparam->buffer = va_arg(ap, void *); + myparam->length = va_arg(ap, unsigned long *); + break; + + case GLITE_JP_DB_TYPE_VARCHAR: + case GLITE_JP_DB_TYPE_CHAR: + myparam->buffer = va_arg(ap, char *); + myparam->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 GLITE_JP_DB_TYPE_DATE: + case GLITE_JP_DB_TYPE_TIME: + case GLITE_JP_DB_TYPE_DATETIME: + case GLITE_JP_DB_TYPE_TIMESTAMP: + mytime = (MYSQL_TIME **)va_arg(ap, void **); + *mytime = calloc(1, sizeof(MYSQL_TIME)); + myparam->buffer = *mytime; + break; - case MYSQL_TYPE_NULL: - break; + case GLITE_JP_DB_TYPE_NULL: + break; - default: - assert("unimplemented parameter assign" == NULL); - break; + default: + assert("unimplemented parameter assign" == NULL); + break; + } + myparam->buffer_type = glite_to_mysql_type[type]; } + myparams->n = n; va_end(ap); + *params = myparams; } -void glite_jp_db_assign_result(MYSQL_BIND *param, enum enum_field_types type, my_bool *is_null, ...) { + +void glite_jp_db_create_results(void **results, int n, ...) { + params_t *myresults; + MYSQL_BIND *myresult; + MYSQL_TIME **mytime; va_list ap; + int i; + glite_jp_db_type_t type; + int *is_null; + + myresults = calloc(n, sizeof(params_t) + (n - 1) * sizeof(MYSQL_BIND)); + va_start(ap, n); + + for (i = 0; i < n; i++) { + myresult = myresults->params + i; + type = va_arg(ap, glite_jp_db_type_t); + is_null = va_arg(ap, int *); + myresult->is_null = (my_bool *)is_null; + if (is_null) *is_null = 0; + + switch(type) { + case GLITE_JP_DB_TYPE_TINYINT: + myresult->buffer = va_arg(ap, char *); + myresult->buffer_length = sizeof(char); + break; + + case GLITE_JP_DB_TYPE_INT: + myresult->buffer = va_arg(ap, long int *); + myresult->buffer_length = sizeof(long int); + break; + + case GLITE_JP_DB_TYPE_TINYBLOB: + case GLITE_JP_DB_TYPE_TINYTEXT: + case GLITE_JP_DB_TYPE_BLOB: + case GLITE_JP_DB_TYPE_TEXT: + case GLITE_JP_DB_TYPE_MEDIUMBLOB: + case GLITE_JP_DB_TYPE_MEDIUMTEXT: + case GLITE_JP_DB_TYPE_LONGBLOB: + case GLITE_JP_DB_TYPE_LONGTEXT: + myresult->buffer = va_arg(ap, void *); + myresult->buffer_length = va_arg(ap, unsigned long); + myresult->length = va_arg(ap, unsigned long *); + break; - 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); + case GLITE_JP_DB_TYPE_VARCHAR: + case GLITE_JP_DB_TYPE_CHAR: + myresult->buffer = va_arg(ap, char *); + myresult->buffer_length = va_arg(ap, unsigned long); + myresult->length = va_arg(ap, unsigned long *); + break; + + case GLITE_JP_DB_TYPE_DATE: + case GLITE_JP_DB_TYPE_TIME: + case GLITE_JP_DB_TYPE_DATETIME: + case GLITE_JP_DB_TYPE_TIMESTAMP: + mytime = (MYSQL_TIME **)va_arg(ap, void **); + *mytime = calloc(1, sizeof(MYSQL_TIME)); + myresult->buffer = *mytime; + break; + + default: + assert("unimplemented result assign" == NULL); + } + myresult->buffer_type = glite_to_mysql_type[type]; + if (myresult->buffer && myresult->buffer_length) memset(myresult->buffer, 0, myresult->buffer_length); } - if (param->buffer && param->buffer_length) memset(param->buffer, 0, param->buffer_length); + myresults->n = n; va_end(ap); + *results = myresults; } -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) { +static void glite_jp_db_destroy_respam(params_t *params) { + MYSQL_BIND *myparam; + int i; + enum enum_field_types type; + + for (i = 0; i < params->n; i++) { + myparam = params->params + i; + type = myparam->buffer_type; + if (type == MYSQL_TYPE_DATE || type == MYSQL_TYPE_TIME || type == MYSQL_TYPE_DATETIME || type == MYSQL_TYPE_TIMESTAMP) { + free(myparam->buffer); + myparam->buffer = NULL; + } + } + free(params); +} + + +void glite_jp_db_destroy_params(void *params) { + glite_jp_db_destroy_respam(params); +} + + +void glite_jp_db_destroy_results(void *results) { + glite_jp_db_destroy_respam(results); +} + + +void glite_jp_db_set_time(void *buffer, const time_t time) { + MYSQL_TIME *mybuffer; + struct tm tm; + + mybuffer = (MYSQL_TIME *)buffer; + gmtime_r(&time, &tm); + mybuffer->year = tm.tm_year + 1900; + mybuffer->month = tm.tm_mon + 1; + mybuffer->day = tm.tm_mday; + mybuffer->hour = tm.tm_hour; + mybuffer->minute = tm.tm_min; + mybuffer->second = tm.tm_sec; +} + + +time_t glite_jp_db_get_time(const void *buffer) { + MYSQL_TIME *mybuffer; + struct tm tm; + + mybuffer = (MYSQL_TIME *)buffer; + memset(&tm, 0, sizeof(tm)); + tm.tm_year = mybuffer->year - 1900; + tm.tm_mon = mybuffer->month - 1; + tm.tm_mday = mybuffer->day; + tm.tm_hour = mybuffer->hour; + tm.tm_min = mybuffer->minute; + tm.tm_sec = mybuffer->second; + + return mktime(&tm); +} + + +int glite_jp_db_rebind(glite_jp_db_stmt_t jpstmt, void *params, void *cols) { + if (jpstmt->params) { + glite_jp_db_destroy_params(jpstmt->params); + jpstmt->params = NULL; + } + if (jpstmt->results) { + glite_jp_db_destroy_results(jpstmt->results); + jpstmt->results = NULL; + } + if (params) { + jpstmt->params = (params_t *)params; + if (mysql_stmt_bind_param(jpstmt->stmt, jpstmt->params->params) != 0) return MY_ERRSTMT(jpstmt); + } + if (cols) { + jpstmt->results = (params_t *)cols; + if (mysql_stmt_bind_result(jpstmt->stmt, jpstmt->results->params) != 0) return MY_ERRSTMT(jpstmt); + } + + return 0; +} + + +int glite_jp_db_prepare(glite_jp_context_t ctx, const char *sql, glite_jp_db_stmt_t *jpstmt, void *params, void *cols) { int ret, retry; glite_jp_clear_error(ctx); // init - *jpstmt = malloc(sizeof(struct _glite_jp_db_stmt_t)); + *jpstmt = calloc(1, 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); + if (((*jpstmt)->stmt = mysql_stmt_init((MYSQL *)ctx->dbhandle)) == NULL) { + ret = MY_ERRSTMT(*jpstmt); + goto failed; + } // prepare the SQL command retry = 1; @@ -418,21 +596,15 @@ int glite_jp_db_prepare(glite_jp_context_t ctx, const char *sql, glite_jp_db_stm } 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); - } + // parameters and results + if ((ret = glite_jp_db_rebind(*jpstmt, params, cols)) != 0) goto failed; return 0; failed: + if (params) glite_jp_db_destroy_params(params); + if (cols) glite_jp_db_destroy_params(cols); + glite_jp_db_freestmt(jpstmt); return ctx->error->code; } -- 1.8.2.3