8ce7da98082db69f86314bf79d8f69978e008455
angie
  Fri Apr 28 16:43:36 2017 -0700
hgVai was crashing when there was a new snpNNN table in the database but not yet in trackDb.  Now make sure to use the latest SNPs track not just the latest table.  refs #19272

diff --git src/hg/lib/hdb.c src/hg/lib/hdb.c
index 8f9b295..b74db38 100644
--- src/hg/lib/hdb.c
+++ src/hg/lib/hdb.c
@@ -5412,56 +5412,66 @@
 {
 char *fileName = hReplaceGbdb(trackDbSetting(tdb, "bigDataUrl"));
 if (fileName == NULL)
     fileName = hReplaceGbdb(trackDbSetting(tdb, "bigGeneDataUrl"));
 if (fileName == NULL)
     fileName = bbiNameFromTableChrom(conn, table, seqName);
 return fileName;
 }
 
 char *bbiNameFromSettingOrTable(struct trackDb *tdb, struct sqlConnection *conn, char *table)
 /* Return file name from bigDataUrl or little table. */
 {
 return bbiNameFromSettingOrTableChrom(tdb, conn, table, NULL);
 }
 
-char *hFindLatestSnpTableConn(struct sqlConnection *conn, char *suffix)
-/* Return the name of the 'snp1__<suffix>' table with the highest build number, if any.
+static struct slName *hListSnpNNNTables(struct sqlConnection *conn, char *suffix)
+/* Return a list of 'snpNNN<suffix>' tables, if any, in reverse 'SHOW TABLES' order
+ * (highest first).  If there are none and suffix is NULL/empty but conn has a table 'snp',
+ * return that as a fallback for older databases like hg16.
  * suffix may be NULL to get the 'All SNPs' table (as opposed to Common, Flagged, Mult). */
 {
-if (suffix == NULL)
-    suffix = "";
-char *tableName = NULL;
 char likeExpr[64];
-safef(likeExpr, sizeof(likeExpr), "LIKE 'snp1__%s'", suffix);
+safef(likeExpr, sizeof(likeExpr), "LIKE 'snp___%s'", suffix ? suffix : "");
 struct slName *snpNNNTables = sqlListTablesLike(conn, likeExpr);
-if (snpNNNTables)
-    {
-    // Skip to last in list -- highest number (show tables can't use rlike or 'order by'):
-    struct slName *table = snpNNNTables;
-    while (table->next != NULL && isdigit(table->next->name[4]) && isdigit(table->next->name[5]))
-        table = table->next;
-    if (table != NULL)
-        tableName = cloneString(table->name);
+slReverse(&snpNNNTables);
+// Trim non-snpNNN tables e.g. snpSeq in hg17, hg18:
+while (snpNNNTables && !isdigit(snpNNNTables->name[3]))
+    snpNNNTables = snpNNNTables->next;
+// hg16 has only "snp":
+if (snpNNNTables == NULL && isEmpty(suffix) && sqlTableExists(conn, "snp"))
+    snpNNNTables = slNameNew("snp");
+return snpNNNTables;
 }
-else if (isEmpty(suffix))
+
+char *hFindLatestSnpTableConn(struct sqlConnection *conn, char *suffix)
+/* Return the name of the 'snpNNN<suffix>' table with the highest build number, if any.
+ * suffix may be NULL to get the 'All SNPs' table (as opposed to Common, Flagged, Mult). */
 {
-    // Before snpNNN* tables (e.g. hg16) there was a track with table 'snp', so check for that:
-    snpNNNTables = sqlListTablesLike(conn, "LIKE 'snp'");
-    if (snpNNNTables != NULL)
+char *tableName = NULL;
+struct slName *snpNNNTables = hListSnpNNNTables(conn, suffix);
+if (snpNNNTables)
     tableName = cloneString(snpNNNTables->name);
-    }
 slNameFreeList(&snpNNNTables);
 return tableName;
 }
 
-char *hFindLatestSnpTable(char *db, char *suffix)
-/* Return the name of the 'snp1__<suffix>' table with the highest build number, if any.
+struct trackDb *hFindLatestSnpTrack(char *db, char *suffix, struct trackDb **pFullTrackList)
+/* Return the 'snpNNN<suffix>' track with the highest build number, if any.
  * suffix may be NULL to get the 'All SNPs' table (as opposed to Common, Flagged, Mult). */
 {
 if (startsWith(hubTrackPrefix, db))
+    // Don't know how to find SNP tracks on hub yet
     return NULL;
 struct sqlConnection *conn = hAllocConn(db);
-char *tableName = hFindLatestSnpTableConn(conn, suffix);
-hFreeConn(&conn);
-return tableName;
+struct slName *snpNNNTables = hListSnpNNNTables(conn, suffix);
+// Return the first trackDb that we can find (sometimes there is a brand new lastest-version table
+// that does not yet have a trackDb)
+struct slName *table;
+for (table = snpNNNTables;  table != NULL;  table = table->next)
+    {
+    struct trackDb *tdb = tdbForTrack(db, table->name, pFullTrackList);
+    if (tdb)
+        return tdb;
+    }
+return NULL;
 }