4f0b12aadc3153194c9b4c81c70adc86d621ff2b
braney
  Fri Oct 10 12:08:26 2025 -0700
support genePred in quickLift

diff --git src/hg/hgc/hgc.c src/hg/hgc/hgc.c
index 0f70c63c5d2..ee4398d780f 100644
--- src/hg/hgc/hgc.c
+++ src/hg/hgc/hgc.c
@@ -255,30 +255,31 @@
 #include "trix.h"
 #include "bPlusTree.h"
 #include "customFactory.h"
 #include "dupTrack.h"
 #include "iupac.h"
 #include "clinvarSubLolly.h"
 #include "jsHelper.h"
 #include "errCatch.h"
 #include "htslib/bgzf.h"
 #include "htslib/kstring.h"
 #include "pipeline.h"
 #include "genark.h"
 #include "chromAlias.h"
 #include "dotPlot.h"
 #include "quickLift.h"
+#include "liftOver.h"
 
 static char *rootDir = "hgcData";
 
 #define LINESIZE 70  /* size of lines in comp seq feature */
 #define MAX_DISPLAY_QUERY_SEQ_SIZE 5000000  // Big enough for HLA alts
 
 struct cart *cart;	/* User's settings. */
 char *seqName;		/* Name of sequence we're working on. */
 int winStart, winEnd;   /* Bounds of sequence. */
 char *database;		/* Name of mySQL database. */
 char *organism;		/* Colloquial name of organism. */
 char *genome;		/* common name, e.g. Mouse, Human */
 char *scientificName;	/* Scientific name of organism. */
 
 /* for earlyBotCheck() function at the beginning of main() */
@@ -2969,31 +2970,31 @@
 	{
 	if (ensemblSource && differentString("protein_coding",ensemblSource))
 	    {
 	    printf("<b>CDS Start: </b> none (non-coding)<BR>\n");
 	    printf("<b>CDS End: </b> none (non-coding)<BR>\n");
 	    }
 	else
 	    {
 	    printf("<b>CDS Start: </b>");
 	    printCdsStatus((gp->strand[0] == '+') ? gp->cdsStartStat : gp->cdsEndStat);
 	    printf("<b>CDS End: </b>");
 	    printCdsStatus((gp->strand[0] == '+') ? gp->cdsEndStat : gp->cdsStartStat);
 	    }
 	}
     /* if a gene class table exists, get gene class and print */
