dbd8fef5786457ba53375f006c4eaedf3d256110 hiram Fri Apr 5 11:46:55 2019 -0700 now output correct string or number json types refs #18869 diff --git src/hg/hubApi/apiUtils.c src/hg/hubApi/apiUtils.c index f9a9a82..ccfca81 100644 --- src/hg/hubApi/apiUtils.c +++ src/hg/hubApi/apiUtils.c @@ -44,56 +44,158 @@ { time_t timeNow = time(NULL); // struct tm tm; // gmtime_r(&timeNow, &tm); struct jsonWrite *jw = jsonWriteNew(); jsonWriteObjectStart(jw, NULL); // not recommended: jsonWriteString(jw, "apiVersion", "v"CGI_VERSION); // not needed jsonWriteString(jw, "source", "UCSantaCruz"); jsonWriteDateFromUnix(jw, "downloadTime", (long long) timeNow); jsonWriteNumber(jw, "downloadTimeStamp", (long long) timeNow); if (debug) jsonWriteNumber(jw, "botDelay", (long long) botDelay); return jw; } +/* these json type strings beyond 'null' are types for UCSC jsonWrite() + * functions. The real 'official' json types are just the first six + */ +char *jsonTypeStrings[] = + { + "string", /* type 0 */ + "number", /* type 1 */ + "object", /* type 2 */ + "array", /* type 3 */ + "boolean", /* type 4 */ + "null", /* type 5 */ + "double" /* type 6 */ + }; + +/* this set of SQL types was taken from a survey of all the table + * descriptions on all tables on hgwdev. This is not necessarily + * a full range of all SQL types possible, just what we have used in + * UCSC databases. The fallback default will be string. + * bigint binary bit blob char date datetime decimal double enum float int + * longblob longtext mediumblob mediumint mediumtext set smallint text + * timestamp tinyblob tinyint tinytext unsigned varbinary varchar + * Many of these are not yet encountered since they are often in + * non-positional tables. This system doesn't yet output non-positional + * tables. + */ +static int sqlTypeToJsonType(char *sqlType) +/* convert SQL data type to JSON data type (index into jsonTypes[]) */ +{ +/* assume string, good enough for just about anything */ +int typeIndex = JSON_STRING; + +if (startsWith("tinyint(1)", sqlType)) + typeIndex = JSON_BOOLEAN; +else if (startsWith("bigint", sqlType) || + startsWith("int", sqlType) || + startsWith("mediumint", sqlType) || + startsWith("smallint", sqlType) || + startsWith("tinyint", sqlType) || + startsWith("unsigned", sqlType) + ) + typeIndex = JSON_NUMBER; +else if (startsWith("decimal", sqlType) || + startsWith("double", sqlType) || + startsWith("float", sqlType) + ) + typeIndex = JSON_DOUBLE; +else if (startsWith("binary", sqlType) || + startsWith("bit", sqlType) || + startsWith("blob", sqlType) || + startsWith("char", sqlType) || + startsWith("date", sqlType) || + startsWith("datetime", sqlType) || + startsWith("enum", sqlType) || + startsWith("longblob", sqlType) || + startsWith("longtext", sqlType) || + startsWith("mediumblob", sqlType) || + startsWith("set", sqlType) || + startsWith("text", sqlType) || + startsWith("time", sqlType) || + startsWith("timestamp", sqlType) || + startsWith("tinyblob", sqlType) || + startsWith("tinytext", sqlType) || + startsWith("varbinary", sqlType) || + startsWith("varchar", sqlType) + ) + typeIndex = JSON_STRING; + +return typeIndex; +} /* static int sqlTypeToJsonType(char *sqlType) */ + +int autoSqlToJsonType(char *asType) +/* convert an autoSql field type to a Json type */ +{ +/* assume string, good enough for just about anything */ +int typeIndex = JSON_STRING; + +if (startsWith("int", asType) || + startsWith("uint", asType) || + startsWith("short", asType) || + startsWith("ushort", asType) || + startsWith("byte", asType) || + startsWith("ubyte", asType) || + startsWith("bigit", asType) + ) + 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) */ + int tableColumns(struct sqlConnection *conn, struct jsonWrite *jw, char *table, - char ***nameReturn, char ***typeReturn) + char ***nameReturn, char ***typeReturn, int **jsonType) /* 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 = namesReturn; +*typeReturn = typesReturn; +*jsonType = 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) {