11c1c560b88d430fd2c6967a86d2e87109806357
max
  Fri Jan 24 09:15:03 2014 -0800
corrections after code review refs #12524. These changes probably don'tneed to reviewed anymore, as Angie has already seen them, I copied them into
the ticket #12524.

diff --git src/hg/lib/jksql.c src/hg/lib/jksql.c
index ee17d37..e64a48d 100644
--- src/hg/lib/jksql.c
+++ src/hg/lib/jksql.c
@@ -59,31 +59,31 @@
     char *password;     // database server password
     struct slName *dbs; // database associated with profile, can be NULL.
     };
 
 struct sqlConnection
 /* This is an item on a list of sql open connections. */
     {
     MYSQL *conn;		    /* Connection. */
     struct sqlProfile *profile;     /* profile, or NULL if not opened via a profile */
     struct dlNode *node;	    /* Pointer to list node. */
     struct dlList *resultList;	    /* Any open results. */
     boolean hasHardLock;	    /* TRUE if table has a non-advisory lock. */
     boolean inCache;                /* debugging flag to indicate it's in a cache */
     boolean isFree;                /* is this connection free for reuse; alway FALSE
                                     * unless managed by a cache */
-    boolean hasTableCache;           /* to avoid repeated checks for cache table name existence, -1 if not initialized yet */
+    int hasTableCache;           /* to avoid repeated checks for cache table name existence, -1 if not initialized yet */
     struct sqlConnection *slowConn; /* optional. tried if a query fails on the conn connection */
     char *db;                       /* to be able to lazily connect later, we need to store the database */
     };
 
 struct sqlResult
 /* This is an item on a list of sql open results. */
     {
     MYSQL_RES *result;			/* Result. */
     struct dlNode *node;		/* Pointer to list node we're on. */
     struct sqlConnection *conn;		/* Pointer to connection. */
     long fetchTime;                     /* cummulative time taken by row fetches for this result */
     };
 
 static struct dlList *sqlOpenConnections = NULL;
 static unsigned sqlNumOpenConnections = 0;
@@ -393,69 +393,59 @@
 /* called at the end of a routine that is monitored, updates time count.
  * returns time since enter. */
 {
 long deltaTime = 0;
 if (monitorFlags)
     {
     deltaTime = clock1000() - monitorEnterTime;
     assert(monitorEnterTime > 0);
     if (monitorFlags & JKSQL_PROF)
         sqlTotalTime += deltaTime;
     monitorEnterTime = 0;
     }
 return deltaTime;
 }
 
-static char *scConnHost(struct sqlConnection *sc)
-/* Return the host of a sqlConnection */
-{
-if (sc->conn)
-    return sc->conn->host;
-if (sc->profile->host)
-    return sc->profile->host;
-return NULL;
-}
-
 static char *scConnDb(struct sqlConnection *sc)
 /* Return sc->db, unless it is NULL -- if NULL, return a string for
  * fprint'd messages. */
 {
 return (sc->db ? sc->db : "db=?");
 }
 
 static void monitorPrintInfo(struct sqlConnection *sc, char *name)
 /* print a monitor message, with connection id and databases. */
 {
 long int threadId = 0;
 if (sc->conn)
     threadId = sc->conn->thread_id;
 fprintf(stderr, "%.*s%s %ld %s\n", traceIndent, indentStr, name,
         threadId, scConnDb(sc));
 fflush(stderr);
 }
 
 static void monitorPrint(struct sqlConnection *sc, char *name,
                          char *format, ...)
 /* print a monitor message, with connection id, databases, and
  * printf style message.*/
 {
 va_list args;
 long int threadId = 0;
 if (sc->conn)
     threadId = sc->conn->thread_id;
 fprintf(stderr, "%.*s%s %ld %s %s ", traceIndent, indentStr, name,
-        threadId, scConnHost(sc), scConnDb(sc));
+        threadId, sqlGetHost(sc), scConnDb(sc));
 va_start(args, format);
 vfprintf(stderr, format, args);
 va_end(args);
 fputc('\n', stderr);
 fflush(stderr);
 }
 
 static void monitorPrintTime(void)
 /* print total time */
 {
 /* only print if not explictly disabled */
 if (monitorFlags & JKSQL_PROF)
     {
     fprintf(stderr, "%.*sSQL_TOTAL_TIME %0.3fs\n", traceIndent, indentStr,
             ((double)sqlTotalTime)/1000.0);
@@ -588,42 +578,44 @@
    
     // also close local cache connection
     if (sc->slowConn != NULL)
         sqlDisconnect(&sc->slowConn);
 
     freez(pSc);
     sqlNumOpenConnections--;
     }
     
         
 }
 
 char* sqlGetDatabase(struct sqlConnection *sc)
 /* Get the database associated with an connection. Warning: return may be NULL! */
 {
-assert(!sc->isFree);
 if (sc->conn)
     return sc->conn->db;
 else
     return sc->db;
 }
 
 char* sqlGetHost(struct sqlConnection *sc)
