15c2acbbf16454d91d9079216f21427fdd33a609
hiram
  Tue Apr 16 13:45:20 2019 -0700
beginning to allow the array output time to function refs #18869

diff --git src/hg/hubApi/getData.c src/hg/hubApi/getData.c
index ab5e0ab..e0e455a 100644
--- src/hg/hubApi/getData.c
+++ src/hg/hubApi/getData.c
@@ -87,32 +87,30 @@
 	safef(endName, sizeof(endName), "genoEnd");
 	}
     }
 
 if (sqlColumnExists(conn, sqlTable, "txStart"))	// track type genePred
     {
     safef(startName, sizeof(startName), "txStart");
     safef(endName, sizeof(endName), "txEnd");
     }
 
 /* no chrom specified, return entire table */
 if (isEmpty(chrom))
     sqlSafef(query, sizeof(query), "select * from %s", sqlTable);
 else if (0 == (start + end))	/* have chrom, no start,end == full chr */
     {
-//    boolean useTname = FALSE;
-    /* need to extend the chrom column check to allow tName also */
     if (! sqlColumnExists(conn, sqlTable, chromName))
 	apiErrAbort(err400, err400Msg, "track '%s' is not a position track, request track without chrom specification, genome: '%s'", track, db);
 
     jsonWriteString(jw, "chrom", chrom);
     struct chromInfo *ci = hGetChromInfo(db, chrom);
     jsonWriteNumber(jw, "start", (long long)0);
     jsonWriteNumber(jw, "end", (long long)ci->size);
     sqlSafef(query, sizeof(query), "select * from %s where %s='%s'", sqlTable, chromName, chrom);
     }
 else	/* fully specified chrom:start-end */
     {
     jsonWriteString(jw, "chrom", chrom);
     jsonWriteNumber(jw, "start", (long long)start);
     jsonWriteNumber(jw, "end", (long long)end);
     if (startsWith("wig", tdb->type))
@@ -122,54 +120,63 @@
 	}
     else
 	{
 	sqlSafef(query, sizeof(query), "select * from %s where %s='%s' AND %s > %u AND %s < %u", sqlTable, chromName, chrom, endName, start, startName, end);
 	}
     }
 
 if (debug)
     jsonWriteString(jw, "select", query);
 
 /* continuing, not a wiggle output */
 char **columnNames = NULL;
 char **columnTypes = NULL;
 int *jsonTypes = NULL;
 int columnCount = tableColumns(conn, jw, sqlTable, &columnNames, &columnTypes, &jsonTypes);