-    if (classTable != NULL)
+    if ((liftDb == NULL) && (classTable != NULL))
         {
         if (hTableExists(db, classTable))
            {
            sqlSafef(query, sizeof(query),
                 "select class from %s where name = \"%s\"", classTable, name);
            sr = sqlGetResult(conn, query);
            /* print class */
            if ((row = sqlNextRow(sr)) != NULL)
               printf("<b>Prediction Class:</b> %s<br>\n", row[0]);
            sqlFreeResult(&sr);
            if (sqlFieldIndex(conn, classTable, "level") > 0 )
                {
                sqlSafef(query, sizeof(query),
                     "select level from %s where name = \"%s\"", classTable, name);
                sr = sqlGetResult(conn, query);
@@ -9504,50 +9505,80 @@
 char *table = cartString(cart, "o");
 /* checks both gbSeq and table */
 aaSeq *seq = hGenBankGetPep(database, pepName, table);
 cartHtmlStart("Protein Translation");
 if (seq == NULL)
     {
     warn("Predicted peptide %s is not avaliable", pepName);
     }
 else
     {
     displayProteinPrediction(pepName, seq->dna);
     dnaSeqFree(&seq);
     }
 }
 
-static struct genePred *getGenePredForPositionSql(char *table, char *geneName)
+static struct genePred *getGenePredForPositionSql(struct trackDb *tdb, char *geneName)
 /* find the genePred for the current gene using an SQL table*/
 {
 struct genePred *gpList = NULL;
 char query[512];
-struct sqlConnection *conn = hAllocConn(database);
+char *db = database;
+char *quickLiftFile = cloneString(trackDbSetting(tdb, "quickLiftUrl"));
+char *liftDb = cloneString(trackDbSetting(tdb, "quickLiftDb"));
+if (liftDb != NULL) 
+    db = liftDb;
+struct sqlConnection *conn = hAllocConn(db);
 struct sqlResult *sr;
 char **row;
 struct genePred *gp;
-int rowOffset = hOffsetPastBin(database, seqName, table);
+int rowOffset = hOffsetPastBin(db, seqName, tdb->table);
+if (liftDb != NULL)
+    {
+    char *table;
+    if (isCustomTrack(tdb->table))
+        {
+        liftDb = CUSTOM_TRASH;
+        table = trackDbSetting(tdb, "dbTableName");
+        }
+    else
+        table = tdb->table;
+    struct hash *chainHash = newHash(8);
+    struct sqlConnection *conn = hAllocConn(liftDb);
+
+// using this loader on genePred tables with less than 15 fields may be a problem.
+extern struct genePred *genePredExtLoad15(char **row);
 
-sqlSafef(query, sizeof(query), "select * from %s where name = \"%s\"", table, geneName);
+    char extraWhere[4096];
+    sqlSafef(extraWhere, sizeof extraWhere, "name = \"%s\"", geneName);
+    gpList = (struct genePred *)quickLiftSql(conn, quickLiftFile, table, seqName, winStart, winEnd,  NULL, extraWhere, (ItemLoader2)genePredExtLoad15, 0, chainHash);
+    hFreeConn(&conn);
+
+    calcLiftOverGenePreds( gpList, chainHash, 0.0, 1.0, TRUE, NULL, NULL,  TRUE, FALSE);
+    }
+else
+    {
+    sqlSafef(query, sizeof(query), "select * from %s where name = \"%s\"", tdb->table, geneName);
     sr = sqlGetResult(conn, query);
     while ((row = sqlNextRow(sr)) != NULL)
         {
         gp = genePredLoad(row+rowOffset);
         slAddHead(&gpList, gp);
         }
 
     sqlFreeResult(&sr);
+    }
 hFreeConn(&conn);
 return gpList;
 }
 
 struct genePred *getGenePredForPositionBigGene(struct trackDb *tdb,  char *geneName)
 /* Find the genePred to the current gene using a bigGenePred. */
 {
 char *fileName = hReplaceGbdb(trackDbSetting(tdb, "bigDataUrl"));
 struct bbiFile *bbi =  bigBedFileOpenAlias(fileName, chromAliasFindAliases);
 struct lm *lm = lmInit(0);
 char *quickLiftFile = cloneString(trackDbSetting(tdb, "quickLiftUrl"));
 struct bigBedInterval *bb, *bbList = NULL;
 struct hash *chainHash = NULL;
 if (quickLiftFile)
     bbList = quickLiftGetIntervals(quickLiftFile, bbi, seqName, winStart, winEnd, &chainHash);
@@ -9584,43 +9615,42 @@
 lmCleanup(&lm);
 
 return gpList;
 }
 
 static struct genePred *getGenePredForPosition(char *table, char *geneName)
 /* Build a genePred list for the given table and gene name. */
 {
 struct genePred *gpList = NULL;
 
 if (isCustomTrack(table))
     {
     struct trackDb *tdb = getCustomTrackTdb(table);
     gpList = getGenePredForPositionBigGene(tdb,  geneName);
     }
-else if (isHubTrack(table))
-    {
-    struct trackDb *tdb = hubConnectAddHubForTrackAndFindTdb( database, table, NULL, trackHash);
-    gpList =  getGenePredForPositionBigGene(tdb, geneName);
-    }
 else
     {
-    struct trackDb *tdb = hashFindVal(trackHash, table);
+    struct trackDb *tdb = NULL;
+    if (isHubTrack(table))
+        tdb = hubConnectAddHubForTrackAndFindTdb( database, table, NULL, trackHash);
+    else
+        tdb = hashFindVal(trackHash, table);
     char *bigDataUrl = trackDbSetting(tdb, "bigDataUrl");
     if (bigDataUrl)
         gpList =  getGenePredForPositionBigGene(tdb, geneName);
     else
-        gpList =  getGenePredForPositionSql(table, geneName);
+        gpList =  getGenePredForPositionSql(tdb, geneName);
     }
 
 return gpList;
 }
 
 void htcTranslatedPredMRna(char *geneName)
 /* Translate virtual mRNA defined by genePred to protein and display it. */
 {
 char *table = cartString(cart, "table");
 struct genePred *gp = NULL;
 char protName[256];
 char *prot = NULL;
 
 cartHtmlStart("Protein Translation from Genome");
 gp = getGenePredForPosition(table, geneName);
@@ -9864,31 +9894,31 @@
 {
 char *table = cartString(cart, "o");
 struct dnaSeq *rnaSeq = getBaseColorSequence(itemName, table );
 cartHtmlStart("RefSeq mRNA Sequence");
 
 printf("<PRE><TT>");
 printf(">%s\n", itemName);
 faWriteNext(stdout, NULL, rnaSeq->dna, rnaSeq->size);
 printf("</TT></PRE>");
 }
 
 
 void htcGeneMrna(char *geneName)
 /* Display cDNA predicted from genome */
 {
-char *table = cartString(cart, "o");
+char *table = cartString(cart, "table");
 cartHtmlStart("Predicted mRNA from Genome");
 struct genePred *gp, *gpList = getGenePredForPosition(table, geneName), *next;
 int cdsStart, cdsEnd;
 struct dnaSeq *seq;
 
 for(gp = gpList; gp; gp = next)
     {
     next = gp->next;
     seq = getCdnaSeq(gp);
     getCdsInMrna(gp, &cdsStart, &cdsEnd);
     toUpperN(seq->dna + cdsStart, cdsEnd - cdsStart);
     if (gp->strand[0] == '-')
 	{
         reverseComplement(seq->dna, seq->size);
 	}
@@ -9915,31 +9945,31 @@
 printf("</TT></PRE>");
 dnaSeqFree(&seq);
 }
 
 void cartContinueRadio(char *var, char *val, char *defaultVal)
 /* Put up radio button, checking it if it matches val */
 {
 char *oldVal = cartUsualString(cart, var, defaultVal);
 cgiMakeRadioButton(var, val, sameString(oldVal, val));
 }
 
 void htcGeneInGenome(char *geneName)
 /* Put up page that lets user display genomic sequence
  * associated with gene. */
 {
-char *tbl = cgiString("o");
+char *tbl = cgiString("table");
 
 cartWebStart(cart, database, "Genomic Sequence Near Gene");
 printf("<H2>Get Genomic Sequence Near Gene</H2>");
 
 puts("<P>"
      "Note: if you would prefer to get DNA for more than one feature of "
      "this track at a time, try the ");
 printf("<A HREF=\"%s\" TARGET=_blank>", hgTablesUrl(FALSE, tbl));
 puts("Table Browser</A> using the output format sequence.");
 
 printf("<FORM ACTION=\"%s\">\n\n", hgcName());
 cartSaveSession(cart);
 cgiMakeHiddenVar("g", "htcDnaNearGene");
 cgiContinueHiddenVar("i");
 printf("\n");
@@ -10075,58 +10105,60 @@
 hti->hasCDS = TRUE;
 hti->hasBlocks = TRUE;
 hti->rootName = tdb->table;
 
 struct bed *bedList = getBedsFromBigBedRange(tdb, geneName);
 int itemCount = hgSeqBed(database, hti, bedList);
 freez(&hti);
 bedFreeList(&bedList);
 return itemCount;
 }
 
 void htcDnaNearGene( char *geneName)
 /* Fetch DNA near a gene. */
 {
 cartWebStart(cart, database, "%s", geneName);
-char *table    = cartString(cart, "o");
+char *table    = cartString(cart, "table");
 int itemCount;
 puts("<PRE>");
 struct trackDb *tdb = NULL;
 
-if (isHubTrack(table))
-    {
-    tdb = hubConnectAddHubForTrackAndFindTdb( database, table, NULL, trackHash);
-    itemCount = getSeqForBigGene(tdb, geneName);
-    }
-else if (isCustomTrack(table))
+if (isCustomTrack(table))
     {
     tdb = getCustomTrackTdb(table);
     itemCount = getSeqForBigGene(tdb, geneName);
     }
 else
     {
+    if (isHubTrack(table))
+        tdb = hubConnectAddHubForTrackAndFindTdb( database, table, NULL, trackHash);
+    else
         tdb = hashFindVal(trackHash, table);
     char *bigDataUrl = trackDbSetting(tdb, "bigDataUrl");
     if (bigDataUrl)
         {
         itemCount = getSeqForBigGene(tdb, geneName);
         }
     else
         {
         char constraints[256];
         sqlSafef(constraints, sizeof(constraints), "name = '%s'", geneName);
-        itemCount = hgSeqItemsInRange(database, table, seqName, winStart, winEnd, constraints);
+        char *db = database;
+        char *liftDb = cloneString(trackDbSetting(tdb, "quickLiftDb"));
+        if (liftDb != NULL) 
+            db = liftDb;
+        itemCount = hgSeqItemsInRange(db, trackHubSkipHubName(table), seqName, winStart, winEnd, constraints);
         }
     }
 if (itemCount == 0)
     printf("\n# No results returned from query.\n\n");
 puts("</PRE>");
 }
 
 void htcTrackHtml(struct trackDb *tdb)
 /* Handle click to display track html */
 {
 cartWebStart(cart, database, "%s", tdb->shortLabel);
 printTrackHtml(tdb);
 }
 
 void doViralProt(struct trackDb *tdb, char *geneName)