1a2011f25ac0bd4ce02ed0eb093ff169724f9047
angie
  Mon May 2 16:39:23 2016 -0700
Added trackDb setting "tableBrowser noGenome", which allows tables to appear in TB and DI menus,
unlike "tableBrowser off", but does not allow genome-wide queries on the tables.  The new "noGenome"
setting is used for OMIM tracks -- OMIM gave the OK for non-genome-wide queries on their tables.

See #4458#note-53 for details of UI & functional changes to the TB and DI for noGenome tracks.

hg/lib/cartTrackDb.c handles access control based on trackDb tableBrowser settings (and the
seldom-used tableAccessControl database tables that restrict tables to be viewed only by
certain hosts).  As before, 'tableBrowser off' means that the track is removed from the
trackList so the TB & DI don't even know that it exists.  'tableBrowser noGenome' tracks are
included in the trackList, but the tracks and any tables listed after 'noGenome' are hashed
for later use by cartTrackDbIsNoGenome().  The hash used to contain permitted-host lists,
but now contains structs that combine the permitted-host lists with a noGenome flag.

hgIntegrator.c now includes a 'noGenome' flag in the JSONified groupedTrackDb, which the JS
code uses to identify noGenome tracks.  When executing a query, if the query region is genome
but hgi_querySpec has noGenome related tables left over from past position-only queries, those
related table settings are removed from the parsed JSON querySpec->config->relatedTables that is
passed down into annoStreamDb.  If one of the dataSources is noGenome but the region is genome
(should be possible only by URL-tweaking), the region is forced to position.

In hgTables, when region is genome, correlation and intersection track menu options for
noGenome tracks are disabled.  On the main page, JS code controls whether options are disabled
depending on the current region.  When listing related tables for filtering or selected fields
output, if region is genome then the checkboxes for noGenome tables are disabled.  If the cart
has noGenome related table or intersection settings left over from past searches, they are
ignored.  If a noGenome query URL is tweaked to have hgta_region=genome, the TB errors out.

hgIntegratorModel.js handles disabling of menu options and related table field settings for
noGenome tracks when region is genome.

refs #4458

diff --git src/hg/lib/annoStreamDb.c src/hg/lib/annoStreamDb.c
index 0ebc36e..a550f6c 100644
--- src/hg/lib/annoStreamDb.c
+++ src/hg/lib/annoStreamDb.c
@@ -1090,61 +1090,64 @@
  * It might also have "naForMissing": true/false; if so, set self->naForMissing. */
 {
 //#*** TODO: hAnnoGetAutoSqlForDbTable should do its own split-table checking
 char maybeSplitTable[HDB_MAX_TABLE_STRING];
 if (!hFindSplitTable(self->db, NULL, self->table, maybeSplitTable, NULL))
     errAbort("annoStreamDbNew: can't find table (or split table) for '%s.%s'",
              self->db, self->table);
 struct asObject *asObj = hAnnoGetAutoSqlForDbTable(self->db, maybeSplitTable, NULL, TRUE);
 makeMainTableDtfList(self, asObj);
 if (configEl != NULL)
     {
     struct hash *config = jsonObjectVal(configEl, "config");
     struct jsonElement *relatedTablesEl = hashFindVal(config, "relatedTables");
     if (relatedTablesEl)
         {
-        // relatedTables is a list of objects whose keys are related [db.]table names
-        // and whose values are lists of fields.
+        // relatedTables is a list of objects like { table: <[db.]table name>,
+        //                                           fields: [ <field1>, <field2>, ...] }
         struct slRef *relatedTables = jsonListVal(relatedTablesEl, "relatedTables");
         struct slRef *tfRef;
         for (tfRef = relatedTables;  tfRef != NULL;  tfRef = tfRef->next)
             {
             struct jsonElement *dbTableFieldEl = tfRef->val;
             struct hash *tfObj = jsonObjectVal(dbTableFieldEl,
                                                "{table,fields} object in relatedTables");
             struct jsonElement *dbTableEl = hashMustFindVal(tfObj, "table");
             char *dbTable = jsonStringVal(dbTableEl, "[db.]table in relatedTables");
             char tfDb[PATH_LEN], tfTable[PATH_LEN];
             hParseDbDotTable(self->db, dbTable, tfDb, sizeof(tfDb), tfTable, sizeof(tfTable));
             if (isEmpty(tfDb))
                 safecpy(tfDb, sizeof(tfDb), self->db);
             if (hTableExists(tfDb, tfTable))
                 {
                 struct jsonElement *fieldListEl = hashMustFindVal(tfObj, "fields");
                 struct slRef *fieldList = jsonListVal(fieldListEl, "fieldList");
                 struct slRef *fieldRef;
                 for (fieldRef = fieldList;  fieldRef != NULL;  fieldRef = fieldRef->next)
                     {
                     struct jsonElement *fieldEl = fieldRef->val;
                     char *tfField = jsonStringVal(fieldEl, "field");
                     slAddHead(&self->relatedDtfList, joinerDtfNew(tfDb, tfTable, tfField));
                     }
                 }
             }
+        if (self->relatedDtfList)
+            {
             slReverse(&self->relatedDtfList);
             asObj = asdAutoSqlFromTableFields(self, asObj);
             }
+        }
     struct jsonElement *naForMissingEl = hashFindVal(config, "naForMissing");
     if (naForMissingEl != NULL)
         self->naForMissing = jsonBooleanVal(naForMissingEl, "naForMissing");
     }
 return asObj;
 }
 
 static char *sqlExplain(struct sqlConnection *conn, char *query)
 /* For now, just turn the values back into a multi-line "#"-comment string. */
 {
 char *trimmedQuery = query;
 if (startsWith(NOSQLINJ, trimmedQuery))
     trimmedQuery = trimmedQuery + strlen(NOSQLINJ);
 struct dyString *dy = dyStringCreate("# Output of 'explain %s':\n", trimmedQuery);
 char explainQuery[PATH_LEN*8];