4450e227ad04fd0176b28b6dffddabc0352a953f chmalee Mon Apr 13 14:28:42 2026 -0700 Restore xref term in search result name/description for findSpec searches with an xrefTable. Commit 5197ebd63b5 batched the per-xref doQuery into one combined "or in (...)" query for performance, but dropped the id -> xrefTerm mapping: pos->name became the raw id and pos->description was no longer set for xref matches. Rebuild the mapping as a hash from xrefList and use it when processing each row to restore pos->name = xrefTerm and pos->description = "(id)". The two-query shape is preserved. refs #37345 diff --git src/hg/lib/hgFind.c src/hg/lib/hgFind.c index 5772125d374..9e56efbe735 100644 --- src/hg/lib/hgFind.c +++ src/hg/lib/hgFind.c @@ -2537,30 +2537,50 @@ else safef(buf, sizeof(buf), "%s", hfs->searchTable); description = cloneString(buf); if (hgp->tableList != NULL && sameString(hgp->tableList->name, hfs->searchTable) && sameString(hgp->tableList->description, description)) table = hgp->tableList; // this is taken from hgFindSpecCustom.c:checkQueryFormat() and changed to // capture the name field for a table static char *queryFormatRegexForIdField = "^select [[:alnum:]]+, ?[[:alnum:]]+, ?[[:alnum:]]+, ?[[:alnum:]]+ " "from %s where ([[:alnum:]]+) (r?like|=) ['\"]?.*%s.*['\"]?$"; regmatch_t substrs[3]; + +// Build an id -> xrefTerm lookup so result rows can be labeled with the +// human-readable xref term (e.g. gene symbol) instead of the raw id. +struct hash *xrefHash = NULL; +if (xrefList) + { + struct slPair *p; + for (p = xrefList; p != NULL; p = p->next) + { + if (isNotEmpty(p->name) && isNotEmpty((char *)p->val)) + { + if (xrefHash == NULL) + xrefHash = hashNew(0); + // first xref term wins if multiple xrefs map to the same id + if (!hashLookup(xrefHash, (char *)p->val)) + hashAdd(xrefHash, (char *)p->val, p->name); + } + } + } + for (tPtr = tableList; tPtr != NULL; tPtr = tPtr->next ) { struct dyString *query = sqlDyStringCreate(hfs->query, tPtr->name, term); if (xrefList) { // NOTE: hfsPolish guarantees the query format and allows the below regex to work. // See hgFindSpecCustom.c for more details, specifically checkQueryFormat() if (regexMatchSubstr(hfs->query, queryFormatRegexForIdField, substrs, ArraySize(substrs))) { char *idField = regexSubstringClone(hfs->query, substrs[1]); sqlDyStringPrintf(query, " or %s in (", idField); struct slName *vals = NULL; struct slPair *ptr = xrefList; for (; ptr != NULL; ptr = ptr->next) { @@ -2586,60 +2606,73 @@ while ((row = sqlNextRow(sr)) != NULL) { if(table == NULL) { AllocVar(table); table->searchTime = -1; table->description = description; table->name = cloneString(hfs->searchTable); slAddHead(&hgp->tableList, table); } found = TRUE; AllocVar(pos); pos->chrom = cloneString(row[0]); pos->chromStart = atoi(row[1]); pos->chromEnd = atoi(row[2]); + char *xrefTerm = xrefHash ? hashFindVal(xrefHash, row[3]) : NULL; + if (isNotEmpty(xrefTerm)) + { + truncatef(buf, sizeof(buf), "%s", xrefTerm); + pos->name = cloneString(buf); + safef(buf, sizeof(buf), "(%s%s)", + termPrefix ? termPrefix : "", row[3]); + pos->description = cloneString(buf); + } + else + { safef(buf, sizeof(buf), "%s%s", termPrefix ? termPrefix : "", row[3]); pos->name = cloneString(buf); + } pos->browserName = cloneString(row[3]); if (relativeFlag && (pos->chromStart + relEnd) <= pos->chromEnd) { pos->chromEnd = pos->chromStart + relEnd; pos->chromStart = pos->chromStart + relStart; } else if (padding > 0 && !multiTerm) { // highlight the item bases to distinguish from padding pos->highlight = addHighlight(db, pos->chrom, pos->chromStart, pos->chromEnd); int chromSize = hChromSize(db, pos->chrom); pos->chromStart -= padding; pos->chromEnd += padding; if (pos->chromStart < 0) pos->chromStart = 0; if (pos->chromEnd > chromSize) pos->chromEnd = chromSize; } slAddHead(&table->posList, pos); } } if (table != NULL) slReverse(&table->posList); sqlFreeResult(&sr); hFreeConn(&conn); slFreeList(&tableList); +hashFree(&xrefHash); if (measureTiming && table) table->searchTime += clock1000() - startTime; return(found); } static boolean hgFindUsingSpec(struct cart *cart, char *db, struct hgFindSpec *hfs, char *term, int limitResults, struct hgPositions *hgp, boolean relativeFlag, int relStart, int relEnd, boolean multiTerm, boolean measureTiming) /* Perform the search described by hfs on term. If successful, put results * in hgp and return TRUE. (If not, don't modify hgp.) */ { struct slPair *xrefList = NULL; boolean found = FALSE;