-/* Get the host associated with an connection. */
+/* Get the host associated with a connection or NULL. */
 {
-assert(!sc->isFree);
+if (sc->conn)
     return sc->conn->host;
+if (sc->profile->host)
+    return sc->profile->host;
+return NULL;
 }
 
 struct slName *sqlGetAllDatabase(struct sqlConnection *sc)
 /* Get a list of all database on the server */
 {
 char query[32];
 sqlSafef(query, sizeof query, "show databases");
 struct sqlResult *sr = sqlGetResult(sc, query);
 char **row;
 struct slName *databases = NULL;
 while ((row = sqlNextRow(sr)) != NULL)
     {
     if (!startsWith("mysql", row[0]))  /* Avoid internal databases. */
         slSafeAddHead(&databases, slNameNew(row[0]));
     }
@@ -953,46 +945,53 @@
 struct sqlConnection *sc;
 
 // get the slow-db profile for the profile, if it exists
 struct sqlProfile *slow = sqlProfileGetFailover(sp, database);
 // if we have a failover profile, don't abort right away
 if (slow!=NULL)
     mainAbort = FALSE;
 
 // connect with the default profile
 sc = sqlConnRemote(sp->host, sp->port, sp->socket, sp->user, sp->password, database, mainAbort);
 if (slow==NULL)
     // the default case: just return sc, can be NULL
     return sc;
 
 // we still have a failover profile to setup
+
 if (sc==NULL)
     {
     // We have a failover connection configured, but no main connection.
     // This can happen if the requested database exists only on the failover connection
     // We only create a failover connection in this case and return it as the main one
     sc = sqlConnRemote(slow->host, slow->port, slow->socket, slow->user, slow->password, database, abort);
+
+    if (sc!=NULL)// sc can be NULL if abort was FALSE
+        sc->profile = sp; // remember the profile
+
     if (monitorFlags & JKSQL_TRACE)
         fprintf(stderr, "SQL_FAILOVER_AT_CONNECT");
     return sc;
     }
 
+// at this point we know that sc cannot be NULL
 sc->profile = sp; // remember the profile
 
 // don't connect the slow connection yet: lazily connect later when needed; saves 0.5
 // seconds per connection on transatlantic links
-// instead create a "placeholder" sqlConnection with all connection data, but no connection
+// instead create a "placeholder" sqlConnection with all connection data, but no mysql connection
+// object
 struct sqlConnection *slowSc;
 AllocVar(slowSc);
 slowSc->profile = slow; // remember the profile
 slowSc->db = database;
 slowSc->hasTableCache = -1;
 sc->slowConn = slowSc;
 return sc;
 }
 
 struct sqlConnection *sqlMayConnect(char *database)
 /* Connect to database on default host as default user.
  * Return NULL (don't abort) on failure. */
 {
 return sqlConnProfile(sqlProfileMustGet(NULL, database), database, FALSE);
 }