-if (debug)
+if (jsonOutputArrays || debug)
     {
     jsonWriteObjectStart(jw, "columnTypes");
     int i = 0;
     for (i = 0; i < columnCount; ++i)
 	{
 	char bothTypes[1024];
 	safef(bothTypes, sizeof(bothTypes), "%s - %s", columnTypes[i], jsonTypeStrings[jsonTypes[i]]);
 	jsonWriteString(jw, columnNames[i], bothTypes);
 	}
     jsonWriteObjectEnd(jw);
     }
 jsonWriteListStart(jw, track);
 struct sqlResult *sr = sqlGetResult(conn, query);
 char **row = NULL;
 unsigned itemCount = 0;
 while (itemCount < maxItemsOutput && (row = sqlNextRow(sr)) != NULL)
     {
+    if (jsonOutputArrays)
+	jsonWriteListStart(jw, NULL);
+    else
 	jsonWriteObjectStart(jw, NULL);
     int i = 0;
     for (i = 0; i < columnCount; ++i)
 	{
+	if (jsonOutputArrays)
+	    jsonDatumOut(jw, NULL, row[i], jsonTypes[i]);
+	else
 	    jsonDatumOut(jw, columnNames[i], row[i], jsonTypes[i]);
 	}
+    if (jsonOutputArrays)
+	jsonWriteListEnd(jw);
+    else
 	jsonWriteObjectEnd(jw);
     ++itemCount;
     }
 sqlFreeResult(&sr);
 jsonWriteListEnd(jw);
 }	/*  static void tableDataOutput(char *db, struct trackDb *tdb, ... ) */
 
 static void bedDataOutput(struct jsonWrite *jw, struct bbiFile *bbi,
     char *chrom, unsigned start, unsigned end, struct sqlFieldType *fiList,
      struct trackDb *tdb)
 /* output bed data for one chrom in the given bbi file */
 {
 char *itemRgb = trackDbSetting(tdb, "itemRgb");
 int *jsonTypes = NULL;
 int columnCount = slCount(fiList);
@@ -185,43 +192,52 @@
 	else
 	    jsonTypes[i++] = autoSqlToJsonType(fi->type);
 	}
     else
 	jsonTypes[i++] = autoSqlToJsonType(fi->type);
     }
 struct lm *bbLm = lmInit(0);
 struct bigBedInterval *iv, *ivList = NULL;
 ivList = bigBedIntervalQuery(bbi,chrom, start, end, 0, bbLm);
 char *row[bbi->fieldCount];
 unsigned itemCount = 0;
 for (iv = ivList; itemCount < maxItemsOutput && iv; iv = iv->next)
     {
     char startBuf[16], endBuf[16];
     bigBedIntervalToRow(iv, chrom, startBuf, endBuf, row, bbi->fieldCount);
+    if (jsonOutputArrays)
+	jsonWriteListStart(jw, NULL);
+    else
 	jsonWriteObjectStart(jw, NULL);
     int i;
     struct sqlFieldType *fi = fiList;
     for (i = 0; i < bbi->fieldCount; ++i)
         {
+	if (jsonOutputArrays)
+	    jsonDatumOut(jw, NULL, row[i], jsonTypes[i]);
+	else
 	    jsonDatumOut(jw, fi->name, row[i], jsonTypes[i]);
         fi = fi->next;
         }
+    if (jsonOutputArrays)
+	jsonWriteListEnd(jw);
+    else
 	jsonWriteObjectEnd(jw);
     ++itemCount;
     }
 lmCleanup(&bbLm);
