5e8e0ed53c05f2ef9b51ce897440bae308367f47 chmalee Wed Feb 9 14:45:54 2022 -0800 Add csv output option to table browser to support opening files in Excel, refs #27623. Also change the output filename message to hint that Excel can auto-recognize .csv extensions and behave appropriately. Lastly, fix output dropdown selection to properly warn on update when using GTF output option or a snp table. diff --git src/hg/hgTables/hgTables.c src/hg/hgTables/hgTables.c index 76ec309..3a0df73 100644 --- src/hg/hgTables/hgTables.c +++ src/hg/hgTables/hgTables.c @@ -986,31 +986,31 @@ hOrFPrintf(f, "%s\t", field); field = sqlFieldName(sr); } if (sameWord("reserved",field)) { hOrFPrintf(f, "itemRgb\n"); ret = lastCol; } else hOrFPrintf(f, "%s\n", field); return(ret); } void doTabOutDb( char *db, char *dbVarName, char *table, char *tableVarName, - FILE *f, struct sqlConnection *conn, char *fields) + FILE *f, struct sqlConnection *conn, char *fields, char outSep) /* Do tab-separated output on fields of a single table. */ { struct region *regionList = getRegions(); struct region *region; struct hTableInfo *hti = NULL; struct dyString *fieldSpec = newDyString(256); struct hash *idHash = NULL; int outCount = 0; boolean isPositional; int fieldCount; char *idField; boolean showItemRgb = FALSE; int itemRgbCol = -1; /* -1 means not found */ boolean printedColumns = FALSE; struct trackDb *tdb = findTdbForTable(db, curTrack, table, ctLookupName); @@ -1070,83 +1070,99 @@ // Show only the SQL filter built from filter page options, not identifierFilter, // because identifierFilter can get enormous (like 126kB for 12,500 rsIDs). char *filterNoIds = filterClause(dbVarName, tableVarName, region->chrom, NULL); if (filterNoIds != NULL) hOrFPrintf(f, "#filter: %s\n", filterNoIds); hOrFPrintf(f, "#"); if (showItemRgb) { itemRgbCol = itemRgbHeader(f, sr, lastCol); if (itemRgbCol == -1) showItemRgb = FALSE; /* did not find "reserved" */ } else { for (colIx = 0; colIx < lastCol; ++colIx) - hOrFPrintf(f, "%s\t", sqlFieldName(sr)); - hOrFPrintf(f, "%s\n", sqlFieldName(sr)); + { + if (outSep == ',') hOrFPrintf(f, "\""); + hOrFPrintf(f, "%s", sqlFieldName(sr)); + if (outSep == ',') hOrFPrintf(f, "\""); + hOrFPrintf(f, "%c", outSep); + } + if (outSep == ',') hOrFPrintf(f, "\""); + hOrFPrintf(f, "%s", sqlFieldName(sr)); + if (outSep == ',') hOrFPrintf(f, "\""); + hOrFPrintf(f, "\n"); } printedColumns = TRUE; } while ((row = sqlNextRow(sr)) != NULL) { if (idHash == NULL || isNotEmpty(identifierFilter) || hashLookup(idHash, row[fieldCount])) { if (showItemRgb) itemRgbDataOut(f, row, lastCol, itemRgbCol); else { for (colIx = 0; colIx < lastCol; ++colIx) - hOrFPrintf(f, "%s\t", row[colIx]); - hOrFPrintf(f, "%s\n", row[lastCol]); + { + if (outSep == ',') hOrFPrintf(f, "\""); + hOrFPrintf(f, "%s", row[colIx]); + if (outSep == ',') hOrFPrintf(f, "\""); + hOrFPrintf(f, "%c", outSep); + } + if (outSep == ',') hOrFPrintf(f, "\""); + hOrFPrintf(f, "%s", row[lastCol]); + if (outSep == ',') hOrFPrintf(f, "\""); + hOrFPrintf(f, "\n"); } ++outCount; } } sqlFreeResult(&sr); if (!isPositional) break; /* No need to iterate across regions in this case. */ freez(&filter); } /* Do some error diagnostics for user. */ if (outCount == 0) explainWhyNoResults(f); hashFree(&idHash); } -void doTabOutTable( char *db, char *table, FILE *f, struct sqlConnection *conn, char *fields) +void doTabOutTable( char *db, char *table, FILE *f, struct sqlConnection *conn, char *fields, char outSep) /* Do tab-separated output on fields of a single table. */ { boolean isTabix = FALSE; if (isBigBed(database, table, curTrack, ctLookupName)) - bigBedTabOut(db, table, conn, fields, f); + bigBedTabOut(db, table, conn, fields, f, outSep); else if (isLongTabixTable(table)) - longTabixTabOut(db, table, conn, fields, f); + longTabixTabOut(db, table, conn, fields, f, outSep); else if (isBamTable(table)) - bamTabOut(db, table, conn, fields, f); + bamTabOut(db, table, conn, fields, f, outSep); else if (isVcfTable(table, &isTabix)) vcfTabOut(db, table, conn, fields, f, isTabix); else if (isHicTable(table)) - hicTabOut(db, table, conn, fields, f); + hicTabOut(db, table, conn, fields, f, outSep); else if (isCustomTrack(table)) { - doTabOutCustomTracks(db, table, conn, fields, f); + doTabOutCustomTracks(db, table, conn, fields, f, outSep); } else - doTabOutDb(db, db, table, table, f, conn, fields); + doTabOutDb(db, db, table, table, f, conn, fields, outSep); } struct slName *fullTableFields(char *db, char *table) /* Return list of fields in db.table.field format. */ { char dtBuf[256]; struct sqlConnection *conn=NULL; struct slName *fieldList = NULL, *dtfList = NULL, *field, *dtf; if (isBigBed(database, table, curTrack, ctLookupName)) { if (!trackHubDatabase(database)) conn = hAllocConn(db); fieldList = bigBedGetFields(table, conn); hFreeConn(&conn); } @@ -1199,34 +1215,35 @@ slReverse(&dtfList); slFreeList(&fieldList); return dtfList; } void doOutPrimaryTable(char *table, struct sqlConnection *conn) /* Dump out primary table. */ { if (anySubtrackMerge(database, table)) errAbort("Can't do all fields output when subtrack merge is on. " "Please go back and select another output type (BED or custom track is good), or clear the subtrack merge."); if (anyIntersection()) errAbort("Can't do all fields output when intersection is on. " "Please go back and select another output type (BED or custom track is good), or clear the intersection."); textOpen(); +char sep = sameString(cartUsualString(cart, hgtaOutSep, outTab), outTab) ? '\t' : ','; if (sameWord(table, WIKI_TRACK_TABLE)) - tabOutSelectedFields(wikiDbName(), table, NULL, fullTableFields(wikiDbName(), table)); + sepOutSelectedFields(wikiDbName(), table, NULL, fullTableFields(wikiDbName(), table), sep); else - tabOutSelectedFields(database, table, NULL, fullTableFields(database, table)); + sepOutSelectedFields(database, table, NULL, fullTableFields(database, table), sep); } void ensureVisibility(char *db, char *table, struct trackDb *tdb) /* Check track visibility; if hide, print out CGI to set it to pack or full. */ { enum trackVisibility vis = tvHide; char *cartVis = cartOptionalString(cart, table); if (isNotEmpty(cartVis)) vis = hTvFromString(cartVis); else { if (tdb == NULL) tdb = hTrackDbForTrackAndAncestors(db, table); if (tdb != NULL) {