0e092ec31d4d48d6a85f4e68d081bd92d88a92b7
hiram
  Wed Apr 17 14:18:30 2019 -0700
correct array output better timing and column header information refs #18869

diff --git src/hg/hubApi/apiUtils.c src/hg/hubApi/apiUtils.c
index 558d13a..001e46f 100644
--- src/hg/hubApi/apiUtils.c
+++ src/hg/hubApi/apiUtils.c
@@ -1,45 +1,61 @@
 /* utility functions for data API business */
 
 #include "dataApi.h"
 
+/* when measureTiming is used */
+static long processingStart = 0;
+
+void startProcessTiming()
+/* for measureTiming, beginning processing */
+{
+processingStart = clock1000();
+}
+
 void apiFinishOutput(int errorCode, char *errorString, struct jsonWrite *jw)
 /* finish json output, potential output an error code other than 200 */
 {
 /* this is the first time any output to stdout has taken place for
  * json output, therefore, start with the appropriate header.
  */
 puts("Content-Type:application/json");
 /* potentially with an error code return in the header */
 if (errorCode)
     {
     char errString[2048];
     safef(errString, sizeof(errString), "Status: %d %s",errorCode,errorString);
     puts(errString);
     if (err429 == errorCode)
 	puts("Retry-After: 30");
     }
 puts("\n");
 
 if (debug)
     {
     char sizeString[64];
     unsigned long long vmPeak = currentVmPeak();
     sprintLongWithCommas(sizeString, vmPeak);
     jsonWriteString(jw, "vmPeak", sizeString);
     }
 
+if (measureTiming)
+    {
+    long nowTime = clock1000();
+    long long et = nowTime - processingStart;
+    jsonWriteNumber(jw, "totalTimeMs", et);
+    }
+
 jsonWriteObjectEnd(jw);
 fputs(jw->dy->string,stdout);
 }	/*	void apiFinishOutput(int errorCode, char *errorString, ... ) */
 
 void apiErrAbort(int errorCode, char *errString, char *format, ...)
 /* Issue an error message in json format, and exit(0) */
 {
 char errMsg[2048];
 va_list args;
 va_start(args, format);
 vsnprintf(errMsg, sizeof(errMsg), format, args);
 struct jsonWrite *jw = apiStartOutput();
 jsonWriteString(jw, "error", errMsg);
 jsonWriteNumber(jw, "statusCode", errorCode);
 jsonWriteString(jw, "statusMessage", errString);
@@ -150,60 +166,96 @@
    )
     typeIndex = JSON_NUMBER;
 else if (startsWith("float", asType))
 	typeIndex = JSON_DOUBLE;
 else if (startsWith("char", asType) ||
 	 startsWith("string", asType) ||
 	 startsWith("lstring", asType) ||
 	 startsWith("enum", asType) ||
 	 startsWith("set", asType)
 	)
 	typeIndex = JSON_STRING;
 
 return typeIndex;
 }	/*	int asToJsonType(char *asType)	*/
 
+/* temporarily from table browser until proven works, then move to library */
+struct asObject *asForTable(struct sqlConnection *conn, char *table,
+    struct trackDb *tdb)
+/* Get autoSQL description if any associated with table. */
+/* Wrap some error catching around asForTable. */
+{
+if (tdb != NULL)
+    return asForTdb(conn,tdb);
+
+// Some cases are for tables with no tdb!
+struct asObject *asObj = NULL;
+if (sqlTableExists(conn, "tableDescriptions"))
+    {
+    struct errCatch *errCatch = errCatchNew();
+    if (errCatchStart(errCatch))
+        {
+        char query[256];
+
+        sqlSafef(query, sizeof(query),
+              "select autoSqlDef from tableDescriptions where tableName='%s'", table);
+        char *asText = asText = sqlQuickString(conn, query);
+
+        // If no result try split table. (not likely)
+        if (asText == NULL)
+            {
+            sqlSafef(query, sizeof(query),
+                  "select autoSqlDef from tableDescriptions where tableName='chrN_%s'", table);
+            asText = sqlQuickString(conn, query);
+            }
+        if (asText != NULL && asText[0] != 0)
+            {
+            asObj = asParseText(asText);
+            }
+        freez(&asText);
+        }
+    errCatchEnd(errCatch);
+    errCatchFree(&errCatch);
+    }
+return asObj;
+}
+
 int tableColumns(struct sqlConnection *conn, struct jsonWrite *jw, char *table,
-   char ***nameReturn, char ***typeReturn, int **jsonType)
+   char ***nameReturn, char ***typeReturn, int **jsonTypes)
 /* return the column names, and their MySQL data type, for the given table
  *  return number of columns (aka 'fields')
  */
 {
-// not needed jsonWriteListStart(jw, "columnNames");
 struct sqlFieldInfo *fi, *fiList = sqlFieldInfoGet(conn, table);
 int columnCount = slCount(fiList);
 char **namesReturn = NULL;
 char **typesReturn = NULL;
 int *jsonReturn = NULL;
 AllocArray(namesReturn, columnCount);
 AllocArray(typesReturn, columnCount);
 AllocArray(jsonReturn, columnCount);
 int i = 0;
 for (fi = fiList; fi; fi = fi->next)
     {
     namesReturn[i] = cloneString(fi->field);
     typesReturn[i] = cloneString(fi->type);
     jsonReturn[i] = sqlTypeToJsonType(fi->type);
     i++;
-// not needed     jsonWriteObjectStart(jw, NULL);
-// not needed     jsonWriteString(jw, fi->field, fi->type);
-// not needed     jsonWriteObjectEnd(jw);
     }
-// not needed jsonWriteListEnd(jw);
 *nameReturn = namesReturn;
 *typeReturn = typesReturn;
-*jsonType = jsonReturn;
+*jsonTypes = jsonReturn;
 return columnCount;
 }
 
 struct trackHub *errCatchTrackHubOpen(char *hubUrl)
 /* use errCatch around a trackHub open in case it fails */
 {
 struct trackHub *hub = NULL;
 struct errCatch *errCatch = errCatchNew();
 if (errCatchStart(errCatch))
     {
     hub = trackHubOpen(hubUrl, "");
     }
 errCatchEnd(errCatch);
 if (errCatch->gotError)
     {