From 894b59e83e129878a858a883a566cb44e48ed706 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Franti=C5=A1ek=20Dvo=C5=99=C3=A1k?= Date: Fri, 18 Jan 2008 15:50:42 +0000 Subject: [PATCH] Prepared commands survival on reconnection. --- org.glite.lbjp-common.db/examples/db_expire.c | 49 ++++++++++++++++---- org.glite.lbjp-common.db/examples/db_test.c | 5 +- org.glite.lbjp-common.db/src/db.c | 67 +++++++++++++++++++-------- 3 files changed, 89 insertions(+), 32 deletions(-) diff --git a/org.glite.lbjp-common.db/examples/db_expire.c b/org.glite.lbjp-common.db/examples/db_expire.c index 8ca3c1b..67fee31 100644 --- a/org.glite.lbjp-common.db/examples/db_expire.c +++ b/org.glite.lbjp-common.db/examples/db_expire.c @@ -8,7 +8,11 @@ * mysql -u root -p -e 'GRANT ALL on test.* to testuser@localhost' * ./db_test * - * Use CS environment variable when using different user/pwd@machine:dbname. + * Then you can launch: + * + * ./db_expire + * + * Use CS environment variable for different user/pwd@machine:dbname. */ #include @@ -49,12 +53,24 @@ static void print_free_result(const char *name, unsigned long *lens, char **res) } +static void print_error(glite_lbu_DBContext ctx) { + if (ctx) { + char *t, *d; + + if (glite_lbu_DBError(ctx, &t, &d)) { + printf("Error %s: %s\n", t, d); + free(t); free(d); + } + } +} + + int main(int argn, char *argv[]) { char *name, *user; const char *cs; glite_lbu_DBContext ctx; glite_lbu_Statement stmt; - int caps, i, nr, c; + int caps, nr, c; unsigned long lens[3]; char *res[3]; @@ -64,25 +80,41 @@ int main(int argn, char *argv[]) { // init dprintf(("connecting to %s...\n", cs)); - if (glite_lbu_InitDBContext(&ctx) != 0) goto fail; - if (glite_lbu_DBConnect(ctx, cs) != 0) goto failctx; - if ((caps = glite_lbu_DBQueryCaps(ctx)) == -1) goto failcon; + if (glite_lbu_InitDBContext(&ctx) != 0) { + print_error(ctx); + goto failctx; + } + if (glite_lbu_DBConnect(ctx, cs) != 0) { + print_error(ctx); + goto failctx; + } + if ((caps = glite_lbu_DBQueryCaps(ctx)) == -1) { + print_error(ctx); + goto failcon; + } if ((caps & GLITE_LBU_DB_CAP_PREPARED) == 0) { + print_error(ctx); dprintf(("can't do prepared commands, exiting.")); goto failcon; } // caps - glite_lbu_DBSetCaps(ctx, caps); + glite_lbu_DBSetCaps(ctx, caps | GLITE_LBU_DB_CAP_ERRORS); dprintf(("capabilities: %d\n", caps)); user = NULL; dprintf(("preparing '%s'...\n", user)); - if ((glite_lbu_PrepareStmt(ctx, SELECT_CMD, &stmt)) != 0) goto failcon; + if ((glite_lbu_PrepareStmt(ctx, SELECT_CMD, &stmt)) != 0) { + print_error(ctx); + goto failcon; + } do { user = "cicomexocitl.civ"; dprintf(("executing '%s'...\n", user)); - if (glite_lbu_ExecPreparedStmt(stmt, 1, GLITE_LBU_DB_TYPE_VARCHAR, user) == -1) goto failstmt; + if (glite_lbu_ExecPreparedStmt(stmt, 1, GLITE_LBU_DB_TYPE_VARCHAR, user) == -1) { + print_error(ctx); + goto failstmt; + } dprintf(("fetching '%s'...\n", user)); while ((nr = glite_lbu_FetchRow(stmt, 3, lens, res)) > 0) { dprintf(("Result: n=%d, res=%p\n", nr, res)); @@ -110,7 +142,6 @@ failcon: glite_lbu_DBClose(ctx); failctx: glite_lbu_FreeDBContext(ctx); -fail: dprintf(("failed\n")); return 1; } diff --git a/org.glite.lbjp-common.db/examples/db_test.c b/org.glite.lbjp-common.db/examples/db_test.c index d32e4a3..c9d1ca9 100644 --- a/org.glite.lbjp-common.db/examples/db_test.c +++ b/org.glite.lbjp-common.db/examples/db_test.c @@ -79,7 +79,7 @@ int main(int argn, char *argv[]) { // init dprintf(("connecting to %s...\n", cs)); - if (glite_lbu_InitDBContext(&ctx) != 0) goto fail; + if (glite_lbu_InitDBContext(&ctx) != 0) goto failctx; if (glite_lbu_DBConnect(ctx, cs) != 0) goto failctx; if ((caps = glite_lbu_DBQueryCaps(ctx)) == -1) goto failcon; if ((caps & GLITE_LBU_DB_CAP_PREPARED) == 0) { @@ -189,7 +189,7 @@ failcon: dprintf(("closing...\n")); glite_lbu_DBClose(ctx); failctx: - { + if (ctx) { char *t, *d; glite_lbu_DBError(ctx, &t, &d); @@ -197,7 +197,6 @@ failctx: free(t); free(d); } glite_lbu_FreeDBContext(ctx); -fail: free(cmd); dprintf(("failed\n")); return 1; diff --git a/org.glite.lbjp-common.db/src/db.c b/org.glite.lbjp-common.db/src/db.c index 9d9de63..a45a16c 100644 --- a/org.glite.lbjp-common.db/src/db.c +++ b/org.glite.lbjp-common.db/src/db.c @@ -64,6 +64,7 @@ struct glite_lbu_Statement_s { /* for prepared commands */ MYSQL_STMT *stmt; unsigned long nrfields; + char *sql; }; @@ -160,6 +161,7 @@ static int FetchRowSimple(glite_lbu_DBContext ctx, MYSQL_RES *result, unsigned l static int FetchRowPrepared(glite_lbu_DBContext ctx, glite_lbu_Statement stmt, unsigned int n, unsigned long *lengths, char **results); static void set_time(MYSQL_TIME *mtime, const time_t time); static void glite_lbu_DBCleanup(void); +static void glite_lbu_FreeStmt_int(glite_lbu_Statement stmt); /* ---- common ---- */ @@ -337,16 +339,22 @@ int glite_lbu_FetchRow(glite_lbu_Statement stmt, unsigned int n, unsigned long * } -void glite_lbu_FreeStmt(glite_lbu_Statement *stmt) { - if (*stmt) { - if ((*stmt)->result) db_handle.mysql_free_result((*stmt)->result); - if ((*stmt)->stmt) db_handle.mysql_stmt_close((*stmt)->stmt); - free(*stmt); - *stmt = NULL; +static void glite_lbu_FreeStmt_int(glite_lbu_Statement stmt) { + if (stmt) { + if (stmt->result) db_handle.mysql_free_result(stmt->result); + if (stmt->stmt) db_handle.mysql_stmt_close(stmt->stmt); + free(stmt->sql); } } +void glite_lbu_FreeStmt(glite_lbu_Statement *stmt) { + 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; @@ -589,6 +597,9 @@ int glite_lbu_PrepareStmt(glite_lbu_DBContext ctx, const char *sql, glite_lbu_St } else (*stmt)->nrfields = 0; + // remember the command + (*stmt)->sql = strdup(sql); + return CLR_ERR(ctx); failed: @@ -598,7 +609,7 @@ failed: int glite_lbu_ExecPreparedStmt_v(glite_lbu_Statement stmt, int n, va_list ap) { - int i; + int i, prepare_retry; glite_lbu_DBType type; char *pchar; long int *plint; @@ -608,6 +619,7 @@ int glite_lbu_ExecPreparedStmt_v(glite_lbu_Statement stmt, int n, va_list ap) { MYSQL_BIND *binds = NULL; void **data = NULL; unsigned long *lens; + glite_lbu_Statement newstmt; // gather parameters if (n) { @@ -666,21 +678,36 @@ int glite_lbu_ExecPreparedStmt_v(glite_lbu_Statement stmt, int n, va_list ap) { binds[i].buffer_type = glite_type_to_mysql[type]; } - // bind parameters - if (n) - if (db_handle.mysql_stmt_bind_param(stmt->stmt, binds) != 0) { - MY_ERRSTMT(stmt); - goto failed; + prepare_retry = 2; + do { + // bind parameters + if (n) { + if (db_handle.mysql_stmt_bind_param(stmt->stmt, binds) != 0) { + MY_ERRSTMT(stmt); + ret = -1; + goto statement_failed; + } } - // run - ctx = stmt->ctx; - retry = 1; - do { - db_handle.mysql_stmt_execute(stmt->stmt); - ret = MY_ISOKSTMT(stmt, &retry); - } while (ret == 0); - if (ret == -1) goto failed; + // run + ctx = stmt->ctx; + retry = 1; + do { + db_handle.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) { + // expired the prepared command ==> restore it + if (glite_lbu_PrepareStmt(stmt->ctx, stmt->sql, &newstmt) == -1) goto failed; + glite_lbu_FreeStmt_int(stmt); + memcpy(stmt, newstmt, sizeof(struct glite_lbu_Statement_s)); + prepare_retry--; + ret = 0; + } else goto failed; + } + } while (ret == 0 && prepare_retry > 0); // result retry = 1; -- 1.8.2.3