Prepared commands survival on reconnection.
authorFrantišek Dvořák <valtri@civ.zcu.cz>
Fri, 18 Jan 2008 15:50:42 +0000 (15:50 +0000)
committerFrantišek Dvořák <valtri@civ.zcu.cz>
Fri, 18 Jan 2008 15:50:42 +0000 (15:50 +0000)
org.glite.lbjp-common.db/examples/db_expire.c
org.glite.lbjp-common.db/examples/db_test.c
org.glite.lbjp-common.db/src/db.c

index 8ca3c1b..67fee31 100644 (file)
@@ -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 <stdio.h>
@@ -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;
 }
index d32e4a3..c9d1ca9 100644 (file)
@@ -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;
index 9d9de63..a45a16c 100644 (file)
@@ -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;