44ccfacbe3a3d4b300f80d48651c77837a4b571e galt Tue Apr 26 11:12:02 2022 -0700 SQL INJECTION Prevention Version 2 - this improves our methods by making subclauses of SQL that get passed around be both easy and correct to use. The way that was achieved was by getting rid of the obscure and not well used functions sqlSafefFrag and sqlDyStringPrintfFrag and replacing them with the plain versions of those functions, since these are not needed anymore. The new version checks for NOSQLINJ in unquoted %-s which is used to include SQL clauses, and will give an error the NOSQLINJ clause is not present, and this will automatically require the correct behavior by developers. sqlDyStringPrint is a very useful function, however because it was not enforced, users could use various other dyString functions and they operated without any awareness or checking for SQL correct use. Now those dyString functions are prohibited and it will produce an error if you try to use a dyString function on a SQL string, which is simply detected by the presence of the NOSQLINJ prefix. diff --git src/hg/hgTracks/gencodeTracks.c src/hg/hgTracks/gencodeTracks.c index 2960563..47fe47e 100644 --- src/hg/hgTracks/gencodeTracks.c +++ src/hg/hgTracks/gencodeTracks.c @@ -1,688 +1,689 @@ /* gencodeTracks - ENCODE GENCODE Genes tracks for both pilot and production ENCODE. * although these are used fundamentally different approaches to display */ /* Copyright (C) 2014 The Regents of the University of California * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */ #include "common.h" #include "hgTracks.h" #include "hdb.h" #include "gencodeIntron.h" #include "genePredReader.h" #include "genePred.h" #include "encode/wgEncodeGencodeAttrs.h" /* item label symbolic names and constants. This must be * in sync with lib/hui.c:gencodeLabelControls() */ enum /* bit set of item labels */ { ITEM_LABEL_GENE_NAME = 0x01, ITEM_LABEL_GENE_ID = 0x02, ITEM_LABEL_TRANSCRIPT_ID = 0x04 }; static struct /* label names to constant */ { char *name; unsigned flag; } itemLabelCartVarNamesMap[] = { {"geneName", ITEM_LABEL_GENE_NAME}, {"geneId", ITEM_LABEL_GENE_ID}, {"transcriptId", ITEM_LABEL_TRANSCRIPT_ID}, {NULL, 0} }; /* function type that returns filter or highlight types */ typedef filterBy_t* (*filterBySetGetFuncType)(struct trackDb *tdb, struct cart *cart, char *name); struct gencodeQuery /* Structure used to store information about the query being assembled. * Joins are for the purpose of filtering results, and in some cases, returning * additional information. */ { struct dyString *fields; // select fields struct dyString *from; // from clause struct dyString *where; // where clause int genePredNumColumns; // number of genePred columns returned int attrsNumColumns; // number of attr columns returned boolean isGenePredX; // does this have the extended fields? boolean isFiltered; // are there filters on the query? boolean joinAttrs; // join the wgEncodeGencodeAttrs table boolean joinSupportLevel; // join the wgEncodeGencodeTranscriptionSupportLevel table boolean joinTranscriptSource; // join the wgEncodeGencodeTranscriptSource table boolean joinTag; // join the wgEncodeGencodeTag table (one to many, so filtering only) }; static struct gencodeQuery *gencodeQueryNew(void) /* construct a new gencodeQuery object */ { struct gencodeQuery *gencodeQuery; AllocVar(gencodeQuery); gencodeQuery->fields = dyStringNew(0); gencodeQuery->from = dyStringNew(0); gencodeQuery->where = dyStringNew(0); return gencodeQuery; } static void gencodeQueryFree(struct gencodeQuery **gencodeQueryPtr) /* construct a new gencodeQuery object */ { struct gencodeQuery *gencodeQuery = *gencodeQueryPtr; if (gencodeQuery != NULL) { dyStringFree(&gencodeQuery->fields); dyStringFree(&gencodeQuery->from); dyStringFree(&gencodeQuery->where); freeMem(gencodeQuery); *gencodeQueryPtr = NULL; } } static void gencodeQueryBeginSubWhere(struct gencodeQuery *gencodeQuery) /* begin adding new where sub-clause */ { if (dyStringLen(gencodeQuery->where) > 0) dyStringAppend(gencodeQuery->where, " and "); dyStringAppend(gencodeQuery->where, "("); } static void gencodeQueryEndSubWhere(struct gencodeQuery *gencodeQuery) /* finish adding new where sub-clause */ { dyStringAppend(gencodeQuery->where, ")"); } static struct genePred *gencodeQueryGenePred(struct gencodeQuery *gencodeQuery, char **row) /* get genePred from a query results */ { return genePredExtLoad(row, gencodeQuery->genePredNumColumns); } static struct wgEncodeGencodeAttrs *gencodeQueryAttrs(struct gencodeQuery *gencodeQuery, char **row) /* get attributes from a query results, or NULL if not requested */ { if (gencodeQuery->attrsNumColumns > 0) return wgEncodeGencodeAttrsLoad(row + gencodeQuery->genePredNumColumns, gencodeQuery->attrsNumColumns); else return NULL; } static boolean anyFilterBy(struct track *tg, filterBySetGetFuncType filterBySetGetFunc) /* check if any filters were specified of the particular type */ { filterBy_t *filterBySet = filterBySetGetFunc(tg->tdb, cart, NULL); filterBy_t *filterBy; boolean someFilters = FALSE; for (filterBy = filterBySet; (filterBy != NULL) && !someFilters; filterBy = filterBy->next) { if (!filterByAllChosen(filterBy)) someFilters = TRUE; } filterBySetFree(&filterBySet); return someFilters; } static char *tslSymToNumStr(char *tslSym) /* convert a transcription support level string (tsl1..tsl5, tslN), to * a numeric string ("1".."5", "-1") */ { if (sameString(tslSym, "tslNA")) return "-1"; else return tslSym+3; } static void filterByMethodChoiceQuery(char *choice, struct gencodeQuery *gencodeQuery) /* add SQL expression for GENCODE transcript method choice. */ { /* * example sources and categories: * havana_ig_gene manual, manual only * ensembl_havana_transcript manual, automatic & manual and automatic * havana manual, manual only * ensembl automatic, automatic only * mt_genbank_import automatic, automatic only */ if (sameString(choice, "manual")) dyStringAppend(gencodeQuery->where, "(transSrc.source like \"%havana%\")"); else if (sameString(choice, "automatic")) dyStringAppend(gencodeQuery->where, "((transSrc.source like \"%ensembl%\") or (transSrc.source not like \"%havana%\"))"); else if (sameString(choice, "manual_only")) dyStringAppend(gencodeQuery->where, "((transSrc.source like \"%havana%\") and (transSrc.source not like \"%ensembl%\"))"); else if (sameString(choice, "automatic_only")) dyStringAppend(gencodeQuery->where, "(transSrc.source not like \"%havana%\")"); else if (sameString(choice, "manual_and_automatic")) dyStringAppend(gencodeQuery->where, "((transSrc.source like \"%havana%\") and (transSrc.source like \"%ensembl%\"))"); else errAbort("BUG: filterByMethodChoiceQuery missing choice: \"%s\"", choice); } static void filterByMethodChoicesQuery(filterBy_t *filterBy, struct gencodeQuery *gencodeQuery) /* add transcript source compare clauses */ { struct slName *choice = NULL; for (choice = filterBy->slChoices; choice != NULL; choice = choice->next) { if (choice != filterBy->slChoices) dyStringAppend(gencodeQuery->where, " or "); filterByMethodChoiceQuery(choice->name, gencodeQuery); } } static void filterByMethodQuery(struct track *tg, filterBy_t *filterBy, struct gencodeQuery *gencodeQuery) /* generate SQL where clause for annotation method filtering */ { gencodeQueryBeginSubWhere(gencodeQuery); filterByMethodChoicesQuery(filterBy, gencodeQuery); gencodeQuery->joinTranscriptSource = TRUE; gencodeQueryEndSubWhere(gencodeQuery); } static void filterBySupportLevelChoiceQuery(char *choice, struct gencodeQuery *gencodeQuery) /* add SQL expression GENCODE support choice. */ { /* table is numeric (silly me), and string is tsl1..tsl5 or tslNA */ dyStringPrintf(gencodeQuery->where, "(supLevel.level = %s)", tslSymToNumStr(choice)); } static void filterBySupportLevelChoicesQuery(filterBy_t *filterBy, struct gencodeQuery *gencodeQuery) /* add support level compare clauses */ { struct slName *choice = NULL; for (choice = filterBy->slChoices; choice != NULL; choice = choice->next) { if (choice != filterBy->slChoices) dyStringAppend(gencodeQuery->where, " or "); filterBySupportLevelChoiceQuery(choice->name, gencodeQuery); } } static void filterBySupportLevelQuery(struct track *tg, filterBy_t *filterBy, struct gencodeQuery *gencodeQuery) /* generate SQL where clause for annotation support level filtering */ { gencodeQueryBeginSubWhere(gencodeQuery); filterBySupportLevelChoicesQuery(filterBy, gencodeQuery); gencodeQuery->joinSupportLevel = TRUE; gencodeQueryEndSubWhere(gencodeQuery); } static void filterByTagChoiceQuery(char *choice, struct gencodeQuery *gencodeQuery) /* add SQL expression GENCODE tag choice. */ { dyStringPrintf(gencodeQuery->where, "(tag.tag = \"%s\")", choice); } static void filterByTagChoicesQuery(filterBy_t *filterBy, struct gencodeQuery *gencodeQuery) /* add tag compare clauses */ { struct slName *choice = NULL; for (choice = filterBy->slChoices; choice != NULL; choice = choice->next) { if (choice != filterBy->slChoices) dyStringAppend(gencodeQuery->where, " or "); filterByTagChoiceQuery(choice->name, gencodeQuery); } } static void filterByTagQuery(struct track *tg, filterBy_t *filterBy, struct gencodeQuery *gencodeQuery) /* generate SQL where clause for annotation tag filtering */ { gencodeQueryBeginSubWhere(gencodeQuery); filterByTagChoicesQuery(filterBy, gencodeQuery); gencodeQuery->joinTag = TRUE; gencodeQueryEndSubWhere(gencodeQuery); } static void filterByAttrsQuery(struct track *tg, filterBy_t *filterBy, struct gencodeQuery *gencodeQuery) /* handle adding on filterBy clause for attributes table */ { char *clause = filterByClause(filterBy); if (clause != NULL) { gencodeQueryBeginSubWhere(gencodeQuery); - dyStringPrintf(gencodeQuery->where, "%s", clause); + sqlDyStringPrintf(gencodeQuery->where, "%-s", clause); gencodeQuery->joinAttrs = TRUE; gencodeQueryEndSubWhere(gencodeQuery); freeMem(clause); } } static void gencodeFilterByQuery(struct track *tg, filterBy_t *filterBy, struct gencodeQuery *gencodeQuery) /* handle adding on filterBy clause for gencode */ { if (sameString(filterBy->column, "transcriptMethod")) filterByMethodQuery(tg, filterBy, gencodeQuery); else if (sameString(filterBy->column, "supportLevel")) filterBySupportLevelQuery(tg, filterBy, gencodeQuery); else if (sameString(filterBy->column, "tag")) filterByTagQuery(tg, filterBy, gencodeQuery); else if (startsWith("attrs.", filterBy->column)) filterByAttrsQuery(tg, filterBy, gencodeQuery); else errAbort("gencodeFilterByQuery: don't know how to filter on column \"%s\"", filterBy->column); gencodeQuery->isFiltered = TRUE; } static void gencodeFilterBySetQuery(struct track *tg, filterBySetGetFuncType filterBySetGetFunc, struct gencodeQuery *gencodeQuery) /* build where sql clauses for filters or highlights. */ { filterBy_t *filterBySet = filterBySetGetFunc(tg->tdb, cart, NULL); filterBy_t *filterBy; for (filterBy = filterBySet; filterBy != NULL; filterBy = filterBy->next) { if (!filterByAllChosen(filterBy)) gencodeFilterByQuery(tg, filterBy, gencodeQuery); } filterBySetFree(&filterBySet); } static void addQueryTables(struct track *tg, struct gencodeQuery *gencodeQuery) /* add required from tables and joins */ { -sqlDyStringPrintfFrag(gencodeQuery->from, "%s g", tg->table); +sqlDyStringPrintf(gencodeQuery->from, "%s g", tg->table); if (gencodeQuery->joinAttrs) { sqlDyStringPrintf(gencodeQuery->from, ", %s attrs", trackDbRequiredSetting(tg->tdb, "wgEncodeGencodeAttrs")); - dyStringAppend(gencodeQuery->where, " and (attrs.transcriptId = g.name)"); + sqlDyStringPrintf(gencodeQuery->where, " and (attrs.transcriptId = g.name)"); } if (gencodeQuery->joinTranscriptSource) { sqlDyStringPrintf(gencodeQuery->from, ", %s transSrc", trackDbRequiredSetting(tg->tdb, "wgEncodeGencodeTranscriptSource")); - dyStringAppend(gencodeQuery->where, " and (transSrc.transcriptId = g.name)"); + sqlDyStringPrintf(gencodeQuery->where, " and (transSrc.transcriptId = g.name)"); } if (gencodeQuery->joinSupportLevel) { sqlDyStringPrintf(gencodeQuery->from, ", %s supLevel", trackDbRequiredSetting(tg->tdb, "wgEncodeGencodeTranscriptionSupportLevel")); - dyStringAppend(gencodeQuery->where, " and (supLevel.transcriptId = g.name)"); + sqlDyStringPrintf(gencodeQuery->where, " and (supLevel.transcriptId = g.name)"); } if (gencodeQuery->joinTag) { sqlDyStringPrintf(gencodeQuery->from, ", %s tag", trackDbRequiredSetting(tg->tdb, "wgEncodeGencodeTag")); - dyStringAppend(gencodeQuery->where, " and (tag.transcriptId = g.name)"); + sqlDyStringPrintf(gencodeQuery->where, " and (tag.transcriptId = g.name)"); } } static void addQueryCommon(struct track *tg, filterBySetGetFuncType filterBySetGetFunc, struct gencodeQuery *gencodeQuery) /* Add tables and joins for both gene and highlight queries */ { // bin range overlap part hAddBinToQuery(winStart, winEnd, gencodeQuery->where); sqlDyStringPrintf(gencodeQuery->where, "(g.chrom = \"%s\") and (g.txStart < %u) and (g.txEnd > %u)", chromName, winEnd, winStart); gencodeFilterBySetQuery(tg, filterBySetGetFunc, gencodeQuery); addQueryTables(tg, gencodeQuery); } static struct sqlResult *executeQuery(struct sqlConnection *conn, struct gencodeQuery *gencodeQuery) /* execute the actual SQL query */ { struct dyString *query = dyStringNew(0); +sqlCkIl(fieldsSafe,dyStringContents(gencodeQuery->fields)) sqlDyStringPrintf(query, "select %-s from %-s where %-s", - sqlCkIl(dyStringContents(gencodeQuery->fields)), dyStringContents(gencodeQuery->from), dyStringContents(gencodeQuery->where)); + fieldsSafe, dyStringContents(gencodeQuery->from), dyStringContents(gencodeQuery->where)); struct sqlResult *sr = sqlGetResult(conn, dyStringContents(query)); dyStringFree(&query); return sr; } static boolean annotIsGenePredExt(struct track *tg) /* determine if a table has genePred extended fields. two-way consensus * pseudo doesn't have them. */ { struct sqlConnection *conn = hAllocConn(database); struct slName *fields = sqlFieldNames(conn, tg->table); hFreeConn(&conn); boolean isGenePredX = slNameInList(fields, "score"); slFreeList(&fields); return isGenePredX; } static boolean attrsHasProteinId(struct track *tg) /* determine if the attributes table has the proteinId field.. */ { struct sqlConnection *conn = hAllocConn(database); struct slName *fields = sqlFieldNames(conn, trackDbRequiredSetting(tg->tdb, "wgEncodeGencodeAttrs")); hFreeConn(&conn); boolean hasProteinId = slNameInList(fields, "proteinId"); slFreeList(&fields); return hasProteinId; } static void geneQueryAddGenePredCols(struct track *tg, struct gencodeQuery *gencodeQuery) /* add genePred columns to query */ { static char *genePredFields = "g.name, g.chrom, g.strand, g.txStart, g.txEnd, g.cdsStart, g.cdsEnd, g.exonCount, g.exonStarts, g.exonEnds"; static char *genePredXFields = ", g.score, g.name2, g.cdsStartStat, g.cdsEndStat, g.exonFrames"; gencodeQuery->isGenePredX = annotIsGenePredExt(tg); dyStringAppend(gencodeQuery->fields, genePredFields); gencodeQuery->genePredNumColumns = GENEPRED_NUM_COLS; if (gencodeQuery->isGenePredX) { dyStringAppend(gencodeQuery->fields, genePredXFields); gencodeQuery->genePredNumColumns = GENEPREDX_NUM_COLS; } } static void geneQueryAddAttrsCols(struct track *tg, struct gencodeQuery *gencodeQuery) /* add attributes columns to query */ { char *attrsBaseFields = "attrs.geneId, attrs.geneName, attrs.geneType, attrs.geneStatus, attrs.transcriptId, attrs.transcriptName, attrs.transcriptType, attrs.transcriptStatus, attrs.havanaGeneId, attrs.havanaTranscriptId, attrs.ccdsId, attrs.level, attrs.transcriptClass"; char *attrsExtraFields = ", attrs.proteinId"; dyStringAppend(gencodeQuery->fields, ", "); dyStringAppend(gencodeQuery->fields, attrsBaseFields); gencodeQuery->attrsNumColumns = WGENCODEGENCODEATTRS_NO_PROTEIN_ID_NUM_COLS; if (attrsHasProteinId(tg)) { dyStringAppend(gencodeQuery->fields, attrsExtraFields); gencodeQuery->attrsNumColumns = WGENCODEGENCODEATTRS_NUM_COLS; } gencodeQuery->joinAttrs = TRUE; } static struct gencodeQuery *geneQueryConstruct(struct track *tg, boolean includeAttrs) /* construct the query for a GENCODE records, which includes filters. */ { struct gencodeQuery *gencodeQuery = gencodeQueryNew(); geneQueryAddGenePredCols(tg, gencodeQuery); if (includeAttrs) geneQueryAddAttrsCols(tg, gencodeQuery); addQueryCommon(tg, filterBySetGet, gencodeQuery); return gencodeQuery; } static struct gencodeQuery *highlightQueryConstruct(struct track *tg) /* construct the query for GENCODE ids which should be highlighted. * this essentially redoes the genePred query, only using the filter functions * and only getting ids */ { struct gencodeQuery *gencodeQuery = gencodeQueryNew(); dyStringAppend(gencodeQuery->fields, "g.name"); addQueryCommon(tg, highlightBySetGet, gencodeQuery); return gencodeQuery; } static unsigned getHighlightColor(struct track *tg) /* get the highlightColor from trackDb, or a default if not found */ { unsigned char red = 255, green = 165, blue = 0; // Orange default char *colorStr = trackDbSetting(tg->tdb, "highlightColor"); if (colorStr != NULL) parseColor(colorStr, &red, &green, &blue); return MAKECOLOR_32(red, green, blue); } static void highlightByGetColor(struct genePred *gp, struct hash *highlightIds, unsigned highlightColor, struct linkedFeatures *lf) /* compute the highlight color based on a extra fields returned in a row, setting * the linkedFeatures field */ { if (hashLookup(highlightIds, gp->name) != NULL) { lf->highlightColor = highlightColor; lf->highlightMode = highlightBackground; } } static struct hash* loadHighlightIds(struct sqlConnection *conn, struct track *tg) /* Load ids (genePred names) in window for annotations to be highlighted. */ { struct hash *highlightIds = hashNew(0); struct gencodeQuery *gencodeQuery = highlightQueryConstruct(tg); struct sqlResult *sr = executeQuery(conn, gencodeQuery); char **row; while ((row = sqlNextRow(sr)) != NULL) hashAddInt(highlightIds, row[0], 1); sqlFreeResult(&sr); return highlightIds; } static boolean getLabelCartVar(struct track *tg, char *labelName, boolean *anyExistsP) /* get the cart label value for a label type. Sort TRUE in anyExistsP if the variable exists. */ { char varSuffix[64]; safef(varSuffix, sizeof(varSuffix), "label.%s", labelName); char *value = cartUsualStringClosestToHome(cart, tg->tdb, FALSE, varSuffix, NULL); if (value != NULL) *anyExistsP = TRUE; return ((value != NULL) && !sameString(value, "0")); } static void setLabelCartVar(struct track *tg, char *labelName, boolean value) /* set one of the label type cart variables. */ { char varName[256]; safef(varName, sizeof(varName), "%s.label.%s", tg->track, labelName); cartSetBoolean(cart, varName, value); } static unsigned setFromOldLabelsVarsInCart(struct track *tg) /* If the old gencode label variable are set for this track, migrate to the new * variable. This prevents labels from disappearing with the new old and an old cart. */ { // logic from simpleTracks.c:genePredAssignConfiguredName() unsigned enabledLabels = 0; char *geneLabel = cartUsualStringClosestToHome(cart, tg->tdb, FALSE, "label", "gene"); if (sameString(geneLabel, "gene") || sameString(geneLabel, "name") || sameString(geneLabel, "both")) { setLabelCartVar(tg, "geneName", TRUE); enabledLabels |= ITEM_LABEL_GENE_NAME; } if (sameString(geneLabel, "accession") || sameString(geneLabel, "both")) { setLabelCartVar(tg, "transcriptId", TRUE); enabledLabels |= ITEM_LABEL_TRANSCRIPT_ID; } cartRemoveVariableClosestToHome(cart, tg->tdb, FALSE, "label"); return enabledLabels; } static unsigned getEnabledLabels(struct track *tg) /* Look up each of the label type names in the cart to see if they are enabled, * Return bit set */ { unsigned enabledLabels = 0; boolean anyExists = FALSE; int i; for (i = 0; itemLabelCartVarNamesMap[i].name != NULL; i++) { if (getLabelCartVar(tg, itemLabelCartVarNamesMap[i].name, &anyExists)) enabledLabels |= itemLabelCartVarNamesMap[i].flag; } // if it looks like new track settings have never been configured, set from old. if ((enabledLabels == 0) && !anyExists) enabledLabels = setFromOldLabelsVarsInCart(tg); return enabledLabels; } static void concatItemName(char *name, int nameSize, char *value) /* add a name to the name buffer */ { if (strlen(name) > 0) safecat(name, nameSize, "/"); safecat(name, nameSize, value); } static char* getTranscriptLabel(unsigned enabledLabels, struct genePred *gp, struct wgEncodeGencodeAttrs *attrs) /* one type of label for a item in track */ { char name[256]; name[0] = '\0'; if (enabledLabels & ITEM_LABEL_GENE_NAME) concatItemName(name, sizeof(name), gp->name2); if (enabledLabels & ITEM_LABEL_GENE_ID) concatItemName(name, sizeof(name), attrs->geneId); if (enabledLabels & ITEM_LABEL_TRANSCRIPT_ID) concatItemName(name, sizeof(name), gp->name); return cloneString(name); } static struct linkedFeatures *loadGencodeTranscript(struct track *tg, struct gencodeQuery *gencodeQuery, char **row, unsigned enabledLabels, struct hash *highlightIds, unsigned highlightColor) /* load one genePred record into a linkedFeatures object */ { struct genePred *gp = gencodeQueryGenePred(gencodeQuery, row); struct wgEncodeGencodeAttrs *attrs = gencodeQueryAttrs(gencodeQuery, row); // maybe NULL struct linkedFeatures *lf = linkedFeaturesFromGenePred(tg, gp, TRUE); if (highlightIds != NULL) highlightByGetColor(gp, highlightIds, highlightColor, lf); if (gencodeQuery->isGenePredX) lf->extra = getTranscriptLabel(enabledLabels, gp, attrs); else lf->extra = cloneString(gp->name); wgEncodeGencodeAttrsFree(&attrs); return lf; } static void loadGencodeTrack(struct track *tg) /* Load genePreds in window info linked feature, with filtering, etc. */ { struct sqlConnection *conn = hAllocConn(database); unsigned enabledLabels = getEnabledLabels(tg); boolean needAttrs = (enabledLabels & ITEM_LABEL_GENE_ID) != 0; // only for certain labels struct hash *highlightIds = NULL; if (anyFilterBy(tg, highlightBySetGet)) highlightIds = loadHighlightIds(conn, tg); struct gencodeQuery *gencodeQuery = geneQueryConstruct(tg, needAttrs); struct sqlResult *sr = executeQuery(conn, gencodeQuery); struct linkedFeatures *lfList = NULL; unsigned highlightColor = getHighlightColor(tg); char **row; while ((row = sqlNextRow(sr)) != NULL) slAddHead(&lfList, loadGencodeTranscript(tg, gencodeQuery, row, enabledLabels, highlightIds, highlightColor)); sqlFreeResult(&sr); hFreeConn(&conn); if (tg->visibility != tvDense) slSort(&lfList, linkedFeaturesCmpStart); else slReverse(&lfList); tg->items = lfList; if (gencodeQuery->isFiltered) labelTrackAsFiltered(tg); gencodeQueryFree(&gencodeQuery); hashFree(&highlightIds); } static char *gencodeGeneName(struct track *tg, void *item) /* Get name to use for Gencode gene item. */ { struct linkedFeatures *lf = item; if (lf->extra != NULL) return lf->extra; else return lf->name; } static void gencodeGeneMethods(struct track *tg) /* Load up custom methods for ENCODE Gencode gene track */ { tg->loadItems = loadGencodeTrack; tg->itemName = gencodeGeneName; } static void registerProductionTrackHandlers() /* register track handlers for production GENCODE tracks */ { // ENCODE 1 legacy registerTrackHandler("wgEncodeSangerGencode", gencodeGeneMethods); // uses trackHandler attribute registerTrackHandler("wgEncodeGencode", gencodeGeneMethods); } static char *gencodePilotGeneName(struct track *tg, void *item) /* Get name to use for GENCODE pilot gene item. */ { struct linkedFeatures *lf = item; if (lf->extra != NULL) return lf->extra; else return lf->name; } static void gencodePilotGeneMethods(struct track *tg) /* Load up custom methods for ENCODE Gencode gene track */ { tg->loadItems = loadGenePredWithConfiguredName; tg->itemName = gencodePilotGeneName; } static Color gencodeIntronPilotColorItem(struct track *tg, void *item, struct hvGfx *hvg) /* Return color of ENCODE gencode intron track item. For ENCODE pilot tracks only. * Use recommended color palette pantone colors (level 4) for red, green, blue.*/ { struct gencodeIntron *intron = (struct gencodeIntron *)item; if (sameString(intron->status, "not_tested")) return hvGfxFindColorIx(hvg, 214,214,216); /* light grey */ if (sameString(intron->status, "RT_negative")) return hvGfxFindColorIx(hvg, 145,51,56); /* red */ if (sameString(intron->status, "RT_positive") || sameString(intron->status, "RACE_validated")) return hvGfxFindColorIx(hvg, 61,142,51); /* green */ if (sameString(intron->status, "RT_wrong_junction")) return getOrangeColor(hvg); /* orange */ if (sameString(intron->status, "RT_submitted")) return hvGfxFindColorIx(hvg, 102,109,112); /* grey */ return hvGfxFindColorIx(hvg, 214,214,216); /* light grey */ } static void gencodeIntronPilotLoadItems(struct track *tg) /* Load up track items. For ENCODE pilot tracks only. */ { bedLoadItem(tg, tg->table, (ItemLoader)gencodeIntronLoad); } static void gencodeIntronPilotMethods(struct track *tg) /* Load up custom methods for ENCODE Gencode intron validation track. * For ENCODE pilot tracks only. */ { tg->loadItems = gencodeIntronPilotLoadItems; tg->itemColor = gencodeIntronPilotColorItem; } static void gencodePilotRaceFragsMethods(struct track *tg) /* Load up custom methods for ENCODE Gencode RACEfrags track. For ENCODE * pilot tracks only. */ { tg->loadItems = loadGenePred; tg->subType = lfNoIntronLines; } static void registerPilotTrackHandlers() /* register track handlers for pilot GENCODE tracks */ { // hg16 only registerTrackHandler("encodeGencodeGene", gencodePilotGeneMethods); registerTrackHandler("encodeGencodeIntron", gencodeIntronPilotMethods); // hg17 only registerTrackHandler("encodeGencodeGeneJun05", gencodePilotGeneMethods); registerTrackHandler("encodeGencodeIntronJun05", gencodeIntronPilotMethods); registerTrackHandler("encodeGencodeGeneOct05", gencodePilotGeneMethods); registerTrackHandler("encodeGencodeIntronOct05", gencodeIntronPilotMethods); registerTrackHandler("encodeGencodeGeneMar07", gencodePilotGeneMethods); registerTrackHandler("encodeGencodeGenePolyAMar07", bed9Methods); registerTrackHandler("encodeGencodeRaceFrags", gencodePilotRaceFragsMethods); } void gencodeRegisterTrackHandlers() /* register track handlers for GENCODE tracks */ { registerProductionTrackHandlers(); registerPilotTrackHandlers(); }