8a4758bc9826bad352cbce19052b01f28fb7171c
hiram
  Fri Jul 5 11:25:55 2019 -0700
now allowing getData for any table in the database refs #23589

diff --git src/hg/hubApi/getData.c src/hg/hubApi/getData.c
index 347f58c..2e4fcce 100644
--- src/hg/hubApi/getData.c
+++ src/hg/hubApi/getData.c
@@ -189,48 +189,48 @@
     {
     /* this setup here is for the case of non-split tables, will later
      * determine if split, and then will go through each chrom
      */
     sqlDyStringPrintf(query, "select * from %s", splitSqlTable);
     }
 else if (0 == (start + end))	/* have chrom, no start,end == full chr */
     {
     if (! sqlColumnExists(conn, splitSqlTable, 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);
-    if (startsWith("wig", tdb->type))
+    if (tdb && startsWith("wig", tdb->type))
 	{
 	if (jsonOutputArrays || debug)
 	    wigColumnTypes(jw);
 	jsonWriteListStart(jw, chrom);
         itemsReturned += wigTableDataOutput(jw, db, splitSqlTable, chrom, 0, ci->size, 0);
 	jsonWriteListEnd(jw);
         return;	/* DONE */
 	}
     else
 	{
 	sqlDyStringPrintf(query, "select * from %s where %s='%s' order by %s", splitSqlTable, chromName, chrom, startName);
 	}
     }
 else	/* fully specified chrom:start-end */
     {
     jsonWriteString(jw, "chrom", chrom);
-    if (startsWith("wig", tdb->type))
+    if (tdb && startsWith("wig", tdb->type))
 	{
 	if (jsonOutputArrays || debug)
 	    wigColumnTypes(jw);
 	jsonWriteListStart(jw, chrom);
         itemsReturned += wigTableDataOutput(jw, db, splitSqlTable, chrom, start, end, 0);
 	jsonWriteListEnd(jw);
         return;	/* DONE */
 	}
     else
 	{
 	sqlDyStringPrintf(query, "select * from %s where ", splitSqlTable);
         if (hti->hasBin)
            hAddBinToQuery(start, end, query);
 	sqlDyStringPrintf(query, "%s='%s' AND %s > %u AND %s < %u ORDER BY %s", chromName, chrom, endName, start, startName, end, startName);
 	}
@@ -263,31 +263,31 @@
     struct chromInfo *ciList = createChromInfoList(NULL, db);
     slSort(ciList, chromInfoCmp);
     struct chromInfo *ci = ciList;
     for ( ; ci && itemsDone < maxItemsOutput; ci = ci->next )
 	{
 	jsonWriteListStart(jw, ci->chrom);	/* starting a chrom output */
 	freeDyString(&query);
 	query = dyStringNew(64);
 	if (hti && hti->isSplit) /* when split, make up split chr name */
 	    {
 	    safef(fullTableName, sizeof(fullTableName), "%s_%s", ci->chrom, hti->rootName);
 	    sqlDyStringPrintf(query, "select * from %s", fullTableName);
 	    }
 	else
 	    sqlDyStringPrintf(query, "select * from %s", splitSqlTable);
-	if (startsWith("wig", tdb->type))
+	if (tdb && startsWith("wig", tdb->type))
             itemsDone += wigTableDataOutput(jw, db, splitSqlTable, chrom,
 		start, end, itemsDone);
 	else
 	    itemsDone += sqlQueryJsonOutput(conn, jw, query->string,
 		columnCount, columnNames, jsonTypes, itemsDone);
 	jsonWriteListEnd(jw);	/* chrom data output list end */
 	}
     if (itemsDone >= maxItemsOutput)
 	reachedMaxItems = TRUE;
     jsonWriteObjectEnd(jw);	/* end track data output */
     itemsReturned += itemsDone;
     }
 else
     {	/* a single chrom has been requested, run it */
     jsonWriteListStart(jw, track);	/* data output list starting */
@@ -436,31 +436,31 @@
 if (isEmpty(track))
     apiErrAbort(err400, err400Msg, "missing track=<name> for endpoint '/getData/track'  given hubUrl='%s'", hubUrl);
 
 struct trackHub *hub = errCatchTrackHubOpen(hubUrl);
 struct trackHubGenome *hubGenome = findHubGenome(hub, genome, "/getData/track",
   hubUrl);
 
 struct trackDb *tdb = obtainTdb(hubGenome, NULL);
 
 if (NULL == tdb)
     apiErrAbort(err400, err400Msg, "failed to find a track hub definition in genome=%s for endpoint '/getData/track'  given hubUrl='%s'", genome, hubUrl);
 
 struct trackDb *thisTrack = findTrackDb(track, tdb);
 if (NULL == thisTrack)
     apiErrAbort(err400, err400Msg, "failed to find specified track=%s in genome=%s for endpoint '/getData/track'  given hubUrl='%s'", track, genome, hubUrl);
-if (tdbIsComposite(thisTrack) || tdbIsCompositeView(thisTrack))
+if (trackHasNoData(thisTrack))
     apiErrAbort(err400, err400Msg, "container track '%s' does not contain data, use the children of this container for data access", track);
 if (! isSupportedType(thisTrack->type))
     apiErrAbort(err415, err415Msg, "track type '%s' for track=%s not supported at this time", thisTrack->type, track);
 
 char *bigDataUrl = trackDbSetting(thisTrack, "bigDataUrl");
 struct bbiFile *bbi = bigFileOpen(thisTrack->type, bigDataUrl);
 if (NULL == bbi)
     apiErrAbort(err400, err400Msg, "track type %s management not implemented yet TBD track=%s in genome=%s for endpoint '/getData/track'  given hubUrl='%s'", thisTrack->type, track, genome, hubUrl);
 
 struct jsonWrite *jw = apiStartOutput();
 jsonWriteString(jw, "hubUrl", hubUrl);
 jsonWriteString(jw, "genome", genome);
 unsigned chromSize = 0;
 struct bbiChromInfo *chromList = NULL;
 if (isNotEmpty(chrom))
@@ -545,61 +545,73 @@
 unsigned uStart = 0;
 unsigned uEnd = chromSize;	/* maybe set later */
 if ( ! (isEmpty(start) || isEmpty(end)) )
     {
     uStart = sqlUnsigned(start);
     uEnd = sqlUnsigned(end);
     if (uEnd < uStart)
 	apiErrAbort(err400, err400Msg, "given start coordinate %u is greater than given end coordinate", uStart, uEnd);
     }
 
 if (isEmpty(db))
     apiErrAbort(err400, err400Msg, "missing URL variable genome=<ucscDb> name for endpoint '/getData/track");
 if (isEmpty(track))
     apiErrAbort(err400, err400Msg, "missing URL variable track=<trackName> name for endpoint '/getData/track");
 
+/* database existence has already been checked before now, might
+ * have disappeared in the mean time (well, not really . . .)
+ */
+struct sqlConnection *conn = hAllocConnMaybe(db);
+if (NULL == conn)
+    apiErrAbort(err400, err400Msg, "can not find genome 'genome=%s' for endpoint '/getData/track", db);
+
 struct trackDb *thisTrack = hTrackDbForTrack(db, track);
 
 if (NULL == thisTrack)
+    {
+    if (! sqlTableExists(conn, track))
 	apiErrAbort(err400, err400Msg, "can not find track=%s name for endpoint '/getData/track", track);
-if (tdbIsComposite(thisTrack) || tdbIsCompositeView(thisTrack))
+    }
+if (thisTrack && ! isSupportedType(thisTrack->type))
+    apiErrAbort(err415, err415Msg, "track type '%s' for track=%s not supported at this time", thisTrack->type, track);
+if (trackHasNoData(thisTrack))
     apiErrAbort(err400, err400Msg, "container track '%s' does not contain data, use the children of this container", track);
-if (! isSupportedType(thisTrack->type))
-    apiErrAbort(err415, err415Msg, "track type '%s' for track=%s not supported at this time subtracks %llx", thisTrack->type, track, (unsigned long long)thisTrack->subtracks);
- // tdb->subtracks && COMPOSITE_NODE( tdb->treeNodeType);
 
 /* might be a big* track with no table */
-char *bigDataUrl = trackDbSetting(thisTrack, "bigDataUrl");
+char *bigDataUrl = NULL;
 boolean tableTrack = TRUE;
+boolean protectedData = FALSE;
+
+if (thisTrack)
+    {
+    bigDataUrl = trackDbSetting(thisTrack, "bigDataUrl");
 
     /* might have a specific table defined instead of the track name */
     char *tableName = trackDbSetting(thisTrack, "table");
     if (isNotEmpty(tableName))
 	{
 	freeMem(sqlTable);
 	sqlTable = cloneString(tableName);
 	}
-boolean protectedData = FALSE;
     if (trackDbSetting(thisTrack, "tableBrowser"))
         protectedData = TRUE;
-
-/* database existence has already been checked before now, might
- * have disappeared in the mean time
- */
-struct sqlConnection *conn = hAllocConnMaybe(db);
-if (NULL == conn)
-    apiErrAbort(err400, err400Msg, "can not find genome 'genome=%s' for endpoint '/getData/track", db);
+    }
+else
+    {
+    freeMem(sqlTable);
+    sqlTable = cloneString(track);
+    }
 
 struct hTableInfo *hti = hFindTableInfoWithConn(conn, NULL, sqlTable);
 
 char *splitSqlTable = NULL;
 
 if (hti && hti->isSplit)
     {
     if (isNotEmpty(chrom))
 	{
 	char fullTableName[256];
 	safef(fullTableName, sizeof(fullTableName), "%s_%s", chrom, hti->rootName);
 	splitSqlTable = cloneString(fullTableName);
 	}
     else
 	{
@@ -624,40 +636,42 @@
 jsonWriteString(jw, "genome", db);
 if (tableTrack)
     {
     char *dataTime = NULL;
     if (hti && hti->isSplit)
 	dataTime = sqlTableUpdate(conn, splitSqlTable);
     else
 	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);
     }
+if (thisTrack)
     jsonWriteString(jw, "trackType", thisTrack->type);
+
 jsonWriteString(jw, "track", track);
 if (debug)
     jsonWriteBoolean(jw, "jsonOutputArrays", jsonOutputArrays);
 
 char query[4096];
 struct bbiFile *bbi = NULL;
 struct bbiChromInfo *chromList = NULL;
 
-if (startsWith("big", thisTrack->type))
+if (thisTrack && 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)))
 	    {
 	    bigDataUrl = cloneString(quickReturn);
 	    bbi = bigFileOpen(thisTrack->type, bigDataUrl);
 	    }
 	}
     if (NULL == bbi)
 	apiErrAbort(err400, err400Msg, "failed to find bigDataUrl=%s for track=%s in database=%s for endpoint '/getData/track'", bigDataUrl, track, db);
