9af188ea6147f9edb20bd531d3ec988501cf997c
chmalee
  Fri Feb 6 12:18:25 2026 -0800
Fix jsonOutputArrays columnTypes output when more than one track is requested with /getData/track. Leaves /list/schema alone. Add option to hgTracks Downloads -> Download track data in view menu to include column headers in output, refs #36858

diff --git src/hg/hubApi/apiUtils.c src/hg/hubApi/apiUtils.c
index b61d501f229..563514c93d0 100644
--- src/hg/hubApi/apiUtils.c
+++ src/hg/hubApi/apiUtils.c
@@ -547,106 +547,106 @@
 /* is given type in the supportedTypes list ? */
 {
 boolean ret = FALSE;
 struct slName *el;
 for (el = supportedTypes; el; el = el->next)
     {
     if (startsWith(el->name, type))
 	{
 	ret = TRUE;
 	break;
 	}
     }
 return ret;
 }
 
-void wigColumnTypes(struct jsonWrite *jw)
+void wigColumnTypes(struct jsonWrite *jw, char *track)
 /* output column headers for a wiggle data output schema */
 {
-jsonWriteListStart(jw, "columnTypes");
+jsonWriteListStart(jw, track);
 
 jsonWriteObjectStart(jw, NULL);
 jsonWriteString(jw, "name", "start");
 jsonWriteString(jw, "sqlType", "int");
 jsonWriteString(jw, "jsonType", "number");
 jsonWriteString(jw, "description", "chromStart: 0-based chromosome start position");
 jsonWriteObjectEnd(jw);
 
 jsonWriteObjectStart(jw, NULL);
 jsonWriteString(jw, "name", "end");
 jsonWriteString(jw, "sqlType", "int");
 jsonWriteString(jw, "jsonType", "number");
 jsonWriteString(jw, "description", "chromEnd: 1-based chromosome end position");
 jsonWriteObjectEnd(jw);
 
 jsonWriteObjectStart(jw, NULL);
 jsonWriteString(jw, "name", "value");
 jsonWriteString(jw, "sqlType", "float");
 jsonWriteString(jw, "jsonType", "number");
 jsonWriteString(jw, "description", "numerical data value for this location:start-end");
 jsonWriteObjectEnd(jw);
 
 jsonWriteListEnd(jw);
 }	/* void wigColumnTypes(struct jsonWrite jw) */
 
 void outputSchema(struct trackDb *tdb, struct jsonWrite *jw,
     char *columnNames[], char *columnTypes[], int jsonTypes[],
 	struct hTableInfo *hti, int columnCount, int asColumnCount,
-	    struct asColumn *columnEl)
+	    struct asColumn *columnEl, char *keyStr)
 /* print out the SQL schema for this trackDb */
 {
 if (tdb && isWiggleDataTable(tdb->type))
     {
-        wigColumnTypes(jw);
+        wigColumnTypes(jw, keyStr);
     }
 else
     {
-    jsonWriteListStart(jw, "columnTypes");
+    jsonWriteListStart(jw, keyStr);
     int i = 0;
     for (i = 0; i < columnCount; ++i)
         {
         jsonWriteObjectStart(jw, NULL);
         jsonWriteString(jw, "name", columnNames[i]);
         jsonWriteString(jw, "sqlType", columnTypes[i]);
         jsonWriteString(jw, "jsonType", jsonTypeStrings[jsonTypes[i]]);
         if ((0 == i) && (hti && hti->hasBin))
             jsonWriteString(jw, "description", "Indexing field to speed chromosome range queries");
         else if (columnEl && isNotEmpty(columnEl->comment))
             jsonWriteString(jw, "description", columnEl->comment);
         else
             jsonWriteString(jw, "description", "");
 
         /* perhaps move the comment pointer forward */
         if (columnEl)
             {
             if (asColumnCount == columnCount)
                 columnEl = columnEl->next;
             else if (! ((0 == i) && (hti && hti->hasBin)))
                 columnEl = columnEl->next;
             }
         jsonWriteObjectEnd(jw);
 	}
     jsonWriteListEnd(jw);
     }
 }
 
 void bigColumnTypes(struct jsonWrite *jw, struct sqlFieldType *fiList,
-    struct asObject *as)
+    struct asObject *as, char *track)
 /* show the column types from a big file autoSql definitions */
 {
 struct asColumn *columnEl = as->columnList;
-jsonWriteListStart(jw, "columnTypes");
+jsonWriteListStart(jw, track);
 struct sqlFieldType *fi = fiList;
 for ( ; fi; fi = fi->next, columnEl = columnEl->next)
     {
     int jsonType = autoSqlToJsonType(fi->type);
     jsonWriteObjectStart(jw, NULL);
     jsonWriteString(jw, "name", fi->name);
     jsonWriteString(jw, "sqlType", fi->type);
     jsonWriteString(jw, "jsonType",jsonTypeStrings[jsonType]);
     if (columnEl && isNotEmpty(columnEl->comment))
 	jsonWriteString(jw, "description", columnEl->comment);
     else
 	jsonWriteString(jw, "description", "");
     jsonWriteObjectEnd(jw);
     }
 jsonWriteListEnd(jw);