bb8470a90643b057df7bbf5d0140a5b2bbf9dddd braney Fri Jun 12 08:44:37 2026 -0700 quickLift: load genePreds by column name, not a fixed 15-col loader Lifting a genePred track to another assembly used genePredExtLoad15, a positional loader that assumes the extended genePred columns. Classic knownGene-format tables instead carry proteinID and alignID after the ten core columns, so the loader read proteinID as the integer score field and aborted with "invalid signed integer" (e.g. "O54946", or "" when empty). This showed up when lifting from an assembly whose knownGene is the legacy format, such as mm10 to mm39 or rheMac10. Add quickLiftGenePreds(), which loads through genePredReader so the actual set of columns in the table is honored by name (proteinID maps to name2, score defaults), matching how the tracks load when not lifted. The three call sites that hardcoded genePredExtLoad15 (hgTracks gene loading and two hgc detail handlers) now use it. The chain-walking shared with quickLiftSql is factored into quickLiftLoadChains() and quickLiftChainQueryRange(). refs #37535 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> diff --git src/hg/hgc/hgc.c src/hg/hgc/hgc.c index 475400b7526..bc3905e0bc2 100644 --- src/hg/hgc/hgc.c +++ src/hg/hgc/hgc.c @@ -2981,34 +2981,32 @@ if (!hFindSplitTable(db, seqName, rootTable, table, sizeof table, NULL)) errAbort("showGenePos track %s not found", rootTable); sqlSafef(query, sizeof(query), "name = \"%s\"", name); if (liftDb != NULL) { // Fetch via quickLiftSql so we get both the items and the set of // swapped chains that map them back to the destination assembly, then // lift the genePreds with calcLiftOverGenePreds. seqName/winStart/ // winEnd are destination coords; quickLiftSql picks up the chains // that overlap that window on the destination side. char *quickLiftFile = trackDbSetting(tdb, "quickLiftUrl"); struct hash *chainHash = newHash(8); char extraWhere[512]; sqlSafef(extraWhere, sizeof extraWhere, "name = \"%s\"", name); - extern struct genePred *genePredExtLoad15(char **row); - gpList = (struct genePred *)quickLiftSql(conn, quickLiftFile, rootTable, - seqName, winStart, winEnd, NULL, extraWhere, - (ItemLoader2)genePredExtLoad15, 0, chainHash); + gpList = quickLiftGenePreds(conn, quickLiftFile, rootTable, + seqName, winStart, winEnd, extraWhere, chainHash); calcLiftOverGenePreds(gpList, chainHash, 0.0, 0.0, TRUE, NULL, NULL, TRUE, FALSE); } else gpList = genePredReaderLoadQuery(conn, table, query); for (gp = gpList; gp != NULL; gp = gp->next) { printPos(gp->chrom, gp->txStart, gp->txEnd, gp->strand, FALSE, NULL); if(sameString(tdb->type,"genePred") && startsWith("ENCODE Gencode",tdb->longLabel) && startsWith("ENST",name)) { char *ensemblIdUrl = trackDbSetting(tdb, "ensemblIdUrl"); printf("<b>Ensembl Transcript Id: </b>"); if (ensemblIdUrl != NULL) @@ -9653,36 +9651,33 @@ struct genePred *gp; 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 = trackHubSkipHubName(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); - 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); + gpList = quickLiftGenePreds(conn, quickLiftFile, table, seqName, winStart, winEnd, extraWhere, chainHash); hFreeConn(&conn); calcLiftOverGenePreds( gpList, chainHash, 0.0, 0.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);