@@ -674,57 +688,57 @@
 else
 	{
 	chromList = bbiChromList(bbi);
 	jsonWriteNumber(jw, "chromCount", (long long)slCount(chromList));
 	}
      jsonWriteString(jw, "bigDataUrl", bigDataUrl);
     }
 
 /* when start, end given, show them */
 if ( uEnd > uStart )
     {
     jsonWriteNumber(jw, "start", uStart);
     jsonWriteNumber(jw, "end", uEnd);
     }
 
-if (allowedBigBedType(thisTrack->type))
+if (thisTrack && allowedBigBedType(thisTrack->type))
     {
     struct asObject *as = bigBedAsOrDefault(bbi);
     struct sqlFieldType *fiList = sqlFieldTypesFromAs(as);
     if (jsonOutputArrays || debug)
         bigColumnTypes(jw, fiList, as);
 
     jsonWriteListStart(jw, track);
     unsigned itemsDone = 0;
     if (isEmpty(chrom))
 	{
 	struct bbiChromInfo *bci;
 	for (bci = chromList; bci && (itemsDone < maxItemsOutput); bci = bci->next)
 	    {
 	    itemsDone += bbiDataOutput(jw, bbi, bci->name, 0, bci->size,
 		fiList, thisTrack, itemsDone);
 	    }
 	    if (itemsDone >= maxItemsOutput)
 		reachedMaxItems = TRUE;
 	}
     else
 	itemsDone += bbiDataOutput(jw, bbi, chrom, uStart, uEnd, fiList,
 		thisTrack, itemsDone);
     itemsReturned += itemsDone;
     jsonWriteListEnd(jw);
     }
-else if (startsWith("bigWig", thisTrack->type))
+else if (thisTrack && startsWith("bigWig", thisTrack->type))
     {
     if (jsonOutputArrays || debug)
 	wigColumnTypes(jw);
 
     jsonWriteObjectStart(jw, track);
     wigData(jw, bbi, chrom, uStart, uEnd);
     jsonWriteObjectEnd(jw);
     bbiFileClose(&bbi);
     }
 else
     tableDataOutput(db, thisTrack, conn, jw, track, chrom, uStart, uEnd);
 
 apiFinishOutput(0, NULL, jw);
 hFreeConn(&conn);
 }