0b9c2a6f9930555f65104385a9edcb00147a5bc6
braney
  Mon Feb 3 09:31:56 2025 -0800
add support for quikLifting mySQL beds.

diff --git src/hg/hgTracks/bedTrack.c src/hg/hgTracks/bedTrack.c
index 81271709e6d..5fa6411c17c 100644
--- src/hg/hgTracks/bedTrack.c
+++ src/hg/hgTracks/bedTrack.c
@@ -5,30 +5,31 @@
 
 #include "common.h"
 #include "jksql.h"
 #include "bed.h"
 #include "hdb.h"
 #include "bedCart.h"
 #include "bbiFile.h"
 #include "bigBed.h"
 #include "hgTracks.h"
 #include "cds.h"
 #include "bedTabix.h"
 #include "obscure.h"
 #include "bigBedFilter.h"
 #include "bigBedLabel.h"
 #include "snake.h"
+#include "liftOver.h"
 #include "quickLift.h"
 
 #define SEQ_DELIM '~'
 
 struct bed *bedLoadPairedTagAlign(char **row)
 /* Load first six fields of bed.
  * Add ~seq1~seq2 to end of name
  * Then remove the sequence to extra field when we convert to linkedFeature.
  * Assumes seq1 and seq2 are in row[6] and row[7], as they would be with a
  * pairedTagAlign type (hg/lib/encode/pairedTagAlign.as). It would be good to be
  * able to check these columns exist but we dont have the sqlResult here. */
 {
 char buf[1024];
 struct bed *ret = bedLoad6(row);
 safef(buf, sizeof(buf), "%s%c%s%c%s", ret->name, SEQ_DELIM, row[6], SEQ_DELIM, row[7]);
@@ -128,64 +129,79 @@
             bed->label = bigBedMakeLabel(tg->tdb, tg->labelColumns, bb, chromName);
 
         slAddHead(&list, bed);
         }
 
     if (filtered)
        labelTrackAsFilteredNumber(tg, filtered);
 
     lmCleanup(&lm);
     }
 else
     {
     char *table = tg->table;
     struct customTrack *ct = tg->customPt;
     struct sqlConnection *conn = NULL;
+    char *liftDb = cloneString(trackDbSetting(tg->tdb, "quickLiftDb"));
+    char *scoreFilterClause = getScoreFilterClause(cart, tg->tdb,NULL);
+
+    if (liftDb != NULL)
+        {
+        struct hash *chainHash = newHash(8);
+        struct sqlConnection *conn = hAllocConn(liftDb);
+        char *quickLiftFile = cloneString(trackDbSetting(tg->tdb, "quickLiftUrl"));
+        bed = (struct bed *)quickLiftSql(conn, quickLiftFile, &tg->table[4], chromName, winStart, winEnd,  NULL, scoreFilterClause, (ItemLoader)loader, chainHash);
+
+        list = quickLiftBeds(bed, chainHash, FALSE);
+        hFreeConn(&conn);
+        }
+    else
+        {
         if (ct == NULL)
             conn = hAllocConnTrack(database, tg->tdb);
         else
             {
             conn = hAllocConn(CUSTOM_TRASH);
             table = ct->dbTableName;
             }
         struct sqlResult *sr = NULL;
         /* limit to items above a specified score */
-    char *scoreFilterClause = getScoreFilterClause(cart, tg->tdb,NULL);
         if (doScoreCtFilter && (topTable != NULL) && hTableExists(database, topTable))
             {
             sqlSafef(query, sizeof(query),"select * from %s order by score desc limit %d",
                   topTable, scoreFilterCt);
             sr = sqlGetResult(conn, query);
             rowOffset = hOffsetPastBin(database, hDefaultChrom(database), topTable);
             }
         else if(scoreFilterClause != NULL && tg->bedSize >= 5)
             {
             sr = hRangeQuery(conn, table, chromName, winStart, winEnd, scoreFilterClause, &rowOffset);
             }
         else
             {
             sr = hRangeQuery(conn, table, chromName, winStart, winEnd, NULL, &rowOffset);
             }
         freeMem(scoreFilterClause);
         while ((row = sqlNextRow(sr)) != NULL)
             {
             bed = loader(row+rowOffset);
             slAddHead(&list, bed);
             }
         sqlFreeResult(&sr);
         hFreeConn(&conn);
         }
+    }
 
 if (doScoreCtFilter)
     {
     /* filter out items not in this window */
     struct bed *newList = bedFilterListInRange(list, NULL, chromName, winStart, winEnd);
     list = newList;
     }
 slReverse(&list);
 tg->items = list;
 }
 
 void loadSimpleBed(struct track *tg)
 /* Load the items in one track - just move beds in
  * window... */
 {
@@ -512,57 +528,83 @@
 boolean useItemRgb = FALSE;
 
 useItemRgb = bedItemRgb(tdb);
 
 if (tg->isBigBed)
     { // avoid opening an unneeded db connection for bigBed; required not to use mysql for parallel fetch tracks
     struct bbiFile *bbi = fetchBbiForTrack(tg);
     bigBedLabelCalculateFields(cart, tg->tdb, bbi,  &tg->labelColumns);
     bigBedAddLinkedFeaturesFrom(tg, chromName, winStart, winEnd,
           scoreMin, scoreMax, useItemRgb, 12, &lfList);
     }
 else
     {
     /* Use tg->tdb->track because subtracks inherit composite track's tdb
      * by default, and the variable is named after the composite track. */
-    struct sqlConnection *conn = hAllocConn(database);
+    char *liftDb = cloneString(trackDbSetting(tg->tdb, "quickLiftDb"));
     char *scoreFilterClause = getScoreFilterClause(cart, tg->tdb,NULL);
+
+    if (liftDb == NULL)
+        {
+        struct sqlConnection *conn = hAllocConn(database);
         if (scoreFilterClause != NULL)
             {
             sr = hRangeQuery(conn, tg->table, chromName, winStart, winEnd,scoreFilterClause, &rowOffset);
             freeMem(scoreFilterClause);
             }
         else
             {
             sr = hRangeQuery(conn, tg->table, chromName, winStart, winEnd, NULL, &rowOffset);
             }
         while ((row = sqlNextRow(sr)) != NULL)
             {
             bed = bedLoad12(row+rowOffset);
             adjustBedScoreGrayLevel(tdb, bed, scoreMin, scoreMax);
             lf = lfFromBedExtra(bed, scoreMin, scoreMax);
             if (useItemRgb)
                 {
                 lf->useItemRgb = TRUE;
                 lf->filterColor=bed->itemRgb;
                 }
             slAddHead(&lfList, lf);
             bedFree(&bed);
             }
         sqlFreeResult(&sr);
         hFreeConn(&conn);
         }
+    else
+        {
+        struct hash *chainHash = newHash(8);
+        struct sqlConnection *conn = hAllocConn(liftDb);
+        char *quickLiftFile = cloneString(trackDbSetting(tg->tdb, "quickLiftUrl"));
+        bed = (struct bed *)quickLiftSql(conn, quickLiftFile, &tg->table[4], chromName, winStart, winEnd,  NULL, scoreFilterClause, (ItemLoader)bedLoad12, chainHash);
+
+        struct bed *liftedBeds = quickLiftBeds(bed, chainHash, TRUE);
+        for(bed = liftedBeds; bed; bed = bed->next)
+            {
+            lf = lfFromBedExtra(bed, scoreMin, scoreMax);
+            if (useItemRgb)
+                {
+                lf->useItemRgb = TRUE;
+                lf->filterColor=bed->itemRgb;
+                }
+            slAddHead(&lfList, lf);
+            }
+        hFreeConn(&conn);
+        }
+    }
+
 slReverse(&lfList);
 if(tg->extraUiData)
     filterBed(tg, &lfList);
 slSort(&lfList, linkedFeaturesCmp);
 tg->items = lfList;
 filterItemsOnNames(tg);
 maybeLoadSnake(tg);   // if we're in snake mode, change the methods
 }
 
 Color colorFromCart(struct track *tg, Color color)
 /* Return the RGB color from the cart setting 'colorOverride' or just return color */
 {
 char varName[1024];
 safef(varName, sizeof(varName), "%s.%s", tg->tdb->track, "colorOverride");
 char *hexColorStr = cartOptionalString(cart, varName);