@@ -1103,31 +1102,31 @@
 
 // additional check finds errors of multiple NOSQLINJ tags
 if (strstr(query, "NOSQLINJ "))
     {
     sqlCheckError("Oops, multiple occurrences of NOSQLINJ tag in query: %s", query);
     query = replaceChars(query, "NOSQLINJ ", "");
     fixedMultipleNOSQLINJ = TRUE;
     }
 
 assert(!sc->isFree);
 
 monitorEnter();
 int mysqlError = mysql_real_query(sc->conn, query, strlen(query));
 
 // if the query fails on the main connection, connect the slower/failover connection and try there
-if (mysqlError != 0 && sc->slowConn)
+if (mysqlError != 0 && sc->slowConn && sameWord(sqlGetDatabase(sc), sqlGetDatabase(sc->slowConn)))
     {
     if (monitorFlags & JKSQL_TRACE)
         monitorPrint(sc, "SQL_FAILOVER", "%s -> %s", sc->profile->name, sc->slowConn->profile->name);
 
     sc = sc->slowConn;
     sc = sqlConnectIfUnconnected(sc);
     mysqlError = mysql_real_query(sc->conn, query, strlen(query));
     }
 
 if (mysqlError != 0)
     {
     if (abort)
         {
         monitorLeave();
 	if (sameOk(cfgOption("noSqlInj.dumpStack"), "on"))
@@ -2159,57 +2158,58 @@
                                         char *database)
 /* does a database match the one in the connection cache? */
 {
 return ((database == NULL) && (scce->conn->db == NULL))
     || sameString(database, scce->conn->db);
 }
 
 static boolean sqlConnChangeDb(struct sqlConnection *sc, char *database, boolean abort)
 /* change the database of an sql connection (and its failover connection)
  * */
 {
 // if we have a failover connection, keep its db in sync
 int slowConnErr = 0;
 if (sc->slowConn)
     {
-    sc->slowConn->db = database;
     if (monitorFlags & JKSQL_TRACE)
         monitorPrint(sc->slowConn, "SQL_SET_DB", "%s %s", sc->slowConn->profile->name, database);
     if (sc->slowConn->conn)
         slowConnErr = mysql_select_db(sc->slowConn->conn, database);
-        // we ignore the errors here: this allows to have some DBs only locally
+        if (slowConnErr==0)
+            sc->slowConn->db = database;
+        // if an error occured, the slowConn will be out of sync with the main connection
     }
 
 sc->db=database;
 if (monitorFlags & JKSQL_TRACE)
     monitorPrint(sc, "SQL_SET_DB", "%s %s", sc->profile->name, database);
 
 // we only fail if there is no failover connection, this allows to have a DB
 // that does not exist locally but only remote
 int localConnErr = 0;
 localConnErr = mysql_select_db(sc->conn, database);
 if (sc->slowConn==NULL && sc->conn!=NULL && localConnErr != 0)
     {
     if (abort) 
-        errAbort("Couldn't set connection database to %s\n%s",
-                 database, mysql_error(sc->conn));
+        sqlAbort(sc, "Couldn't set connection database to %s", database);
     else
         return FALSE;
     }
 
 if (localConnErr!=0 && slowConnErr!=0 && abort)
-    errAbort("Couldn't set connection database to %s in both default and failover connection\n%s",
+    // can't use sqlAbort, not sure which one is connected at this point
+    errAbort("Couldn't set connection database to %s in either default or failover connection\n%s",
              database, mysql_error(sc->conn));
 
 return TRUE;
 }
 
 static boolean sqlConnCacheEntrySetDb(struct sqlConnCacheEntry *scce,
                                       char *database,
                                       boolean abort)
 /* set the connect cache and connect to the specified database */
 {
 return sqlConnChangeDb(scce->conn, database, abort);
 }
 
 static struct sqlConnCacheEntry *sqlConnCacheFindFree(struct sqlConnCache *cache,
                                                       struct sqlProfile *profile,