-}
+}	/* static void bedDataOutput(struct jsonWrite *jw, . . . ) */
 
 static void wigDataOutput(struct jsonWrite *jw, struct bbiFile *bwf,
     char *chrom, unsigned start, unsigned end)
 /* output wig data for one chrom in the given bwf file */
 {
 struct lm *lm = lmInit(0);
 struct bbiInterval *iv, *ivList = bigWigIntervalQuery(bwf, chrom, start, end, lm);
 if (NULL == ivList)
     return;
 
 unsigned itemCount = 0;
 
 jsonWriteListStart(jw, chrom);
 for (iv = ivList; iv && itemCount < maxItemsOutput; iv = iv->next)
     {
@@ -333,30 +349,32 @@
     jsonWriteNumber(jw, "chromCount", (long long)slCount(chromList));
     }
 
 unsigned uStart = 0;
 unsigned uEnd = chromSize;
 if ( ! (isEmpty(start) || isEmpty(end)) )
     {
     uStart = sqlUnsigned(start);
     uEnd = sqlUnsigned(end);
     jsonWriteNumber(jw, "start", uStart);
     jsonWriteNumber(jw, "end", uEnd);
     }
 
 jsonWriteString(jw, "bigDataUrl", bigDataUrl);
 jsonWriteString(jw, "trackType", thisTrack->type);
+if (debug)
+    jsonWriteString(jw, "jsonOutputArrays", jsonOutputArrays ? "TRUE":"FALSE");
 
 if (allowedBigBedType(thisTrack->type))
     {
     struct asObject *as = bigBedAsOrDefault(bbi);
     struct sqlFieldType *fiList = sqlFieldTypesFromAs(as);
     if (debug)
         bigColumnTypes(jw, fiList);
 
     jsonWriteListStart(jw, track);
     if (isEmpty(chrom))
 	{
 	struct bbiChromInfo *bci;
 	for (bci = chromList; bci; bci = bci->next)
 	    {
 	    bedDataOutput(jw, bbi, bci->name, 0, bci->size, fiList, thisTrack);
@@ -433,30 +451,32 @@
 
 struct jsonWrite *jw = apiStartOutput();
 jsonWriteString(jw, "db", db);
 if (tableTrack)
     {
     char *dataTime = sqlTableUpdate(conn, sqlTable);
     time_t dataTimeStamp = sqlDateToUnixTime(dataTime);
     replaceChar(dataTime, ' ', 'T');	/*	ISO 8601	*/
     jsonWriteString(jw, "dataTime", dataTime);
     jsonWriteNumber(jw, "dataTimeStamp", (long long)dataTimeStamp);
     if (differentStringNullOk(sqlTable,track))
 	jsonWriteString(jw, "sqlTable", sqlTable);
     }
 jsonWriteString(jw, "trackType", thisTrack->type);
 jsonWriteString(jw, "track", track);
+if (debug)
+    jsonWriteString(jw, "jsonOutputArrays", jsonOutputArrays ? "TRUE":"FALSE");
 
 char query[4096];
 struct bbiFile *bbi = NULL;
 struct bbiChromInfo *chromList = NULL;
 
 if (startsWith("big", thisTrack->type))
     {
     if (bigDataUrl)
 	bbi = bigFileOpen(thisTrack->type, bigDataUrl);
     else
 	{
 	char quickReturn[2048];
         sqlSafef(query, sizeof(query), "select fileName from %s", sqlTable);
         if (sqlQuickQuery(conn, query, quickReturn, sizeof(quickReturn)))
 	    {
@@ -610,35 +630,39 @@
 /* this MaybeChromInfo will open the twoBit file, if not already done */
 struct chromInfo *ci = trackHubMaybeChromInfo(hubGenome->name, chrom);
 if (NULL == ci)
     apiErrAbort(err400, err400Msg, "can not find sequence for chrom=%s for endpoint '/getData/sequence?genome=%s;chrom=%s' given hubUrl='%s'", chrom, genome, chrom, hubUrl);
 
 struct jsonWrite *jw = apiStartOutput();
 jsonWriteString(jw, "hubUrl", hubUrl);
 jsonWriteString(jw, "genome", genome);
 jsonWriteString(jw, "chrom", chrom);
 int fragStart = 0;
 int fragEnd = 0;
 if (isNotEmpty(start) && isNotEmpty(end))
     {
     fragStart = sqlSigned(start);
     fragEnd = sqlSigned(end);
+    if ((fragEnd - fragStart) > MAX_DNA_LENGTH)
+	apiErrAbort(err400, err400Msg, "DNA sequence request %d too large, limit: %u for endpoint '/getData/sequence?genome=%s;chrom=%s;start=%d;end=%d' given hubUrl='%s'", fragEnd-fragEnd, MAX_DNA_LENGTH, genome, chrom, fragStart, fragEnd, hubUrl);
     jsonWriteNumber(jw, "start", (long long)fragStart);
     jsonWriteNumber(jw, "end", (long long)fragEnd);
     }
 else
     {
+    if (ci->size > MAX_DNA_LENGTH)
+	apiErrAbort(err400, err400Msg, "DNA sequence request %d too large, limit: %u for endpoint '/getData/sequence?genome=%s;chrom=%s' given hubUrl='%s'", ci->size, MAX_DNA_LENGTH, genome, chrom, hubUrl);
     jsonWriteNumber(jw, "start", (long long)0);
     jsonWriteNumber(jw, "end", (long long)ci->size);
     }
 struct dnaSeq *seq = twoBitReadSeqFrag(hubGenome->tbf, chrom, fragStart, fragEnd);
 if (NULL == seq)
     {
     if (fragEnd > fragStart)
 	apiErrAbort(err400, err400Msg, "can not find sequence for chrom=%s;start=%s;end=%s for endpoint '/getData/sequence?genome=%s;chrom=%s;start=%s;end=%s' give hubUrl='%s'", chrom, start, end, genome, chrom, start, end, hubUrl);
     else
 	apiErrAbort(err400, err400Msg, "can not find sequence for chrom=%s for endpoint '/getData/sequence?genome=%s;chrom=%s' give hubUrl='%s'", chrom, genome, chrom, hubUrl);
     }
 jsonWriteString(jw, "dna", seq->dna);
 apiFinishOutput(0, NULL, jw);
 }